Home | History | Annotate | Download | only in Frontend
      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/AST/DeclGroup.h"
     14 #include "clang/Lex/HeaderSearch.h"
     15 #include "clang/Lex/Preprocessor.h"
     16 #include "clang/Frontend/ASTUnit.h"
     17 #include "clang/Frontend/CompilerInstance.h"
     18 #include "clang/Frontend/FrontendDiagnostic.h"
     19 #include "clang/Frontend/FrontendPluginRegistry.h"
     20 #include "clang/Frontend/MultiplexConsumer.h"
     21 #include "clang/Parse/ParseAST.h"
     22 #include "clang/Serialization/ASTDeserializationListener.h"
     23 #include "clang/Serialization/ASTReader.h"
     24 #include "clang/Serialization/ChainedIncludesSource.h"
     25 #include "llvm/Support/MemoryBuffer.h"
     26 #include "llvm/Support/Timer.h"
     27 #include "llvm/Support/ErrorHandling.h"
     28 #include "llvm/Support/raw_ostream.h"
     29 using namespace clang;
     30 
     31 namespace {
     32 
     33 /// \brief Dumps deserialized declarations.
     34 class DeserializedDeclsDumper : public ASTDeserializationListener {
     35   ASTDeserializationListener *Previous;
     36 
     37 public:
     38   DeserializedDeclsDumper(ASTDeserializationListener *Previous)
     39     : Previous(Previous) { }
     40 
     41   virtual void DeclRead(serialization::DeclID ID, const Decl *D) {
     42     llvm::outs() << "PCH DECL: " << D->getDeclKindName();
     43     if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
     44       llvm::outs() << " - " << ND->getNameAsString();
     45     llvm::outs() << "\n";
     46 
     47     if (Previous)
     48       Previous->DeclRead(ID, D);
     49   }
     50 };
     51 
     52   /// \brief Checks deserialized declarations and emits error if a name
     53   /// matches one given in command-line using -error-on-deserialized-decl.
     54   class DeserializedDeclsChecker : public ASTDeserializationListener {
     55     ASTContext &Ctx;
     56     std::set<std::string> NamesToCheck;
     57     ASTDeserializationListener *Previous;
     58 
     59   public:
     60     DeserializedDeclsChecker(ASTContext &Ctx,
     61                              const std::set<std::string> &NamesToCheck,
     62                              ASTDeserializationListener *Previous)
     63       : Ctx(Ctx), NamesToCheck(NamesToCheck), Previous(Previous) { }
     64 
     65     virtual void DeclRead(serialization::DeclID ID, const Decl *D) {
     66       if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
     67         if (NamesToCheck.find(ND->getNameAsString()) != NamesToCheck.end()) {
     68           unsigned DiagID
     69             = Ctx.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error,
     70                                                    "%0 was deserialized");
     71           Ctx.getDiagnostics().Report(Ctx.getFullLoc(D->getLocation()), DiagID)
     72               << ND->getNameAsString();
     73         }
     74 
     75       if (Previous)
     76         Previous->DeclRead(ID, D);
     77     }
     78 };
     79 
     80 } // end anonymous namespace
     81 
     82 FrontendAction::FrontendAction() : Instance(0) {}
     83 
     84 FrontendAction::~FrontendAction() {}
     85 
     86 void FrontendAction::setCurrentFile(StringRef Value, InputKind Kind,
     87                                     ASTUnit *AST) {
     88   CurrentFile = Value;
     89   CurrentFileKind = Kind;
     90   CurrentASTUnit.reset(AST);
     91 }
     92 
     93 ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
     94                                                       StringRef InFile) {
     95   ASTConsumer* Consumer = CreateASTConsumer(CI, InFile);
     96   if (!Consumer)
     97     return 0;
     98 
     99   if (CI.getFrontendOpts().AddPluginActions.size() == 0)
    100     return Consumer;
    101 
    102   // Make sure the non-plugin consumer is first, so that plugins can't
    103   // modifiy the AST.
    104   std::vector<ASTConsumer*> Consumers(1, Consumer);
    105 
    106   for (size_t i = 0, e = CI.getFrontendOpts().AddPluginActions.size();
    107        i != e; ++i) {
    108     // This is O(|plugins| * |add_plugins|), but since both numbers are
    109     // way below 50 in practice, that's ok.
    110     for (FrontendPluginRegistry::iterator
    111         it = FrontendPluginRegistry::begin(),
    112         ie = FrontendPluginRegistry::end();
    113         it != ie; ++it) {
    114       if (it->getName() == CI.getFrontendOpts().AddPluginActions[i]) {
    115         llvm::OwningPtr<PluginASTAction> P(it->instantiate());
    116         FrontendAction* c = P.get();
    117         if (P->ParseArgs(CI, CI.getFrontendOpts().AddPluginArgs[i]))
    118           Consumers.push_back(c->CreateASTConsumer(CI, InFile));
    119       }
    120     }
    121   }
    122 
    123   return new MultiplexConsumer(Consumers);
    124 }
    125 
    126 bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
    127                                      StringRef Filename,
    128                                      InputKind InputKind) {
    129   assert(!Instance && "Already processing a source file!");
    130   assert(!Filename.empty() && "Unexpected empty filename!");
    131   setCurrentFile(Filename, InputKind);
    132   setCompilerInstance(&CI);
    133 
    134   if (!BeginInvocation(CI))
    135     goto failure;
    136 
    137   // AST files follow a very different path, since they share objects via the
    138   // AST unit.
    139   if (InputKind == IK_AST) {
    140     assert(!usesPreprocessorOnly() &&
    141            "Attempt to pass AST file to preprocessor only action!");
    142     assert(hasASTFileSupport() &&
    143            "This action does not have AST file support!");
    144 
    145     llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
    146     std::string Error;
    147     ASTUnit *AST = ASTUnit::LoadFromASTFile(Filename, Diags,
    148                                             CI.getFileSystemOpts());
    149     if (!AST)
    150       goto failure;
    151 
    152     setCurrentFile(Filename, InputKind, AST);
    153 
    154     // Set the shared objects, these are reset when we finish processing the
    155     // file, otherwise the CompilerInstance will happily destroy them.
    156     CI.setFileManager(&AST->getFileManager());
    157     CI.setSourceManager(&AST->getSourceManager());
    158     CI.setPreprocessor(&AST->getPreprocessor());
    159     CI.setASTContext(&AST->getASTContext());
    160 
    161     // Initialize the action.
    162     if (!BeginSourceFileAction(CI, Filename))
    163       goto failure;
    164 
    165     /// Create the AST consumer.
    166     CI.setASTConsumer(CreateWrappedASTConsumer(CI, Filename));
    167     if (!CI.hasASTConsumer())
    168       goto failure;
    169 
    170     return true;
    171   }
    172 
    173   // Set up the file and source managers, if needed.
    174   if (!CI.hasFileManager())
    175     CI.createFileManager();
    176   if (!CI.hasSourceManager())
    177     CI.createSourceManager(CI.getFileManager());
    178 
    179   // IR files bypass the rest of initialization.
    180   if (InputKind == IK_LLVM_IR) {
    181     assert(hasIRSupport() &&
    182            "This action does not have IR file support!");
    183 
    184     // Inform the diagnostic client we are processing a source file.
    185     CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), 0);
    186 
    187     // Initialize the action.
    188     if (!BeginSourceFileAction(CI, Filename))
    189       goto failure;
    190 
    191     return true;
    192   }
    193 
    194   // Set up the preprocessor.
    195   CI.createPreprocessor();
    196 
    197   // Inform the diagnostic client we are processing a source file.
    198   CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(),
    199                                            &CI.getPreprocessor());
    200 
    201   // Initialize the action.
    202   if (!BeginSourceFileAction(CI, Filename))
    203     goto failure;
    204 
    205   /// Create the AST context and consumer unless this is a preprocessor only
    206   /// action.
    207   if (!usesPreprocessorOnly()) {
    208     CI.createASTContext();
    209 
    210     llvm::OwningPtr<ASTConsumer> Consumer(
    211         CreateWrappedASTConsumer(CI, Filename));
    212     if (!Consumer)
    213       goto failure;
    214 
    215     CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener());
    216 
    217     if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) {
    218       // Convert headers to PCH and chain them.
    219       llvm::OwningPtr<ExternalASTSource> source;
    220       source.reset(ChainedIncludesSource::create(CI));
    221       if (!source)
    222         goto failure;
    223       CI.getASTContext().setExternalSource(source);
    224 
    225     } else if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
    226       // Use PCH.
    227       assert(hasPCHSupport() && "This action does not have PCH support!");
    228       ASTDeserializationListener *DeserialListener =
    229           Consumer->GetASTDeserializationListener();
    230       if (CI.getPreprocessorOpts().DumpDeserializedPCHDecls)
    231         DeserialListener = new DeserializedDeclsDumper(DeserialListener);
    232       if (!CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn.empty())
    233         DeserialListener = new DeserializedDeclsChecker(CI.getASTContext(),
    234                          CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn,
    235                                                         DeserialListener);
    236       CI.createPCHExternalASTSource(
    237                                 CI.getPreprocessorOpts().ImplicitPCHInclude,
    238                                 CI.getPreprocessorOpts().DisablePCHValidation,
    239                                 CI.getPreprocessorOpts().DisableStatCache,
    240                                 DeserialListener);
    241       if (!CI.getASTContext().getExternalSource())
    242         goto failure;
    243     }
    244 
    245     CI.setASTConsumer(Consumer.take());
    246     if (!CI.hasASTConsumer())
    247       goto failure;
    248   }
    249 
    250   // Initialize built-in info as long as we aren't using an external AST
    251   // source.
    252   if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
    253     Preprocessor &PP = CI.getPreprocessor();
    254     PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
    255                                            PP.getLangOptions());
    256   }
    257 
    258   return true;
    259 
    260   // If we failed, reset state since the client will not end up calling the
    261   // matching EndSourceFile().
    262   failure:
    263   if (isCurrentFileAST()) {
    264     CI.setASTContext(0);
    265     CI.setPreprocessor(0);
    266     CI.setSourceManager(0);
    267     CI.setFileManager(0);
    268   }
    269 
    270   CI.getDiagnosticClient().EndSourceFile();
    271   setCurrentFile("", IK_None);
    272   setCompilerInstance(0);
    273   return false;
    274 }
    275 
    276 void FrontendAction::Execute() {
    277   CompilerInstance &CI = getCompilerInstance();
    278 
    279   // Initialize the main file entry. This needs to be delayed until after PCH
    280   // has loaded.
    281   if (isCurrentFileAST()) {
    282     // Set the main file ID to an empty file.
    283     //
    284     // FIXME: We probably shouldn't need this, but for now this is the
    285     // simplest way to reuse the logic in ParseAST.
    286     const char *EmptyStr = "";
    287     llvm::MemoryBuffer *SB =
    288       llvm::MemoryBuffer::getMemBuffer(EmptyStr, "<dummy input>");
    289     CI.getSourceManager().createMainFileIDForMemBuffer(SB);
    290   } else {
    291     if (!CI.InitializeSourceManager(getCurrentFile()))
    292       return;
    293   }
    294 
    295   if (CI.hasFrontendTimer()) {
    296     llvm::TimeRegion Timer(CI.getFrontendTimer());
    297     ExecuteAction();
    298   }
    299   else ExecuteAction();
    300 }
    301 
    302 void FrontendAction::EndSourceFile() {
    303   CompilerInstance &CI = getCompilerInstance();
    304 
    305   // Inform the diagnostic client we are done with this source file.
    306   CI.getDiagnosticClient().EndSourceFile();
    307 
    308   // Finalize the action.
    309   EndSourceFileAction();
    310 
    311   // Release the consumer and the AST, in that order since the consumer may
    312   // perform actions in its destructor which require the context.
    313   //
    314   // FIXME: There is more per-file stuff we could just drop here?
    315   if (CI.getFrontendOpts().DisableFree) {
    316     CI.takeASTConsumer();
    317     if (!isCurrentFileAST()) {
    318       CI.takeSema();
    319       CI.resetAndLeakASTContext();
    320     }
    321   } else {
    322     if (!isCurrentFileAST()) {
    323       CI.setSema(0);
    324       CI.setASTContext(0);
    325     }
    326     CI.setASTConsumer(0);
    327   }
    328 
    329   // Inform the preprocessor we are done.
    330   if (CI.hasPreprocessor())
    331     CI.getPreprocessor().EndSourceFile();
    332 
    333   if (CI.getFrontendOpts().ShowStats) {
    334     llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n";
    335     CI.getPreprocessor().PrintStats();
    336     CI.getPreprocessor().getIdentifierTable().PrintStats();
    337     CI.getPreprocessor().getHeaderSearchInfo().PrintStats();
    338     CI.getSourceManager().PrintStats();
    339     llvm::errs() << "\n";
    340   }
    341 
    342   // Cleanup the output streams, and erase the output files if we encountered
    343   // an error.
    344   CI.clearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().hasErrorOccurred());
    345 
    346   if (isCurrentFileAST()) {
    347     CI.takeSema();
    348     CI.resetAndLeakASTContext();
    349     CI.resetAndLeakPreprocessor();
    350     CI.resetAndLeakSourceManager();
    351     CI.resetAndLeakFileManager();
    352   }
    353 
    354   setCompilerInstance(0);
    355   setCurrentFile("", IK_None);
    356 }
    357 
    358 //===----------------------------------------------------------------------===//
    359 // Utility Actions
    360 //===----------------------------------------------------------------------===//
    361 
    362 void ASTFrontendAction::ExecuteAction() {
    363   CompilerInstance &CI = getCompilerInstance();
    364 
    365   // FIXME: Move the truncation aspect of this into Sema, we delayed this till
    366   // here so the source manager would be initialized.
    367   if (hasCodeCompletionSupport() &&
    368       !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
    369     CI.createCodeCompletionConsumer();
    370 
    371   // Use a code completion consumer?
    372   CodeCompleteConsumer *CompletionConsumer = 0;
    373   if (CI.hasCodeCompletionConsumer())
    374     CompletionConsumer = &CI.getCodeCompletionConsumer();
    375 
    376   if (!CI.hasSema())
    377     CI.createSema(getTranslationUnitKind(), CompletionConsumer);
    378 
    379   ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats);
    380 }
    381 
    382 ASTConsumer *
    383 PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
    384                                               StringRef InFile) {
    385   llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!");
    386 }
    387 
    388 ASTConsumer *WrapperFrontendAction::CreateASTConsumer(CompilerInstance &CI,
    389                                                       StringRef InFile) {
    390   return WrappedAction->CreateASTConsumer(CI, InFile);
    391 }
    392 bool WrapperFrontendAction::BeginInvocation(CompilerInstance &CI) {
    393   return WrappedAction->BeginInvocation(CI);
    394 }
    395 bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI,
    396                                                   StringRef Filename) {
    397   WrappedAction->setCurrentFile(getCurrentFile(), getCurrentFileKind());
    398   WrappedAction->setCompilerInstance(&CI);
    399   return WrappedAction->BeginSourceFileAction(CI, Filename);
    400 }
    401 void WrapperFrontendAction::ExecuteAction() {
    402   WrappedAction->ExecuteAction();
    403 }
    404 void WrapperFrontendAction::EndSourceFileAction() {
    405   WrappedAction->EndSourceFileAction();
    406 }
    407 
    408 bool WrapperFrontendAction::usesPreprocessorOnly() const {
    409   return WrappedAction->usesPreprocessorOnly();
    410 }
    411 TranslationUnitKind WrapperFrontendAction::getTranslationUnitKind() {
    412   return WrappedAction->getTranslationUnitKind();
    413 }
    414 bool WrapperFrontendAction::hasPCHSupport() const {
    415   return WrappedAction->hasPCHSupport();
    416 }
    417 bool WrapperFrontendAction::hasASTFileSupport() const {
    418   return WrappedAction->hasASTFileSupport();
    419 }
    420 bool WrapperFrontendAction::hasIRSupport() const {
    421   return WrappedAction->hasIRSupport();
    422 }
    423 bool WrapperFrontendAction::hasCodeCompletionSupport() const {
    424   return WrappedAction->hasCodeCompletionSupport();
    425 }
    426 
    427 WrapperFrontendAction::WrapperFrontendAction(FrontendAction *WrappedAction)
    428   : WrappedAction(WrappedAction) {}
    429 
    430