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