Home | History | Annotate | Line # | Download | only in Interpreter
      1 //===--------- IncrementalParser.cpp - Incremental Compilation  -----------===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // This file implements the class which performs incremental code compilation.
     10 //
     11 //===----------------------------------------------------------------------===//
     12 
     13 #include "IncrementalParser.h"
     14 
     15 #include "clang/CodeGen/BackendUtil.h"
     16 #include "clang/CodeGen/CodeGenAction.h"
     17 #include "clang/CodeGen/ModuleBuilder.h"
     18 #include "clang/Frontend/CompilerInstance.h"
     19 #include "clang/Frontend/FrontendAction.h"
     20 #include "clang/FrontendTool/Utils.h"
     21 #include "clang/Parse/Parser.h"
     22 #include "clang/Sema/Sema.h"
     23 
     24 #include "llvm/Option/ArgList.h"
     25 #include "llvm/Support/CrashRecoveryContext.h"
     26 #include "llvm/Support/Error.h"
     27 #include "llvm/Support/Timer.h"
     28 
     29 #include <sstream>
     30 
     31 namespace clang {
     32 
     33 /// A custom action enabling the incremental processing functionality.
     34 ///
     35 /// The usual \p FrontendAction expects one call to ExecuteAction and once it
     36 /// sees a call to \p EndSourceFile it deletes some of the important objects
     37 /// such as \p Preprocessor and \p Sema assuming no further input will come.
     38 ///
     39 /// \p IncrementalAction ensures it keep its underlying action's objects alive
     40 /// as long as the \p IncrementalParser needs them.
     41 ///
     42 class IncrementalAction : public WrapperFrontendAction {
     43 private:
     44   bool IsTerminating = false;
     45 
     46 public:
     47   IncrementalAction(CompilerInstance &CI, llvm::LLVMContext &LLVMCtx,
     48                     llvm::Error &Err)
     49       : WrapperFrontendAction([&]() {
     50           llvm::ErrorAsOutParameter EAO(&Err);
     51           std::unique_ptr<FrontendAction> Act;
     52           switch (CI.getFrontendOpts().ProgramAction) {
     53           default:
     54             Err = llvm::createStringError(
     55                 std::errc::state_not_recoverable,
     56                 "Driver initialization failed. "
     57                 "Incremental mode for action %d is not supported",
     58                 CI.getFrontendOpts().ProgramAction);
     59             return Act;
     60           case frontend::ASTDump:
     61             LLVM_FALLTHROUGH;
     62           case frontend::ASTPrint:
     63             LLVM_FALLTHROUGH;
     64           case frontend::ParseSyntaxOnly:
     65             Act = CreateFrontendAction(CI);
     66             break;
     67           case frontend::EmitAssembly:
     68             LLVM_FALLTHROUGH;
     69           case frontend::EmitObj:
     70             LLVM_FALLTHROUGH;
     71           case frontend::EmitLLVMOnly:
     72             Act.reset(new EmitLLVMOnlyAction(&LLVMCtx));
     73             break;
     74           }
     75           return Act;
     76         }()) {}
     77   FrontendAction *getWrapped() const { return WrappedAction.get(); }
     78   void ExecuteAction() override {
     79     CompilerInstance &CI = getCompilerInstance();
     80     assert(CI.hasPreprocessor() && "No PP!");
     81 
     82     // FIXME: Move the truncation aspect of this into Sema, we delayed this till
     83     // here so the source manager would be initialized.
     84     if (hasCodeCompletionSupport() &&
     85         !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
     86       CI.createCodeCompletionConsumer();
     87 
     88     // Use a code completion consumer?
     89     CodeCompleteConsumer *CompletionConsumer = nullptr;
     90     if (CI.hasCodeCompletionConsumer())
     91       CompletionConsumer = &CI.getCodeCompletionConsumer();
     92 
     93     Preprocessor &PP = CI.getPreprocessor();
     94     PP.enableIncrementalProcessing();
     95     PP.EnterMainSourceFile();
     96 
     97     if (!CI.hasSema())
     98       CI.createSema(getTranslationUnitKind(), CompletionConsumer);
     99   }
    100 
    101   // Do not terminate after processing the input. This allows us to keep various
    102   // clang objects alive and to incrementally grow the current TU.
    103   void EndSourceFile() override {
    104     // The WrappedAction can be nullptr if we issued an error in the ctor.
    105     if (IsTerminating && getWrapped())
    106       WrapperFrontendAction::EndSourceFile();
    107   }
    108 
    109   void FinalizeAction() {
    110     assert(!IsTerminating && "Already finalized!");
    111     IsTerminating = true;
    112     EndSourceFile();
    113   }
    114 };
    115 
    116 IncrementalParser::IncrementalParser(std::unique_ptr<CompilerInstance> Instance,
    117                                      llvm::LLVMContext &LLVMCtx,
    118                                      llvm::Error &Err)
    119     : CI(std::move(Instance)) {
    120   llvm::ErrorAsOutParameter EAO(&Err);
    121   Act = std::make_unique<IncrementalAction>(*CI, LLVMCtx, Err);
    122   if (Err)
    123     return;
    124   CI->ExecuteAction(*Act);
    125   Consumer = &CI->getASTConsumer();
    126   P.reset(
    127       new Parser(CI->getPreprocessor(), CI->getSema(), /*SkipBodies=*/false));
    128   P->Initialize();
    129 }
    130 
    131 IncrementalParser::~IncrementalParser() { Act->FinalizeAction(); }
    132 
    133 llvm::Expected<Transaction &> IncrementalParser::ParseOrWrapTopLevelDecl() {
    134   DiagnosticsEngine &Diags = getCI()->getDiagnostics();
    135 
    136   if (Diags.hasErrorOccurred())
    137     llvm::report_fatal_error("Previous input had errors, "
    138                              "recovery not yet supported",
    139                              /*GenCrashDiag=*/false);
    140 
    141   // Recover resources if we crash before exiting this method.
    142   Sema &S = CI->getSema();
    143   llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S);
    144   Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true);
    145   Sema::LocalEagerInstantiationScope LocalInstantiations(S);
    146 
    147   // Skip previous eof due to last incremental input.
    148   if (P->getCurToken().is(tok::eof))
    149     P->ConsumeToken();
    150 
    151   Transactions.emplace_back(Transaction());
    152   Transaction &LastTransaction = Transactions.back();
    153 
    154   Parser::DeclGroupPtrTy ADecl;
    155   for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl); !AtEOF;
    156        AtEOF = P->ParseTopLevelDecl(ADecl)) {
    157     // If we got a null return and something *was* parsed, ignore it.  This
    158     // is due to a top-level semicolon, an action override, or a parse error
    159     // skipping something.
    160     if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
    161       return llvm::make_error<llvm::StringError>("Parsing failed. "
    162                                                  "The consumer rejected a decl",
    163                                                  std::error_code());
    164     LastTransaction.Decls.push_back(ADecl.get());
    165   }
    166 
    167   // Process any TopLevelDecls generated by #pragma weak.
    168   for (Decl *D : S.WeakTopLevelDecls()) {
    169     DeclGroupRef DGR(D);
    170     LastTransaction.Decls.push_back(DGR);
    171     Consumer->HandleTopLevelDecl(DGR);
    172   }
    173 
    174   LocalInstantiations.perform();
    175   GlobalInstantiations.perform();
    176 
    177   Consumer->HandleTranslationUnit(S.getASTContext());
    178 
    179   if (Diags.hasErrorOccurred())
    180     return llvm::make_error<llvm::StringError>("Parsing failed.",
    181                                                std::error_code());
    182 
    183   return LastTransaction;
    184 }
    185 
    186 static CodeGenerator *getCodeGen(FrontendAction *Act) {
    187   IncrementalAction *IncrAct = static_cast<IncrementalAction *>(Act);
    188   FrontendAction *WrappedAct = IncrAct->getWrapped();
    189   if (!WrappedAct->hasIRSupport())
    190     return nullptr;
    191   return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator();
    192 }
    193 
    194 llvm::Expected<Transaction &> IncrementalParser::Parse(llvm::StringRef input) {
    195   Preprocessor &PP = CI->getPreprocessor();
    196   assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?");
    197 
    198   std::ostringstream SourceName;
    199   SourceName << "input_line_" << InputCount++;
    200 
    201   // Create an uninitialized memory buffer, copy code in and append "\n"
    202   size_t InputSize = input.size(); // don't include trailing 0
    203   // MemBuffer size should *not* include terminating zero
    204   std::unique_ptr<llvm::MemoryBuffer> MB(
    205       llvm::WritableMemoryBuffer::getNewUninitMemBuffer(InputSize + 1,
    206                                                         SourceName.str()));
    207   char *MBStart = const_cast<char *>(MB->getBufferStart());
    208   memcpy(MBStart, input.data(), InputSize);
    209   MBStart[InputSize] = '\n';
    210 
    211   SourceManager &SM = CI->getSourceManager();
    212 
    213   // FIXME: Create SourceLocation, which will allow clang to order the overload
    214   // candidates for example
    215   SourceLocation NewLoc = SM.getLocForStartOfFile(SM.getMainFileID());
    216 
    217   // Create FileID for the current buffer.
    218   FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0,
    219                                /*LoadedOffset=*/0, NewLoc);
    220 
    221   // NewLoc only used for diags.
    222   if (PP.EnterSourceFile(FID, /*DirLookup=*/0, NewLoc))
    223     return llvm::make_error<llvm::StringError>("Parsing failed. "
    224                                                "Cannot enter source file.",
    225                                                std::error_code());
    226 
    227   auto ErrOrTransaction = ParseOrWrapTopLevelDecl();
    228   if (auto Err = ErrOrTransaction.takeError())
    229     return std::move(Err);
    230 
    231   if (PP.getLangOpts().DelayedTemplateParsing) {
    232     // Microsoft-specific:
    233     // Late parsed templates can leave unswallowed "macro"-like tokens.
    234     // They will seriously confuse the Parser when entering the next
    235     // source file. So lex until we are EOF.
    236     Token Tok;
    237     do {
    238       PP.Lex(Tok);
    239     } while (Tok.isNot(tok::eof));
    240   }
    241 
    242   Token AssertTok;
    243   PP.Lex(AssertTok);
    244   assert(AssertTok.is(tok::eof) &&
    245          "Lexer must be EOF when starting incremental parse!");
    246 
    247   if (CodeGenerator *CG = getCodeGen(Act.get())) {
    248     std::unique_ptr<llvm::Module> M(CG->ReleaseModule());
    249     CG->StartModule("incr_module_" + std::to_string(Transactions.size()),
    250                     M->getContext());
    251 
    252     ErrOrTransaction->TheModule = std::move(M);
    253   }
    254 
    255   return ErrOrTransaction;
    256 }
    257 } // end namespace clang
    258