xref: /llvm-project/clang/lib/Frontend/CompilerInstance.cpp (revision 692bc47d25a637e4215d4c1bc3ff4f5a7f9c57f5)
1 //===--- CompilerInstance.cpp ---------------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "clang/Frontend/CompilerInstance.h"
11 #include "clang/AST/ASTConsumer.h"
12 #include "clang/AST/ASTContext.h"
13 #include "clang/Basic/Diagnostic.h"
14 #include "clang/Basic/FileManager.h"
15 #include "clang/Basic/SourceManager.h"
16 #include "clang/Basic/TargetInfo.h"
17 #include "clang/Lex/HeaderSearch.h"
18 #include "clang/Lex/Preprocessor.h"
19 #include "clang/Lex/PTHManager.h"
20 #include "clang/Frontend/ChainedDiagnosticClient.h"
21 #include "clang/Frontend/PCHReader.h"
22 #include "clang/Frontend/FrontendDiagnostic.h"
23 #include "clang/Frontend/TextDiagnosticPrinter.h"
24 #include "clang/Frontend/VerifyDiagnosticsClient.h"
25 #include "clang/Frontend/Utils.h"
26 #include "clang/Sema/CodeCompleteConsumer.h"
27 #include "llvm/LLVMContext.h"
28 #include "llvm/Support/MemoryBuffer.h"
29 #include "llvm/Support/raw_ostream.h"
30 #include "llvm/Support/Timer.h"
31 #include "llvm/System/Path.h"
32 #include "llvm/System/Program.h"
33 using namespace clang;
34 
35 CompilerInstance::CompilerInstance(llvm::LLVMContext *_LLVMContext,
36                                    bool _OwnsLLVMContext)
37   : LLVMContext(_LLVMContext),
38     OwnsLLVMContext(_OwnsLLVMContext) {
39     }
40 
41 CompilerInstance::~CompilerInstance() {
42   if (OwnsLLVMContext)
43     delete LLVMContext;
44 }
45 
46 void CompilerInstance::setDiagnostics(Diagnostic *Value) {
47   Diagnostics.reset(Value);
48 }
49 
50 void CompilerInstance::setDiagnosticClient(DiagnosticClient *Value) {
51   DiagClient.reset(Value);
52 }
53 
54 void CompilerInstance::setTarget(TargetInfo *Value) {
55   Target.reset(Value);
56 }
57 
58 void CompilerInstance::setFileManager(FileManager *Value) {
59   FileMgr.reset(Value);
60 }
61 
62 void CompilerInstance::setSourceManager(SourceManager *Value) {
63   SourceMgr.reset(Value);
64 }
65 
66 void CompilerInstance::setPreprocessor(Preprocessor *Value) {
67   PP.reset(Value);
68 }
69 
70 void CompilerInstance::setASTContext(ASTContext *Value) {
71   Context.reset(Value);
72 }
73 
74 void CompilerInstance::setASTConsumer(ASTConsumer *Value) {
75   Consumer.reset(Value);
76 }
77 
78 void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) {
79   CompletionConsumer.reset(Value);
80 }
81 
82 // Diagnostics
83 
84 static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
85                               unsigned argc, char **argv,
86                               llvm::OwningPtr<DiagnosticClient> &DiagClient) {
87   std::string ErrorInfo;
88   llvm::raw_ostream *OS =
89     new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo);
90   if (!ErrorInfo.empty()) {
91     // FIXME: Do not fail like this.
92     llvm::errs() << "error opening -dump-build-information file '"
93                  << DiagOpts.DumpBuildInformation << "', option ignored!\n";
94     delete OS;
95     return;
96   }
97 
98   (*OS) << "clang-cc command line arguments: ";
99   for (unsigned i = 0; i != argc; ++i)
100     (*OS) << argv[i] << ' ';
101   (*OS) << '\n';
102 
103   // Chain in a diagnostic client which will log the diagnostics.
104   DiagnosticClient *Logger =
105     new TextDiagnosticPrinter(*OS, DiagOpts, /*OwnsOutputStream=*/true);
106   DiagClient.reset(new ChainedDiagnosticClient(DiagClient.take(), Logger));
107 }
108 
109 void CompilerInstance::createDiagnostics(int Argc, char **Argv) {
110   Diagnostics.reset(createDiagnostics(getDiagnosticOpts(), Argc, Argv));
111 
112   if (Diagnostics)
113     DiagClient.reset(Diagnostics->getClient());
114 }
115 
116 Diagnostic *CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
117                                                 int Argc, char **Argv) {
118   llvm::OwningPtr<Diagnostic> Diags(new Diagnostic());
119 
120   // Create the diagnostic client for reporting errors or for
121   // implementing -verify.
122   llvm::OwningPtr<DiagnosticClient> DiagClient(
123     new TextDiagnosticPrinter(llvm::errs(), Opts));
124 
125   // Chain in -verify checker, if requested.
126   if (Opts.VerifyDiagnostics)
127     DiagClient.reset(new VerifyDiagnosticsClient(*Diags, DiagClient.take()));
128 
129   if (!Opts.DumpBuildInformation.empty())
130     SetUpBuildDumpLog(Opts, Argc, Argv, DiagClient);
131 
132   // Configure our handling of diagnostics.
133   Diags->setClient(DiagClient.take());
134   if (ProcessWarningOptions(*Diags, Opts))
135     return 0;
136 
137   return Diags.take();
138 }
139 
140 // File Manager
141 
142 void CompilerInstance::createFileManager() {
143   FileMgr.reset(new FileManager());
144 }
145 
146 // Source Manager
147 
148 void CompilerInstance::createSourceManager() {
149   SourceMgr.reset(new SourceManager());
150 }
151 
152 // Preprocessor
153 
154 void CompilerInstance::createPreprocessor() {
155   PP.reset(createPreprocessor(getDiagnostics(), getLangOpts(),
156                               getPreprocessorOpts(), getHeaderSearchOpts(),
157                               getDependencyOutputOpts(), getTarget(),
158                               getSourceManager(), getFileManager()));
159 }
160 
161 Preprocessor *
162 CompilerInstance::createPreprocessor(Diagnostic &Diags,
163                                      const LangOptions &LangInfo,
164                                      const PreprocessorOptions &PPOpts,
165                                      const HeaderSearchOptions &HSOpts,
166                                      const DependencyOutputOptions &DepOpts,
167                                      const TargetInfo &Target,
168                                      SourceManager &SourceMgr,
169                                      FileManager &FileMgr) {
170   // Create a PTH manager if we are using some form of a token cache.
171   PTHManager *PTHMgr = 0;
172   if (!PPOpts.TokenCache.empty())
173     PTHMgr = PTHManager::Create(PPOpts.TokenCache, Diags);
174 
175   // Create the Preprocessor.
176   HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr);
177   Preprocessor *PP = new Preprocessor(Diags, LangInfo, Target,
178                                       SourceMgr, *HeaderInfo, PTHMgr,
179                                       /*OwnsHeaderSearch=*/true);
180 
181   // Note that this is different then passing PTHMgr to Preprocessor's ctor.
182   // That argument is used as the IdentifierInfoLookup argument to
183   // IdentifierTable's ctor.
184   if (PTHMgr) {
185     PTHMgr->setPreprocessor(PP);
186     PP->setPTHManager(PTHMgr);
187   }
188 
189   InitializePreprocessor(*PP, PPOpts, HSOpts);
190 
191   // Handle generating dependencies, if requested.
192   if (!DepOpts.OutputFile.empty())
193     AttachDependencyFileGen(*PP, DepOpts);
194 
195   return PP;
196 }
197 
198 // ASTContext
199 
200 void CompilerInstance::createASTContext() {
201   Preprocessor &PP = getPreprocessor();
202   Context.reset(new ASTContext(getLangOpts(), PP.getSourceManager(),
203                                getTarget(), PP.getIdentifierTable(),
204                                PP.getSelectorTable(), PP.getBuiltinInfo(),
205                                /*FreeMemory=*/ !getFrontendOpts().DisableFree,
206                                /*size_reserve=*/ 0));
207 }
208 
209 // ExternalASTSource
210 
211 void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path) {
212   llvm::OwningPtr<ExternalASTSource> Source;
213   Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot,
214                                           getPreprocessor(), getASTContext()));
215   getASTContext().setExternalSource(Source);
216 }
217 
218 ExternalASTSource *
219 CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path,
220                                              const std::string &Sysroot,
221                                              Preprocessor &PP,
222                                              ASTContext &Context) {
223   llvm::OwningPtr<PCHReader> Reader;
224   Reader.reset(new PCHReader(PP, &Context,
225                              Sysroot.empty() ? 0 : Sysroot.c_str()));
226 
227   switch (Reader->ReadPCH(Path)) {
228   case PCHReader::Success:
229     // Set the predefines buffer as suggested by the PCH reader. Typically, the
230     // predefines buffer will be empty.
231     PP.setPredefines(Reader->getSuggestedPredefines());
232     return Reader.take();
233 
234   case PCHReader::Failure:
235     // Unrecoverable failure: don't even try to process the input file.
236     break;
237 
238   case PCHReader::IgnorePCH:
239     // No suitable PCH file could be found. Return an error.
240     break;
241   }
242 
243   return 0;
244 }
245 
246 // Code Completion
247 
248 void CompilerInstance::createCodeCompletionConsumer() {
249   const ParsedSourceLocation &Loc = getFrontendOpts().CodeCompletionAt;
250   CompletionConsumer.reset(
251     createCodeCompletionConsumer(getPreprocessor(),
252                                  Loc.FileName, Loc.Line, Loc.Column,
253                                  getFrontendOpts().DebugCodeCompletionPrinter,
254                                  getFrontendOpts().ShowMacrosInCodeCompletion,
255                                  llvm::outs()));
256 
257   if (CompletionConsumer->isOutputBinary() &&
258       llvm::sys::Program::ChangeStdoutToBinary()) {
259     getPreprocessor().getDiagnostics().Report(diag::err_fe_stdout_binary);
260     CompletionConsumer.reset();
261   }
262 }
263 
264 void CompilerInstance::createFrontendTimer() {
265   FrontendTimer.reset(new llvm::Timer("Clang front-end timer"));
266 }
267 
268 CodeCompleteConsumer *
269 CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP,
270                                                const std::string &Filename,
271                                                unsigned Line,
272                                                unsigned Column,
273                                                bool UseDebugPrinter,
274                                                bool ShowMacros,
275                                                llvm::raw_ostream &OS) {
276   // Tell the source manager to chop off the given file at a specific
277   // line and column.
278   const FileEntry *Entry = PP.getFileManager().getFile(Filename);
279   if (!Entry) {
280     PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file)
281       << Filename;
282     return 0;
283   }
284 
285   // Truncate the named file at the given line/column.
286   PP.SetCodeCompletionPoint(Entry, Line, Column);
287 
288   // Set up the creation routine for code-completion.
289   if (UseDebugPrinter)
290     return new PrintingCodeCompleteConsumer(ShowMacros, OS);
291   else
292     return new CIndexCodeCompleteConsumer(ShowMacros, OS);
293 }
294 
295 // Output Files
296 
297 void CompilerInstance::addOutputFile(llvm::StringRef Path,
298                                      llvm::raw_ostream *OS) {
299   assert(OS && "Attempt to add empty stream to output list!");
300   OutputFiles.push_back(std::make_pair(Path, OS));
301 }
302 
303 void CompilerInstance::ClearOutputFiles(bool EraseFiles) {
304   for (std::list< std::pair<std::string, llvm::raw_ostream*> >::iterator
305          it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) {
306     delete it->second;
307     if (EraseFiles && !it->first.empty())
308       llvm::sys::Path(it->first).eraseFromDisk();
309   }
310   OutputFiles.clear();
311 }
312 
313 llvm::raw_fd_ostream *
314 CompilerInstance::createDefaultOutputFile(bool Binary,
315                                           llvm::StringRef InFile,
316                                           llvm::StringRef Extension) {
317   return createOutputFile(getFrontendOpts().OutputFile, Binary,
318                           InFile, Extension);
319 }
320 
321 llvm::raw_fd_ostream *
322 CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
323                                    bool Binary,
324                                    llvm::StringRef InFile,
325                                    llvm::StringRef Extension) {
326   std::string Error, OutputPathName;
327   llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary,
328                                               InFile, Extension,
329                                               &OutputPathName);
330   if (!OS) {
331     // FIXME: Don't fail this way.
332     llvm::errs() << "error: " << Error << "\n";
333     ::exit(1);
334   }
335 
336   // Add the output file -- but don't try to remove "-", since this means we are
337   // using stdin.
338   addOutputFile((OutputPathName != "-") ? OutputPathName : "", OS);
339 
340   return OS;
341 }
342 
343 llvm::raw_fd_ostream *
344 CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
345                                    std::string &Error,
346                                    bool Binary,
347                                    llvm::StringRef InFile,
348                                    llvm::StringRef Extension,
349                                    std::string *ResultPathName) {
350   std::string OutFile;
351   if (!OutputPath.empty()) {
352     OutFile = OutputPath;
353   } else if (InFile == "-") {
354     OutFile = "-";
355   } else if (!Extension.empty()) {
356     llvm::sys::Path Path(InFile);
357     Path.eraseSuffix();
358     Path.appendSuffix(Extension);
359     OutFile = Path.str();
360   } else {
361     OutFile = "-";
362   }
363 
364   llvm::OwningPtr<llvm::raw_fd_ostream> OS(
365     new llvm::raw_fd_ostream(OutFile.c_str(), Error,
366                              (Binary ? llvm::raw_fd_ostream::F_Binary : 0)));
367   if (!Error.empty())
368     return 0;
369 
370   if (ResultPathName)
371     *ResultPathName = OutFile;
372 
373   return OS.take();
374 }
375 
376 // Initialization Utilities
377 
378 bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile) {
379   return InitializeSourceManager(InputFile, getDiagnostics(), getFileManager(),
380                                  getSourceManager(), getFrontendOpts());
381 }
382 
383 bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile,
384                                                Diagnostic &Diags,
385                                                FileManager &FileMgr,
386                                                SourceManager &SourceMgr,
387                                                const FrontendOptions &Opts) {
388   // Figure out where to get and map in the main file.
389   if (Opts.EmptyInputOnly) {
390     const char *EmptyStr = "";
391     llvm::MemoryBuffer *SB =
392       llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<empty input>");
393     SourceMgr.createMainFileIDForMemBuffer(SB);
394   } else if (InputFile != "-") {
395     const FileEntry *File = FileMgr.getFile(InputFile);
396     if (File) SourceMgr.createMainFileID(File, SourceLocation());
397     if (SourceMgr.getMainFileID().isInvalid()) {
398       Diags.Report(diag::err_fe_error_reading) << InputFile;
399       return false;
400     }
401   } else {
402     llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getSTDIN();
403     SourceMgr.createMainFileIDForMemBuffer(SB);
404     if (SourceMgr.getMainFileID().isInvalid()) {
405       Diags.Report(diag::err_fe_error_reading_stdin);
406       return false;
407     }
408   }
409 
410   return true;
411 }
412