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