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/Frontend/ASTUnit.h"
     15 #include "clang/Frontend/CompilerInstance.h"
     16 #include "clang/Frontend/FrontendDiagnostic.h"
     17 #include "clang/Frontend/FrontendPluginRegistry.h"
     18 #include "clang/Frontend/LayoutOverrideSource.h"
     19 #include "clang/Frontend/MultiplexConsumer.h"
     20 #include "clang/Frontend/Utils.h"
     21 #include "clang/Lex/HeaderSearch.h"
     22 #include "clang/Lex/Preprocessor.h"
     23 #include "clang/Parse/ParseAST.h"
     24 #include "clang/Serialization/ASTDeserializationListener.h"
     25 #include "clang/Serialization/ASTReader.h"
     26 #include "clang/Serialization/GlobalModuleIndex.h"
     27 #include "llvm/Support/ErrorHandling.h"
     28 #include "llvm/Support/FileSystem.h"
     29 #include "llvm/Support/MemoryBuffer.h"
     30 #include "llvm/Support/Timer.h"
     31 #include "llvm/Support/raw_ostream.h"
     32 #include <system_error>
     33 using namespace clang;
     34 
     35 template class llvm::Registry<clang::PluginASTAction>;
     36 
     37 namespace {
     38 
     39 class DelegatingDeserializationListener : public ASTDeserializationListener {
     40   ASTDeserializationListener *Previous;
     41   bool DeletePrevious;
     42 
     43 public:
     44   explicit DelegatingDeserializationListener(
     45       ASTDeserializationListener *Previous, bool DeletePrevious)
     46       : Previous(Previous), DeletePrevious(DeletePrevious) {}
     47   ~DelegatingDeserializationListener() override {
     48     if (DeletePrevious)
     49       delete Previous;
     50   }
     51 
     52   void ReaderInitialized(ASTReader *Reader) override {
     53     if (Previous)
     54       Previous->ReaderInitialized(Reader);
     55   }
     56   void IdentifierRead(serialization::IdentID ID,
     57                       IdentifierInfo *II) override {
     58     if (Previous)
     59       Previous->IdentifierRead(ID, II);
     60   }
     61   void TypeRead(serialization::TypeIdx Idx, QualType T) override {
     62     if (Previous)
     63       Previous->TypeRead(Idx, T);
     64   }
     65   void DeclRead(serialization::DeclID ID, const Decl *D) override {
     66     if (Previous)
     67       Previous->DeclRead(ID, D);
     68   }
     69   void SelectorRead(serialization::SelectorID ID, Selector Sel) override {
     70     if (Previous)
     71       Previous->SelectorRead(ID, Sel);
     72   }
     73   void MacroDefinitionRead(serialization::PreprocessedEntityID PPID,
     74                            MacroDefinitionRecord *MD) override {
     75     if (Previous)
     76       Previous->MacroDefinitionRead(PPID, MD);
     77   }
     78 };
     79 
     80 /// \brief Dumps deserialized declarations.
     81 class DeserializedDeclsDumper : public DelegatingDeserializationListener {
     82 public:
     83   explicit DeserializedDeclsDumper(ASTDeserializationListener *Previous,
     84                                    bool DeletePrevious)
     85       : DelegatingDeserializationListener(Previous, DeletePrevious) {}
     86 
     87   void DeclRead(serialization::DeclID ID, const Decl *D) override {
     88     llvm::outs() << "PCH DECL: " << D->getDeclKindName();
     89     if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
     90       llvm::outs() << " - " << *ND;
     91     llvm::outs() << "\n";
     92 
     93     DelegatingDeserializationListener::DeclRead(ID, D);
     94   }
     95 };
     96 
     97 /// \brief Checks deserialized declarations and emits error if a name
     98 /// matches one given in command-line using -error-on-deserialized-decl.
     99 class DeserializedDeclsChecker : public DelegatingDeserializationListener {
    100   ASTContext &Ctx;
    101   std::set<std::string> NamesToCheck;
    102 
    103 public:
    104   DeserializedDeclsChecker(ASTContext &Ctx,
    105                            const std::set<std::string> &NamesToCheck,
    106                            ASTDeserializationListener *Previous,
    107                            bool DeletePrevious)
    108       : DelegatingDeserializationListener(Previous, DeletePrevious), Ctx(Ctx),
    109         NamesToCheck(NamesToCheck) {}
    110 
    111   void DeclRead(serialization::DeclID ID, const Decl *D) override {
    112     if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
    113       if (NamesToCheck.find(ND->getNameAsString()) != NamesToCheck.end()) {
    114         unsigned DiagID
    115           = Ctx.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error,
    116                                                  "%0 was deserialized");
    117         Ctx.getDiagnostics().Report(Ctx.getFullLoc(D->getLocation()), DiagID)
    118             << ND->getNameAsString();
    119       }
    120 
    121     DelegatingDeserializationListener::DeclRead(ID, D);
    122   }
    123 };
    124 
    125 } // end anonymous namespace
    126 
    127 FrontendAction::FrontendAction() : Instance(nullptr) {}
    128 
    129 FrontendAction::~FrontendAction() {}
    130 
    131 void FrontendAction::setCurrentInput(const FrontendInputFile &CurrentInput,
    132                                      std::unique_ptr<ASTUnit> AST) {
    133   this->CurrentInput = CurrentInput;
    134   CurrentASTUnit = std::move(AST);
    135 }
    136 
    137 std::unique_ptr<ASTConsumer>
    138 FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
    139                                          StringRef InFile) {
    140   std::unique_ptr<ASTConsumer> Consumer = CreateASTConsumer(CI, InFile);
    141   if (!Consumer)
    142     return nullptr;
    143 
    144   if (CI.getFrontendOpts().AddPluginActions.size() == 0)
    145     return Consumer;
    146 
    147   // Make sure the non-plugin consumer is first, so that plugins can't
    148   // modifiy the AST.
    149   std::vector<std::unique_ptr<ASTConsumer>> Consumers;
    150   Consumers.push_back(std::move(Consumer));
    151 
    152   for (size_t i = 0, e = CI.getFrontendOpts().AddPluginActions.size();
    153        i != e; ++i) {
    154     // This is O(|plugins| * |add_plugins|), but since both numbers are
    155     // way below 50 in practice, that's ok.
    156     for (FrontendPluginRegistry::iterator
    157         it = FrontendPluginRegistry::begin(),
    158         ie = FrontendPluginRegistry::end();
    159         it != ie; ++it) {
    160       if (it->getName() != CI.getFrontendOpts().AddPluginActions[i])
    161         continue;
    162       std::unique_ptr<PluginASTAction> P = it->instantiate();
    163       if (P->ParseArgs(CI, CI.getFrontendOpts().AddPluginArgs[i]))
    164         Consumers.push_back(P->CreateASTConsumer(CI, InFile));
    165     }
    166   }
    167 
    168   return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
    169 }
    170 
    171 bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
    172                                      const FrontendInputFile &Input) {
    173   assert(!Instance && "Already processing a source file!");
    174   assert(!Input.isEmpty() && "Unexpected empty filename!");
    175   setCurrentInput(Input);
    176   setCompilerInstance(&CI);
    177 
    178   StringRef InputFile = Input.getFile();
    179   bool HasBegunSourceFile = false;
    180   if (!BeginInvocation(CI))
    181     goto failure;
    182 
    183   // AST files follow a very different path, since they share objects via the
    184   // AST unit.
    185   if (Input.getKind() == IK_AST) {
    186     assert(!usesPreprocessorOnly() &&
    187            "Attempt to pass AST file to preprocessor only action!");
    188     assert(hasASTFileSupport() &&
    189            "This action does not have AST file support!");
    190 
    191     IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
    192 
    193     std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromASTFile(
    194         InputFile, CI.getPCHContainerReader(), Diags, CI.getFileSystemOpts(),
    195         CI.getCodeGenOpts().DebugTypeExtRefs);
    196 
    197     if (!AST)
    198       goto failure;
    199 
    200     // Inform the diagnostic client we are processing a source file.
    201     CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), nullptr);
    202     HasBegunSourceFile = true;
    203 
    204     // Set the shared objects, these are reset when we finish processing the
    205     // file, otherwise the CompilerInstance will happily destroy them.
    206     CI.setFileManager(&AST->getFileManager());
    207     CI.setSourceManager(&AST->getSourceManager());
    208     CI.setPreprocessor(&AST->getPreprocessor());
    209     CI.setASTContext(&AST->getASTContext());
    210 
    211     setCurrentInput(Input, std::move(AST));
    212 
    213     // Initialize the action.
    214     if (!BeginSourceFileAction(CI, InputFile))
    215       goto failure;
    216 
    217     // Create the AST consumer.
    218     CI.setASTConsumer(CreateWrappedASTConsumer(CI, InputFile));
    219     if (!CI.hasASTConsumer())
    220       goto failure;
    221 
    222     return true;
    223   }
    224 
    225   if (!CI.hasVirtualFileSystem()) {
    226     if (IntrusiveRefCntPtr<vfs::FileSystem> VFS =
    227           createVFSFromCompilerInvocation(CI.getInvocation(),
    228                                           CI.getDiagnostics()))
    229       CI.setVirtualFileSystem(VFS);
    230     else
    231       goto failure;
    232   }
    233 
    234   // Set up the file and source managers, if needed.
    235   if (!CI.hasFileManager())
    236     CI.createFileManager();
    237   if (!CI.hasSourceManager())
    238     CI.createSourceManager(CI.getFileManager());
    239 
    240   // IR files bypass the rest of initialization.
    241   if (Input.getKind() == IK_LLVM_IR) {
    242     assert(hasIRSupport() &&
    243            "This action does not have IR file support!");
    244 
    245     // Inform the diagnostic client we are processing a source file.
    246     CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(), nullptr);
    247     HasBegunSourceFile = true;
    248 
    249     // Initialize the action.
    250     if (!BeginSourceFileAction(CI, InputFile))
    251       goto failure;
    252 
    253     // Initialize the main file entry.
    254     if (!CI.InitializeSourceManager(CurrentInput))
    255       goto failure;
    256 
    257     return true;
    258   }
    259 
    260   // If the implicit PCH include is actually a directory, rather than
    261   // a single file, search for a suitable PCH file in that directory.
    262   if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
    263     FileManager &FileMgr = CI.getFileManager();
    264     PreprocessorOptions &PPOpts = CI.getPreprocessorOpts();
    265     StringRef PCHInclude = PPOpts.ImplicitPCHInclude;
    266     std::string SpecificModuleCachePath = CI.getSpecificModuleCachePath();
    267     if (const DirectoryEntry *PCHDir = FileMgr.getDirectory(PCHInclude)) {
    268       std::error_code EC;
    269       SmallString<128> DirNative;
    270       llvm::sys::path::native(PCHDir->getName(), DirNative);
    271       bool Found = false;
    272       for (llvm::sys::fs::directory_iterator Dir(DirNative, EC), DirEnd;
    273            Dir != DirEnd && !EC; Dir.increment(EC)) {
    274         // Check whether this is an acceptable AST file.
    275         if (ASTReader::isAcceptableASTFile(
    276                 Dir->path(), FileMgr, CI.getPCHContainerReader(),
    277                 CI.getLangOpts(), CI.getTargetOpts(), CI.getPreprocessorOpts(),
    278                 SpecificModuleCachePath)) {
    279           PPOpts.ImplicitPCHInclude = Dir->path();
    280           Found = true;
    281           break;
    282         }
    283       }
    284 
    285       if (!Found) {
    286         CI.getDiagnostics().Report(diag::err_fe_no_pch_in_dir) << PCHInclude;
    287         goto failure;
    288       }
    289     }
    290   }
    291 
    292   // Set up the preprocessor if needed. When parsing model files the
    293   // preprocessor of the original source is reused.
    294   if (!isModelParsingAction())
    295     CI.createPreprocessor(getTranslationUnitKind());
    296 
    297   // Inform the diagnostic client we are processing a source file.
    298   CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(),
    299                                            &CI.getPreprocessor());
    300   HasBegunSourceFile = true;
    301 
    302   // Initialize the action.
    303   if (!BeginSourceFileAction(CI, InputFile))
    304     goto failure;
    305 
    306   // Initialize the main file entry. It is important that this occurs after
    307   // BeginSourceFileAction, which may change CurrentInput during module builds.
    308   if (!CI.InitializeSourceManager(CurrentInput))
    309     goto failure;
    310 
    311   // Create the AST context and consumer unless this is a preprocessor only
    312   // action.
    313   if (!usesPreprocessorOnly()) {
    314     // Parsing a model file should reuse the existing ASTContext.
    315     if (!isModelParsingAction())
    316       CI.createASTContext();
    317 
    318     std::unique_ptr<ASTConsumer> Consumer =
    319         CreateWrappedASTConsumer(CI, InputFile);
    320     if (!Consumer)
    321       goto failure;
    322 
    323     // FIXME: should not overwrite ASTMutationListener when parsing model files?
    324     if (!isModelParsingAction())
    325       CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener());
    326 
    327     if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) {
    328       // Convert headers to PCH and chain them.
    329       IntrusiveRefCntPtr<ExternalSemaSource> source, FinalReader;
    330       source = createChainedIncludesSource(CI, FinalReader);
    331       if (!source)
    332         goto failure;
    333       CI.setModuleManager(static_cast<ASTReader *>(FinalReader.get()));
    334       CI.getASTContext().setExternalSource(source);
    335     } else if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
    336       // Use PCH.
    337       assert(hasPCHSupport() && "This action does not have PCH support!");
    338       ASTDeserializationListener *DeserialListener =
    339           Consumer->GetASTDeserializationListener();
    340       bool DeleteDeserialListener = false;
    341       if (CI.getPreprocessorOpts().DumpDeserializedPCHDecls) {
    342         DeserialListener = new DeserializedDeclsDumper(DeserialListener,
    343                                                        DeleteDeserialListener);
    344         DeleteDeserialListener = true;
    345       }
    346       if (!CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn.empty()) {
    347         DeserialListener = new DeserializedDeclsChecker(
    348             CI.getASTContext(),
    349             CI.getPreprocessorOpts().DeserializedPCHDeclsToErrorOn,
    350             DeserialListener, DeleteDeserialListener);
    351         DeleteDeserialListener = true;
    352       }
    353       CI.createPCHExternalASTSource(
    354           CI.getPreprocessorOpts().ImplicitPCHInclude,
    355           CI.getPreprocessorOpts().DisablePCHValidation,
    356           CI.getPreprocessorOpts().AllowPCHWithCompilerErrors, DeserialListener,
    357           DeleteDeserialListener);
    358       if (!CI.getASTContext().getExternalSource())
    359         goto failure;
    360     }
    361 
    362     CI.setASTConsumer(std::move(Consumer));
    363     if (!CI.hasASTConsumer())
    364       goto failure;
    365   }
    366 
    367   // Initialize built-in info as long as we aren't using an external AST
    368   // source.
    369   if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
    370     Preprocessor &PP = CI.getPreprocessor();
    371 
    372     // If modules are enabled, create the module manager before creating
    373     // any builtins, so that all declarations know that they might be
    374     // extended by an external source.
    375     if (CI.getLangOpts().Modules)
    376       CI.createModuleManager();
    377 
    378     PP.getBuiltinInfo().initializeBuiltins(PP.getIdentifierTable(),
    379                                            PP.getLangOpts());
    380   } else {
    381     // FIXME: If this is a problem, recover from it by creating a multiplex
    382     // source.
    383     assert((!CI.getLangOpts().Modules || CI.getModuleManager()) &&
    384            "modules enabled but created an external source that "
    385            "doesn't support modules");
    386   }
    387 
    388   // If we were asked to load any module map files, do so now.
    389   for (const auto &Filename : CI.getFrontendOpts().ModuleMapFiles) {
    390     if (auto *File = CI.getFileManager().getFile(Filename))
    391       CI.getPreprocessor().getHeaderSearchInfo().loadModuleMapFile(
    392           File, /*IsSystem*/false);
    393     else
    394       CI.getDiagnostics().Report(diag::err_module_map_not_found) << Filename;
    395   }
    396 
    397   // If we were asked to load any module files, do so now.
    398   for (const auto &ModuleFile : CI.getFrontendOpts().ModuleFiles)
    399     if (!CI.loadModuleFile(ModuleFile))
    400       goto failure;
    401 
    402   // If there is a layout overrides file, attach an external AST source that
    403   // provides the layouts from that file.
    404   if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() &&
    405       CI.hasASTContext() && !CI.getASTContext().getExternalSource()) {
    406     IntrusiveRefCntPtr<ExternalASTSource>
    407       Override(new LayoutOverrideSource(
    408                      CI.getFrontendOpts().OverrideRecordLayoutsFile));
    409     CI.getASTContext().setExternalSource(Override);
    410   }
    411 
    412   return true;
    413 
    414   // If we failed, reset state since the client will not end up calling the
    415   // matching EndSourceFile().
    416   failure:
    417   if (isCurrentFileAST()) {
    418     CI.setASTContext(nullptr);
    419     CI.setPreprocessor(nullptr);
    420     CI.setSourceManager(nullptr);
    421     CI.setFileManager(nullptr);
    422   }
    423 
    424   if (HasBegunSourceFile)
    425     CI.getDiagnosticClient().EndSourceFile();
    426   CI.clearOutputFiles(/*EraseFiles=*/true);
    427   setCurrentInput(FrontendInputFile());
    428   setCompilerInstance(nullptr);
    429   return false;
    430 }
    431 
    432 bool FrontendAction::Execute() {
    433   CompilerInstance &CI = getCompilerInstance();
    434 
    435   if (CI.hasFrontendTimer()) {
    436     llvm::TimeRegion Timer(CI.getFrontendTimer());
    437     ExecuteAction();
    438   }
    439   else ExecuteAction();
    440 
    441   // If we are supposed to rebuild the global module index, do so now unless
    442   // there were any module-build failures.
    443   if (CI.shouldBuildGlobalModuleIndex() && CI.hasFileManager() &&
    444       CI.hasPreprocessor()) {
    445     StringRef Cache =
    446         CI.getPreprocessor().getHeaderSearchInfo().getModuleCachePath();
    447     if (!Cache.empty())
    448       GlobalModuleIndex::writeIndex(CI.getFileManager(),
    449                                     CI.getPCHContainerReader(), Cache);
    450   }
    451 
    452   return true;
    453 }
    454 
    455 void FrontendAction::EndSourceFile() {
    456   CompilerInstance &CI = getCompilerInstance();
    457 
    458   // Inform the diagnostic client we are done with this source file.
    459   CI.getDiagnosticClient().EndSourceFile();
    460 
    461   // Inform the preprocessor we are done.
    462   if (CI.hasPreprocessor())
    463     CI.getPreprocessor().EndSourceFile();
    464 
    465   // Finalize the action.
    466   EndSourceFileAction();
    467 
    468   // Sema references the ast consumer, so reset sema first.
    469   //
    470   // FIXME: There is more per-file stuff we could just drop here?
    471   bool DisableFree = CI.getFrontendOpts().DisableFree;
    472   if (DisableFree) {
    473     CI.resetAndLeakSema();
    474     CI.resetAndLeakASTContext();
    475     BuryPointer(CI.takeASTConsumer().get());
    476   } else {
    477     CI.setSema(nullptr);
    478     CI.setASTContext(nullptr);
    479     CI.setASTConsumer(nullptr);
    480   }
    481 
    482   if (CI.getFrontendOpts().ShowStats) {
    483     llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n";
    484     CI.getPreprocessor().PrintStats();
    485     CI.getPreprocessor().getIdentifierTable().PrintStats();
    486     CI.getPreprocessor().getHeaderSearchInfo().PrintStats();
    487     CI.getSourceManager().PrintStats();
    488     llvm::errs() << "\n";
    489   }
    490 
    491   // Cleanup the output streams, and erase the output files if instructed by the
    492   // FrontendAction.
    493   CI.clearOutputFiles(/*EraseFiles=*/shouldEraseOutputFiles());
    494 
    495   if (isCurrentFileAST()) {
    496     if (DisableFree) {
    497       CI.resetAndLeakPreprocessor();
    498       CI.resetAndLeakSourceManager();
    499       CI.resetAndLeakFileManager();
    500     } else {
    501       CI.setPreprocessor(nullptr);
    502       CI.setSourceManager(nullptr);
    503       CI.setFileManager(nullptr);
    504     }
    505   }
    506 
    507   setCompilerInstance(nullptr);
    508   setCurrentInput(FrontendInputFile());
    509 }
    510 
    511 bool FrontendAction::shouldEraseOutputFiles() {
    512   return getCompilerInstance().getDiagnostics().hasErrorOccurred();
    513 }
    514 
    515 //===----------------------------------------------------------------------===//
    516 // Utility Actions
    517 //===----------------------------------------------------------------------===//
    518 
    519 void ASTFrontendAction::ExecuteAction() {
    520   CompilerInstance &CI = getCompilerInstance();
    521   if (!CI.hasPreprocessor())
    522     return;
    523 
    524   // FIXME: Move the truncation aspect of this into Sema, we delayed this till
    525   // here so the source manager would be initialized.
    526   if (hasCodeCompletionSupport() &&
    527       !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
    528     CI.createCodeCompletionConsumer();
    529 
    530   // Use a code completion consumer?
    531   CodeCompleteConsumer *CompletionConsumer = nullptr;
    532   if (CI.hasCodeCompletionConsumer())
    533     CompletionConsumer = &CI.getCodeCompletionConsumer();
    534 
    535   if (!CI.hasSema())
    536     CI.createSema(getTranslationUnitKind(), CompletionConsumer);
    537 
    538   ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats,
    539            CI.getFrontendOpts().SkipFunctionBodies);
    540 }
    541 
    542 void PluginASTAction::anchor() { }
    543 
    544 std::unique_ptr<ASTConsumer>
    545 PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
    546                                               StringRef InFile) {
    547   llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!");
    548 }
    549 
    550 std::unique_ptr<ASTConsumer>
    551 WrapperFrontendAction::CreateASTConsumer(CompilerInstance &CI,
    552                                          StringRef InFile) {
    553   return WrappedAction->CreateASTConsumer(CI, InFile);
    554 }
    555 bool WrapperFrontendAction::BeginInvocation(CompilerInstance &CI) {
    556   return WrappedAction->BeginInvocation(CI);
    557 }
    558 bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI,
    559                                                   StringRef Filename) {
    560   WrappedAction->setCurrentInput(getCurrentInput());
    561   WrappedAction->setCompilerInstance(&CI);
    562   return WrappedAction->BeginSourceFileAction(CI, Filename);
    563 }
    564 void WrapperFrontendAction::ExecuteAction() {
    565   WrappedAction->ExecuteAction();
    566 }
    567 void WrapperFrontendAction::EndSourceFileAction() {
    568   WrappedAction->EndSourceFileAction();
    569 }
    570 
    571 bool WrapperFrontendAction::usesPreprocessorOnly() const {
    572   return WrappedAction->usesPreprocessorOnly();
    573 }
    574 TranslationUnitKind WrapperFrontendAction::getTranslationUnitKind() {
    575   return WrappedAction->getTranslationUnitKind();
    576 }
    577 bool WrapperFrontendAction::hasPCHSupport() const {
    578   return WrappedAction->hasPCHSupport();
    579 }
    580 bool WrapperFrontendAction::hasASTFileSupport() const {
    581   return WrappedAction->hasASTFileSupport();
    582 }
    583 bool WrapperFrontendAction::hasIRSupport() const {
    584   return WrappedAction->hasIRSupport();
    585 }
    586 bool WrapperFrontendAction::hasCodeCompletionSupport() const {
    587   return WrappedAction->hasCodeCompletionSupport();
    588 }
    589 
    590 WrapperFrontendAction::WrapperFrontendAction(FrontendAction *WrappedAction)
    591   : WrappedAction(WrappedAction) {}
    592 
    593