CompilerInstance.cpp revision 12ce6943aae499225708ecf364c5a8b0a3269c87
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/TextDiagnosticBuffer.h"
24#include "clang/Frontend/TextDiagnosticPrinter.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"
30using namespace clang;
31
32CompilerInstance::CompilerInstance(llvm::LLVMContext *_LLVMContext,
33                                   bool _OwnsLLVMContext)
34  : LLVMContext(_LLVMContext),
35    OwnsLLVMContext(_OwnsLLVMContext) {
36    }
37
38CompilerInstance::~CompilerInstance() {
39  if (OwnsLLVMContext)
40    delete LLVMContext;
41}
42
43void CompilerInstance::setDiagnostics(Diagnostic *Value) {
44  Diagnostics.reset(Value);
45}
46
47void CompilerInstance::setDiagnosticClient(DiagnosticClient *Value) {
48  DiagClient.reset(Value);
49}
50
51void CompilerInstance::setTarget(TargetInfo *Value) {
52  Target.reset(Value);
53}
54
55void CompilerInstance::setFileManager(FileManager *Value) {
56  FileMgr.reset(Value);
57}
58
59void CompilerInstance::setSourceManager(SourceManager *Value) {
60  SourceMgr.reset(Value);
61}
62
63void CompilerInstance::setPreprocessor(Preprocessor *Value) {
64  PP.reset(Value);
65}
66
67void CompilerInstance::setASTContext(ASTContext *Value) {
68  Context.reset(Value);
69}
70
71void CompilerInstance::setASTConsumer(ASTConsumer *Value) {
72  Consumer.reset(Value);
73}
74
75void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) {
76  CompletionConsumer.reset(Value);
77}
78
79// Diagnostics
80
81static 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
106void CompilerInstance::createDiagnostics(int Argc, char **Argv) {
107  Diagnostics.reset(createDiagnostics(getDiagnosticOpts(), Argc, Argv));
108
109  if (Diagnostics)
110    DiagClient.reset(Diagnostics->getClient());
111}
112
113Diagnostic *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  if (Opts.VerifyDiagnostics) {
119    // When checking diagnostics, just buffer them up.
120    DiagClient.reset(new TextDiagnosticBuffer());
121  } else {
122    DiagClient.reset(new TextDiagnosticPrinter(llvm::errs(), Opts));
123  }
124
125  if (!Opts.DumpBuildInformation.empty())
126    SetUpBuildDumpLog(Opts, Argc, Argv, DiagClient);
127
128  // Configure our handling of diagnostics.
129  Diagnostic *Diags = new Diagnostic(DiagClient.take());
130  if (ProcessWarningOptions(*Diags, Opts))
131    return 0;
132
133  return Diags;
134}
135
136// File Manager
137
138void CompilerInstance::createFileManager() {
139  FileMgr.reset(new FileManager());
140}
141
142// Source Manager
143
144void CompilerInstance::createSourceManager() {
145  SourceMgr.reset(new SourceManager());
146}
147
148// Preprocessor
149
150void CompilerInstance::createPreprocessor() {
151  PP.reset(createPreprocessor(getDiagnostics(), getLangOpts(),
152                              getPreprocessorOpts(), getHeaderSearchOpts(),
153                              getDependencyOutputOpts(), getTarget(),
154                              getSourceManager(), getFileManager()));
155}
156
157Preprocessor *
158CompilerInstance::createPreprocessor(Diagnostic &Diags,
159                                     const LangOptions &LangInfo,
160                                     const PreprocessorOptions &PPOpts,
161                                     const HeaderSearchOptions &HSOpts,
162                                     const DependencyOutputOptions &DepOpts,
163                                     const TargetInfo &Target,
164                                     SourceManager &SourceMgr,
165                                     FileManager &FileMgr) {
166  // Create a PTH manager if we are using some form of a token cache.
167  PTHManager *PTHMgr = 0;
168  if (!PPOpts.getTokenCache().empty())
169    PTHMgr = PTHManager::Create(PPOpts.getTokenCache(), Diags);
170
171  // FIXME: Don't fail like this.
172  if (Diags.hasErrorOccurred())
173    exit(1);
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
200void 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
211void 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
218ExternalASTSource *
219CompilerInstance::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
248void 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
258CodeCompleteConsumer *
259CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP,
260                                               const std::string &Filename,
261                                               unsigned Line,
262                                               unsigned Column,
263                                               bool UseDebugPrinter,
264                                               bool ShowMacros,
265                                               llvm::raw_ostream &OS) {
266  // Tell the source manager to chop off the given file at a specific
267  // line and column.
268  const FileEntry *Entry = PP.getFileManager().getFile(Filename);
269  if (!Entry) {
270    PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file)
271      << Filename;
272    return 0;
273  }
274
275  // Truncate the named file at the given line/column.
276  PP.getSourceManager().truncateFileAt(Entry, Line, Column);
277
278  // Set up the creation routine for code-completion.
279  if (UseDebugPrinter)
280    return new PrintingCodeCompleteConsumer(ShowMacros, OS);
281  else
282    return new CIndexCodeCompleteConsumer(ShowMacros, OS);
283}
284
285// Output Files
286
287void CompilerInstance::addOutputFile(llvm::StringRef Path,
288                                     llvm::raw_ostream *OS) {
289  assert(OS && "Attempt to add empty stream to output list!");
290  OutputFiles.push_back(std::make_pair(Path, OS));
291}
292
293void CompilerInstance::ClearOutputFiles(bool EraseFiles) {
294  for (std::list< std::pair<std::string, llvm::raw_ostream*> >::iterator
295         it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) {
296    delete it->second;
297    if (EraseFiles && !it->first.empty())
298      llvm::sys::Path(it->first).eraseFromDisk();
299  }
300  OutputFiles.clear();
301}
302
303llvm::raw_fd_ostream *
304CompilerInstance::createDefaultOutputFile(bool Binary,
305                                          llvm::StringRef InFile,
306                                          llvm::StringRef Extension) {
307  return createOutputFile(getFrontendOpts().OutputFile, Binary,
308                          InFile, Extension);
309}
310
311llvm::raw_fd_ostream *
312CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
313                                   bool Binary,
314                                   llvm::StringRef InFile,
315                                   llvm::StringRef Extension) {
316  std::string Error, OutputPathName;
317  llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary,
318                                              InFile, Extension,
319                                              &OutputPathName);
320  if (!OS) {
321    // FIXME: Don't fail this way.
322    llvm::errs() << "ERROR: " << Error << "\n";
323    ::exit(1);
324  }
325
326  // Add the output file -- but don't try to remove "-", since this means we are
327  // using stdin.
328  addOutputFile((OutputPathName != "-") ? OutputPathName : "", OS);
329
330  return OS;
331}
332
333llvm::raw_fd_ostream *
334CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
335                                   std::string &Error,
336                                   bool Binary,
337                                   llvm::StringRef InFile,
338                                   llvm::StringRef Extension,
339                                   std::string *ResultPathName) {
340  std::string OutFile;
341  if (!OutputPath.empty()) {
342    OutFile = OutputPath;
343  } else if (InFile == "-") {
344    OutFile = "-";
345  } else if (!Extension.empty()) {
346    llvm::sys::Path Path(InFile);
347    Path.eraseSuffix();
348    Path.appendSuffix(Extension);
349    OutFile = Path.str();
350  } else {
351    OutFile = "-";
352  }
353
354  llvm::raw_fd_ostream *OS =
355    new llvm::raw_fd_ostream(OutFile.c_str(), Error,
356                             (Binary ? llvm::raw_fd_ostream::F_Binary : 0));
357  if (!OS)
358    return 0;
359
360  if (ResultPathName)
361    *ResultPathName = OutFile;
362
363  return OS;
364}
365