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