FrontendAction.cpp revision 2d602ab01fe1ee87df29961b7b1bde328c8ef6a0
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/ASTConsumer.h"
12#include "clang/AST/ASTContext.h"
13#include "clang/Lex/HeaderSearch.h"
14#include "clang/Lex/Preprocessor.h"
15#include "clang/Frontend/ASTUnit.h"
16#include "clang/Frontend/CompilerInstance.h"
17#include "clang/Frontend/FrontendDiagnostic.h"
18#include "clang/Parse/ParseAST.h"
19#include "clang/Serialization/ASTDeserializationListener.h"
20#include "llvm/Support/MemoryBuffer.h"
21#include "llvm/Support/Timer.h"
22#include "llvm/Support/ErrorHandling.h"
23#include "llvm/Support/raw_ostream.h"
24using namespace clang;
25
26namespace {
27
28/// \brief Dumps deserialized declarations.
29class DeserializedDeclsDumper : public ASTDeserializationListener {
30  ASTDeserializationListener *Previous;
31
32public:
33  DeserializedDeclsDumper(ASTDeserializationListener *Previous)
34    : Previous(Previous) { }
35
36  virtual void DeclRead(serialization::DeclID ID, const Decl *D) {
37    llvm::outs() << "PCH DECL: " << D->getDeclKindName();
38    if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
39      llvm::outs() << " - " << ND->getNameAsString();
40    llvm::outs() << "\n";
41
42    if (Previous)
43      Previous->DeclRead(ID, D);
44  }
45
46  virtual void SetReader(ASTReader *Reader) {}
47  virtual void IdentifierRead(serialization::IdentID ID, IdentifierInfo *II) {}
48  virtual void TypeRead(serialization::TypeIdx Idx, QualType T) {}
49  virtual void SelectorRead(serialization::SelectorID iD, Selector Sel) {}
50  virtual void MacroDefinitionRead(serialization::MacroID,
51                                   MacroDefinition *MD) {}
52};
53
54  /// \brief Checks deserialized declarations and emits error if a name
55  /// matches one given in command-line using -error-on-deserialized-decl.
56  class DeserializedDeclsChecker : public ASTDeserializationListener {
57    ASTContext &Ctx;
58    std::set<std::string> NamesToCheck;
59    ASTDeserializationListener *Previous;
60
61  public:
62    DeserializedDeclsChecker(ASTContext &Ctx,
63                             const std::set<std::string> &NamesToCheck,
64                             ASTDeserializationListener *Previous)
65      : Ctx(Ctx), NamesToCheck(NamesToCheck), Previous(Previous) { }
66
67    virtual void DeclRead(serialization::DeclID ID, const Decl *D) {
68      if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
69        if (NamesToCheck.find(ND->getNameAsString()) != NamesToCheck.end()) {
70          unsigned DiagID
71            = Ctx.getDiagnostics().getCustomDiagID(Diagnostic::Error,
72                                                   "%0 was deserialized");
73          Ctx.getDiagnostics().Report(Ctx.getFullLoc(D->getLocation()), DiagID)
74              << ND->getNameAsString();
75        }
76
77      if (Previous)
78        Previous->DeclRead(ID, D);
79    }
80
81    virtual void SetReader(ASTReader *Reader) {}
82    virtual void IdentifierRead(serialization::IdentID ID, IdentifierInfo *II) {}
83    virtual void TypeRead(serialization::TypeIdx Idx, QualType T) {}
84    virtual void SelectorRead(serialization::SelectorID iD, Selector Sel) {}
85    virtual void MacroDefinitionRead(serialization::MacroID,
86                                     MacroDefinition *MD) {}
87};
88
89} // end anonymous namespace
90
91FrontendAction::FrontendAction() : Instance(0) {}
92
93FrontendAction::~FrontendAction() {}
94
95void FrontendAction::setCurrentFile(llvm::StringRef Value, InputKind Kind,
96                                    ASTUnit *AST) {
97  CurrentFile = Value;
98  CurrentFileKind = Kind;
99  CurrentASTUnit.reset(AST);
100}
101
102bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
103                                     llvm::StringRef Filename,
104                                     InputKind InputKind) {
105  assert(!Instance && "Already processing a source file!");
106  assert(!Filename.empty() && "Unexpected empty filename!");
107  setCurrentFile(Filename, InputKind);
108  setCompilerInstance(&CI);
109
110  // AST files follow a very different path, since they share objects via the
111  // AST unit.
112  if (InputKind == IK_AST) {
113    assert(!usesPreprocessorOnly() &&
114           "Attempt to pass AST file to preprocessor only action!");
115    assert(hasASTFileSupport() &&
116           "This action does not have AST file support!");
117
118    llvm::IntrusiveRefCntPtr<Diagnostic> Diags(&CI.getDiagnostics());
119    std::string Error;
120    ASTUnit *AST = ASTUnit::LoadFromASTFile(Filename, Diags);
121    if (!AST)
122      goto failure;
123
124    setCurrentFile(Filename, InputKind, AST);
125
126    // Set the shared objects, these are reset when we finish processing the
127    // file, otherwise the CompilerInstance will happily destroy them.
128    CI.setFileManager(&AST->getFileManager());
129    CI.setSourceManager(&AST->getSourceManager());
130    CI.setPreprocessor(&AST->getPreprocessor());
131    CI.setASTContext(&AST->getASTContext());
132
133    // Initialize the action.
134    if (!BeginSourceFileAction(CI, Filename))
135      goto failure;
136
137    /// Create the AST consumer.
138    CI.setASTConsumer(CreateASTConsumer(CI, Filename));
139    if (!CI.hasASTConsumer())
140      goto failure;
141
142    return true;
143  }
144
145  // Set up the file and source managers, if needed.
146  if (!CI.hasFileManager())
147    CI.createFileManager();
148  if (!CI.hasSourceManager())
149    CI.createSourceManager();
150
151  // IR files bypass the rest of initialization.
152  if (InputKind == IK_LLVM_IR) {
153    assert(hasIRSupport() &&
154           "This action does not have IR file support!");
155
156    // Inform the diagnostic client we are processing a source file.
157    CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 0);
158
159    // Initialize the action.
160    if (!BeginSourceFileAction(CI, Filename))
161      goto failure;
162
163    return true;
164  }
165
166  // Set up the preprocessor.
167  CI.createPreprocessor();
168
169  // Inform the diagnostic client we are processing a source file.
170  CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(),
171                                           &CI.getPreprocessor());
172
173  // Initialize the action.
174  if (!BeginSourceFileAction(CI, Filename))
175    goto failure;
176
177  /// Create the AST context and consumer unless this is a preprocessor only
178  /// action.
179  if (!usesPreprocessorOnly()) {
180    CI.createASTContext();
181
182    llvm::OwningPtr<ASTConsumer> Consumer(CreateASTConsumer(CI, Filename));
183
184    /// Use PCH?
185    if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
186      assert(hasPCHSupport() && "This action does not have PCH support!");
187      ASTDeserializationListener *DeserialListener
188          = CI.getInvocation().getFrontendOpts().ChainedPCH ?
189                  Consumer->GetASTDeserializationListener() : 0;
190      if (CI.getPreprocessorOpts().DumpDeserializedPCHDecls)
191        DeserialListener = new DeserializedDeclsDumper(DeserialListener);
192      if (!CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn.empty())
193        DeserialListener = new DeserializedDeclsChecker(CI.getASTContext(),
194                         CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn,
195                                                        DeserialListener);
196      CI.createPCHExternalASTSource(
197                                CI.getPreprocessorOpts().ImplicitPCHInclude,
198                                CI.getPreprocessorOpts().DisablePCHValidation,
199                                DeserialListener);
200      if (!CI.getASTContext().getExternalSource())
201        goto failure;
202    }
203
204    CI.setASTConsumer(Consumer.take());
205    if (!CI.hasASTConsumer())
206      goto failure;
207  }
208
209  // Initialize builtin info as long as we aren't using an external AST
210  // source.
211  if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
212    Preprocessor &PP = CI.getPreprocessor();
213    PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
214                                           PP.getLangOptions().NoBuiltin);
215  }
216
217  return true;
218
219  // If we failed, reset state since the client will not end up calling the
220  // matching EndSourceFile().
221  failure:
222  if (isCurrentFileAST()) {
223    CI.takeASTContext();
224    CI.takePreprocessor();
225    CI.takeSourceManager();
226    CI.takeFileManager();
227  }
228
229  CI.getDiagnosticClient().EndSourceFile();
230  setCurrentFile("", IK_None);
231  setCompilerInstance(0);
232  return false;
233}
234
235void FrontendAction::Execute() {
236  CompilerInstance &CI = getCompilerInstance();
237
238  // Initialize the main file entry. This needs to be delayed until after PCH
239  // has loaded.
240  if (isCurrentFileAST()) {
241    // Set the main file ID to an empty file.
242    //
243    // FIXME: We probably shouldn't need this, but for now this is the
244    // simplest way to reuse the logic in ParseAST.
245    const char *EmptyStr = "";
246    llvm::MemoryBuffer *SB =
247      llvm::MemoryBuffer::getMemBuffer(EmptyStr, "<dummy input>");
248    CI.getSourceManager().createMainFileIDForMemBuffer(SB);
249  } else {
250    if (!CI.InitializeSourceManager(getCurrentFile()))
251      return;
252  }
253
254  if (CI.hasFrontendTimer()) {
255    llvm::TimeRegion Timer(CI.getFrontendTimer());
256    ExecuteAction();
257  }
258  else ExecuteAction();
259}
260
261void FrontendAction::EndSourceFile() {
262  CompilerInstance &CI = getCompilerInstance();
263
264  // Finalize the action.
265  EndSourceFileAction();
266
267  // Release the consumer and the AST, in that order since the consumer may
268  // perform actions in its destructor which require the context.
269  //
270  // FIXME: There is more per-file stuff we could just drop here?
271  if (CI.getFrontendOpts().DisableFree) {
272    CI.takeASTConsumer();
273    if (!isCurrentFileAST()) {
274      CI.takeSema();
275      CI.takeASTContext();
276    }
277  } else {
278    if (!isCurrentFileAST()) {
279      CI.setSema(0);
280      CI.setASTContext(0);
281    }
282    CI.setASTConsumer(0);
283  }
284
285  // Inform the preprocessor we are done.
286  if (CI.hasPreprocessor())
287    CI.getPreprocessor().EndSourceFile();
288
289  if (CI.getFrontendOpts().ShowStats) {
290    llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n";
291    CI.getPreprocessor().PrintStats();
292    CI.getPreprocessor().getIdentifierTable().PrintStats();
293    CI.getPreprocessor().getHeaderSearchInfo().PrintStats();
294    CI.getSourceManager().PrintStats();
295    llvm::errs() << "\n";
296  }
297
298  // Cleanup the output streams, and erase the output files if we encountered
299  // an error.
300  CI.clearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().getNumErrors());
301
302  // Inform the diagnostic client we are done with this source file.
303  CI.getDiagnosticClient().EndSourceFile();
304
305  if (isCurrentFileAST()) {
306    CI.takeSema();
307    CI.takeASTContext();
308    CI.takePreprocessor();
309    CI.takeSourceManager();
310    CI.takeFileManager();
311  }
312
313  setCompilerInstance(0);
314  setCurrentFile("", IK_None);
315}
316
317//===----------------------------------------------------------------------===//
318// Utility Actions
319//===----------------------------------------------------------------------===//
320
321void ASTFrontendAction::ExecuteAction() {
322  CompilerInstance &CI = getCompilerInstance();
323
324  // FIXME: Move the truncation aspect of this into Sema, we delayed this till
325  // here so the source manager would be initialized.
326  if (hasCodeCompletionSupport() &&
327      !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
328    CI.createCodeCompletionConsumer();
329
330  // Use a code completion consumer?
331  CodeCompleteConsumer *CompletionConsumer = 0;
332  if (CI.hasCodeCompletionConsumer())
333    CompletionConsumer = &CI.getCodeCompletionConsumer();
334
335  if (!CI.hasSema())
336    CI.createSema(usesCompleteTranslationUnit(), CompletionConsumer);
337
338  ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats);
339}
340
341ASTConsumer *
342PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
343                                              llvm::StringRef InFile) {
344  llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!");
345}
346