FrontendAction.cpp revision f79bafa608a5d7c49ec40ad199af5e32f3038b47
1//===--- FrontendAction.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/FrontendAction.h"
11#include "clang/AST/ASTContext.h"
12#include "clang/Lex/HeaderSearch.h"
13#include "clang/Lex/Preprocessor.h"
14#include "clang/Frontend/ASTUnit.h"
15#include "clang/Frontend/CompilerInstance.h"
16#include "clang/Frontend/FrontendDiagnostic.h"
17#include "clang/Sema/ParseAST.h"
18#include "llvm/Support/MemoryBuffer.h"
19#include "llvm/Support/Timer.h"
20#include "llvm/Support/ErrorHandling.h"
21#include "llvm/Support/raw_ostream.h"
22using namespace clang;
23
24FrontendAction::FrontendAction() : Instance(0) {}
25
26FrontendAction::~FrontendAction() {}
27
28void FrontendAction::setCurrentFile(llvm::StringRef Value, ASTUnit *AST) {
29  CurrentFile = Value;
30  CurrentASTUnit.reset(AST);
31}
32
33bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
34                                     llvm::StringRef Filename,
35                                     bool IsAST) {
36  assert(!Instance && "Already processing a source file!");
37  assert(!Filename.empty() && "Unexpected empty filename!");
38  setCurrentFile(Filename);
39  setCompilerInstance(&CI);
40
41  // AST files follow a very different path, since they share objects via the
42  // AST unit.
43  if (IsAST) {
44    assert(!usesPreprocessorOnly() &&
45           "Attempt to pass AST file to preprocessor only action!");
46    assert(hasASTSupport() && "This action does not have AST support!");
47
48    std::string Error;
49    ASTUnit *AST = ASTUnit::LoadFromPCHFile(Filename, &Error);
50    if (!AST) {
51      CI.getDiagnostics().Report(diag::err_fe_invalid_ast_file) << Error;
52      goto failure;
53    }
54
55    setCurrentFile(Filename, AST);
56
57    // Set the shared objects, these are reset when we finish processing the
58    // file, otherwise the CompilerInstance will happily destroy them.
59    CI.setFileManager(&AST->getFileManager());
60    CI.setSourceManager(&AST->getSourceManager());
61    CI.setPreprocessor(&AST->getPreprocessor());
62    CI.setASTContext(&AST->getASTContext());
63
64    // Initialize the action.
65    if (!BeginSourceFileAction(CI, Filename))
66      goto failure;
67
68    /// Create the AST consumer.
69    CI.setASTConsumer(CreateASTConsumer(CI, Filename));
70    if (!CI.hasASTConsumer())
71      goto failure;
72
73    return true;
74  }
75
76  // Inform the diagnostic client we are processing a source file.
77  CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(),
78                                           &CI.getPreprocessor());
79
80  // Initialize the action.
81  if (!BeginSourceFileAction(CI, Filename))
82    goto failure;
83
84  /// Create the AST context and consumer unless this is a preprocessor only
85  /// action.
86  if (!usesPreprocessorOnly()) {
87    CI.createASTContext();
88    CI.setASTConsumer(CreateASTConsumer(CI, Filename));
89    if (!CI.hasASTConsumer())
90      goto failure;
91
92    /// Use PCH?
93    if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
94      assert(hasPCHSupport() && "This action does not have PCH support!");
95      CI.createPCHExternalASTSource(
96        CI.getPreprocessorOpts().ImplicitPCHInclude);
97      if (!CI.getASTContext().getExternalSource())
98        goto failure;
99    }
100  }
101
102  // Initialize builtin info as long as we aren't using an external AST
103  // source.
104  if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
105    Preprocessor &PP = CI.getPreprocessor();
106    PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
107                                           PP.getLangOptions().NoBuiltin);
108  }
109
110  return true;
111
112  // If we failed, reset state since the client will not end up calling the
113  // matching EndSourceFile().
114  failure:
115  if (isCurrentFileAST()) {
116    CI.takeASTContext();
117    CI.takePreprocessor();
118    CI.takeSourceManager();
119    CI.takeFileManager();
120  }
121
122  CI.getDiagnosticClient().EndSourceFile();
123  setCurrentFile("");
124  setCompilerInstance(0);
125  return false;
126}
127
128void FrontendAction::Execute() {
129  CompilerInstance &CI = getCompilerInstance();
130
131  // Initialize the main file entry. This needs to be delayed until after PCH
132  // has loaded.
133  if (isCurrentFileAST()) {
134    // Set the main file ID to an empty file.
135    //
136    // FIXME: We probably shouldn't need this, but for now this is the
137    // simplest way to reuse the logic in ParseAST.
138    const char *EmptyStr = "";
139    llvm::MemoryBuffer *SB =
140      llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<dummy input>");
141    CI.getSourceManager().createMainFileIDForMemBuffer(SB);
142  } else {
143    if (!CI.InitializeSourceManager(getCurrentFile()))
144      return;
145  }
146
147  if (CI.hasFrontendTimer()) {
148    llvm::TimeRegion Timer(CI.getFrontendTimer());
149    ExecuteAction();
150  }
151  else ExecuteAction();
152}
153
154void FrontendAction::EndSourceFile() {
155  CompilerInstance &CI = getCompilerInstance();
156
157  // Finalize the action.
158  EndSourceFileAction();
159
160  // Release the consumer and the AST, in that order since the consumer may
161  // perform actions in its destructor which require the context.
162  //
163  // FIXME: There is more per-file stuff we could just drop here?
164  if (CI.getFrontendOpts().DisableFree) {
165    CI.takeASTConsumer();
166    if (!isCurrentFileAST())
167      CI.takeASTContext();
168  } else {
169    CI.setASTConsumer(0);
170    if (!isCurrentFileAST())
171      CI.setASTContext(0);
172  }
173
174  if (CI.getFrontendOpts().ShowStats) {
175    llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n";
176    CI.getPreprocessor().PrintStats();
177    CI.getPreprocessor().getIdentifierTable().PrintStats();
178    CI.getPreprocessor().getHeaderSearchInfo().PrintStats();
179    CI.getSourceManager().PrintStats();
180    llvm::errs() << "\n";
181  }
182
183  // Cleanup the output streams, and erase the output files if we encountered
184  // an error.
185  CI.ClearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().getNumErrors());
186
187  // Inform the diagnostic client we are done with this source file.
188  CI.getDiagnosticClient().EndSourceFile();
189
190  if (isCurrentFileAST()) {
191    CI.takeASTContext();
192    CI.takePreprocessor();
193    CI.takeSourceManager();
194    CI.takeFileManager();
195  }
196
197  setCompilerInstance(0);
198  setCurrentFile("");
199}
200
201//===----------------------------------------------------------------------===//
202// Utility Actions
203//===----------------------------------------------------------------------===//
204
205void ASTFrontendAction::ExecuteAction() {
206  CompilerInstance &CI = getCompilerInstance();
207
208  // FIXME: Move the truncation aspect of this into Sema, we delayed this till
209  // here so the source manager would be initialized.
210  if (hasCodeCompletionSupport() &&
211      !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
212    CI.createCodeCompletionConsumer();
213
214  // Use a code completion consumer?
215  CodeCompleteConsumer *CompletionConsumer = 0;
216  if (CI.hasCodeCompletionConsumer())
217    CompletionConsumer = &CI.getCodeCompletionConsumer();
218
219  ParseAST(CI.getPreprocessor(), &CI.getASTConsumer(), CI.getASTContext(),
220           CI.getFrontendOpts().ShowStats,
221           usesCompleteTranslationUnit(), CompletionConsumer);
222}
223
224ASTConsumer *
225PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
226                                              llvm::StringRef InFile) {
227  llvm::llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!");
228}
229