1fe6060f1SDimitry Andric //===--------- IncrementalParser.cpp - Incremental Compilation -----------===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric // 9fe6060f1SDimitry Andric // This file implements the class which performs incremental code compilation. 10fe6060f1SDimitry Andric // 11fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 12fe6060f1SDimitry Andric 13fe6060f1SDimitry Andric #include "IncrementalParser.h" 14fe6060f1SDimitry Andric 15fe6060f1SDimitry Andric #include "clang/AST/DeclContextInternals.h" 16fe6060f1SDimitry Andric #include "clang/CodeGen/BackendUtil.h" 17fe6060f1SDimitry Andric #include "clang/CodeGen/CodeGenAction.h" 18fe6060f1SDimitry Andric #include "clang/CodeGen/ModuleBuilder.h" 19fe6060f1SDimitry Andric #include "clang/Frontend/CompilerInstance.h" 20fe6060f1SDimitry Andric #include "clang/Frontend/FrontendAction.h" 21fe6060f1SDimitry Andric #include "clang/FrontendTool/Utils.h" 22fe6060f1SDimitry Andric #include "clang/Parse/Parser.h" 23fe6060f1SDimitry Andric #include "clang/Sema/Sema.h" 24fe6060f1SDimitry Andric 25fe6060f1SDimitry Andric #include "llvm/Option/ArgList.h" 26fe6060f1SDimitry Andric #include "llvm/Support/CrashRecoveryContext.h" 27fe6060f1SDimitry Andric #include "llvm/Support/Error.h" 28fe6060f1SDimitry Andric #include "llvm/Support/Timer.h" 29fe6060f1SDimitry Andric 30fe6060f1SDimitry Andric #include <sstream> 31fe6060f1SDimitry Andric 32fe6060f1SDimitry Andric namespace clang { 33fe6060f1SDimitry Andric 34fe6060f1SDimitry Andric /// A custom action enabling the incremental processing functionality. 35fe6060f1SDimitry Andric /// 36fe6060f1SDimitry Andric /// The usual \p FrontendAction expects one call to ExecuteAction and once it 37fe6060f1SDimitry Andric /// sees a call to \p EndSourceFile it deletes some of the important objects 38fe6060f1SDimitry Andric /// such as \p Preprocessor and \p Sema assuming no further input will come. 39fe6060f1SDimitry Andric /// 40fe6060f1SDimitry Andric /// \p IncrementalAction ensures it keep its underlying action's objects alive 41fe6060f1SDimitry Andric /// as long as the \p IncrementalParser needs them. 42fe6060f1SDimitry Andric /// 43fe6060f1SDimitry Andric class IncrementalAction : public WrapperFrontendAction { 44fe6060f1SDimitry Andric private: 45fe6060f1SDimitry Andric bool IsTerminating = false; 46fe6060f1SDimitry Andric 47fe6060f1SDimitry Andric public: 48fe6060f1SDimitry Andric IncrementalAction(CompilerInstance &CI, llvm::LLVMContext &LLVMCtx, 49fe6060f1SDimitry Andric llvm::Error &Err) 50fe6060f1SDimitry Andric : WrapperFrontendAction([&]() { 51fe6060f1SDimitry Andric llvm::ErrorAsOutParameter EAO(&Err); 52fe6060f1SDimitry Andric std::unique_ptr<FrontendAction> Act; 53fe6060f1SDimitry Andric switch (CI.getFrontendOpts().ProgramAction) { 54fe6060f1SDimitry Andric default: 55fe6060f1SDimitry Andric Err = llvm::createStringError( 56fe6060f1SDimitry Andric std::errc::state_not_recoverable, 57fe6060f1SDimitry Andric "Driver initialization failed. " 58fe6060f1SDimitry Andric "Incremental mode for action %d is not supported", 59fe6060f1SDimitry Andric CI.getFrontendOpts().ProgramAction); 60fe6060f1SDimitry Andric return Act; 61fe6060f1SDimitry Andric case frontend::ASTDump: 62*bdd1243dSDimitry Andric [[fallthrough]]; 63fe6060f1SDimitry Andric case frontend::ASTPrint: 64*bdd1243dSDimitry Andric [[fallthrough]]; 65fe6060f1SDimitry Andric case frontend::ParseSyntaxOnly: 66fe6060f1SDimitry Andric Act = CreateFrontendAction(CI); 67fe6060f1SDimitry Andric break; 68349cc55cSDimitry Andric case frontend::PluginAction: 69*bdd1243dSDimitry Andric [[fallthrough]]; 70fe6060f1SDimitry Andric case frontend::EmitAssembly: 71*bdd1243dSDimitry Andric [[fallthrough]]; 72*bdd1243dSDimitry Andric case frontend::EmitBC: 73*bdd1243dSDimitry Andric [[fallthrough]]; 74fe6060f1SDimitry Andric case frontend::EmitObj: 75*bdd1243dSDimitry Andric [[fallthrough]]; 76*bdd1243dSDimitry Andric case frontend::PrintPreprocessedInput: 77*bdd1243dSDimitry Andric [[fallthrough]]; 78fe6060f1SDimitry Andric case frontend::EmitLLVMOnly: 79fe6060f1SDimitry Andric Act.reset(new EmitLLVMOnlyAction(&LLVMCtx)); 80fe6060f1SDimitry Andric break; 81fe6060f1SDimitry Andric } 82fe6060f1SDimitry Andric return Act; 83fe6060f1SDimitry Andric }()) {} 84fe6060f1SDimitry Andric FrontendAction *getWrapped() const { return WrappedAction.get(); } 85fe6060f1SDimitry Andric TranslationUnitKind getTranslationUnitKind() override { 86fe6060f1SDimitry Andric return TU_Incremental; 87fe6060f1SDimitry Andric } 88fe6060f1SDimitry Andric void ExecuteAction() override { 89fe6060f1SDimitry Andric CompilerInstance &CI = getCompilerInstance(); 90fe6060f1SDimitry Andric assert(CI.hasPreprocessor() && "No PP!"); 91fe6060f1SDimitry Andric 92fe6060f1SDimitry Andric // FIXME: Move the truncation aspect of this into Sema, we delayed this till 93fe6060f1SDimitry Andric // here so the source manager would be initialized. 94fe6060f1SDimitry Andric if (hasCodeCompletionSupport() && 95fe6060f1SDimitry Andric !CI.getFrontendOpts().CodeCompletionAt.FileName.empty()) 96fe6060f1SDimitry Andric CI.createCodeCompletionConsumer(); 97fe6060f1SDimitry Andric 98fe6060f1SDimitry Andric // Use a code completion consumer? 99fe6060f1SDimitry Andric CodeCompleteConsumer *CompletionConsumer = nullptr; 100fe6060f1SDimitry Andric if (CI.hasCodeCompletionConsumer()) 101fe6060f1SDimitry Andric CompletionConsumer = &CI.getCodeCompletionConsumer(); 102fe6060f1SDimitry Andric 103fe6060f1SDimitry Andric Preprocessor &PP = CI.getPreprocessor(); 104fe6060f1SDimitry Andric PP.EnterMainSourceFile(); 105fe6060f1SDimitry Andric 106fe6060f1SDimitry Andric if (!CI.hasSema()) 107fe6060f1SDimitry Andric CI.createSema(getTranslationUnitKind(), CompletionConsumer); 108fe6060f1SDimitry Andric } 109fe6060f1SDimitry Andric 110fe6060f1SDimitry Andric // Do not terminate after processing the input. This allows us to keep various 111fe6060f1SDimitry Andric // clang objects alive and to incrementally grow the current TU. 112fe6060f1SDimitry Andric void EndSourceFile() override { 113fe6060f1SDimitry Andric // The WrappedAction can be nullptr if we issued an error in the ctor. 114fe6060f1SDimitry Andric if (IsTerminating && getWrapped()) 115fe6060f1SDimitry Andric WrapperFrontendAction::EndSourceFile(); 116fe6060f1SDimitry Andric } 117fe6060f1SDimitry Andric 118fe6060f1SDimitry Andric void FinalizeAction() { 119fe6060f1SDimitry Andric assert(!IsTerminating && "Already finalized!"); 120fe6060f1SDimitry Andric IsTerminating = true; 121fe6060f1SDimitry Andric EndSourceFile(); 122fe6060f1SDimitry Andric } 123fe6060f1SDimitry Andric }; 124fe6060f1SDimitry Andric 125fe6060f1SDimitry Andric IncrementalParser::IncrementalParser(std::unique_ptr<CompilerInstance> Instance, 126fe6060f1SDimitry Andric llvm::LLVMContext &LLVMCtx, 127fe6060f1SDimitry Andric llvm::Error &Err) 128fe6060f1SDimitry Andric : CI(std::move(Instance)) { 129fe6060f1SDimitry Andric llvm::ErrorAsOutParameter EAO(&Err); 130fe6060f1SDimitry Andric Act = std::make_unique<IncrementalAction>(*CI, LLVMCtx, Err); 131fe6060f1SDimitry Andric if (Err) 132fe6060f1SDimitry Andric return; 133fe6060f1SDimitry Andric CI->ExecuteAction(*Act); 134fe6060f1SDimitry Andric Consumer = &CI->getASTConsumer(); 135fe6060f1SDimitry Andric P.reset( 136fe6060f1SDimitry Andric new Parser(CI->getPreprocessor(), CI->getSema(), /*SkipBodies=*/false)); 137fe6060f1SDimitry Andric P->Initialize(); 138fe6060f1SDimitry Andric } 139fe6060f1SDimitry Andric 14081ad6265SDimitry Andric IncrementalParser::~IncrementalParser() { 14181ad6265SDimitry Andric P.reset(); 14281ad6265SDimitry Andric Act->FinalizeAction(); 14381ad6265SDimitry Andric } 144fe6060f1SDimitry Andric 145fe6060f1SDimitry Andric llvm::Expected<PartialTranslationUnit &> 146fe6060f1SDimitry Andric IncrementalParser::ParseOrWrapTopLevelDecl() { 147fe6060f1SDimitry Andric // Recover resources if we crash before exiting this method. 148fe6060f1SDimitry Andric Sema &S = CI->getSema(); 149fe6060f1SDimitry Andric llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S); 150fe6060f1SDimitry Andric Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true); 151fe6060f1SDimitry Andric Sema::LocalEagerInstantiationScope LocalInstantiations(S); 152fe6060f1SDimitry Andric 153fe6060f1SDimitry Andric PTUs.emplace_back(PartialTranslationUnit()); 154fe6060f1SDimitry Andric PartialTranslationUnit &LastPTU = PTUs.back(); 155fe6060f1SDimitry Andric // Add a new PTU. 156fe6060f1SDimitry Andric ASTContext &C = S.getASTContext(); 157fe6060f1SDimitry Andric C.addTranslationUnitDecl(); 158fe6060f1SDimitry Andric LastPTU.TUPart = C.getTranslationUnitDecl(); 159fe6060f1SDimitry Andric 160fe6060f1SDimitry Andric // Skip previous eof due to last incremental input. 161fe6060f1SDimitry Andric if (P->getCurToken().is(tok::eof)) { 162fe6060f1SDimitry Andric P->ConsumeToken(); 163fe6060f1SDimitry Andric // FIXME: Clang does not call ExitScope on finalizing the regular TU, we 164fe6060f1SDimitry Andric // might want to do that around HandleEndOfTranslationUnit. 165fe6060f1SDimitry Andric P->ExitScope(); 166fe6060f1SDimitry Andric S.CurContext = nullptr; 167fe6060f1SDimitry Andric // Start a new PTU. 168fe6060f1SDimitry Andric P->EnterScope(Scope::DeclScope); 169fe6060f1SDimitry Andric S.ActOnTranslationUnitScope(P->getCurScope()); 170fe6060f1SDimitry Andric } 171fe6060f1SDimitry Andric 172fe6060f1SDimitry Andric Parser::DeclGroupPtrTy ADecl; 17381ad6265SDimitry Andric Sema::ModuleImportState ImportState; 17481ad6265SDimitry Andric for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF; 17581ad6265SDimitry Andric AtEOF = P->ParseTopLevelDecl(ADecl, ImportState)) { 176fe6060f1SDimitry Andric if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get())) 177fe6060f1SDimitry Andric return llvm::make_error<llvm::StringError>("Parsing failed. " 178fe6060f1SDimitry Andric "The consumer rejected a decl", 179fe6060f1SDimitry Andric std::error_code()); 180fe6060f1SDimitry Andric } 181fe6060f1SDimitry Andric 182fe6060f1SDimitry Andric DiagnosticsEngine &Diags = getCI()->getDiagnostics(); 183fe6060f1SDimitry Andric if (Diags.hasErrorOccurred()) { 18481ad6265SDimitry Andric PartialTranslationUnit MostRecentPTU = {C.getTranslationUnitDecl(), 18581ad6265SDimitry Andric nullptr}; 18681ad6265SDimitry Andric CleanUpPTU(MostRecentPTU); 187fe6060f1SDimitry Andric 18881ad6265SDimitry Andric Diags.Reset(/*soft=*/true); 18981ad6265SDimitry Andric Diags.getClient()->clear(); 190fe6060f1SDimitry Andric return llvm::make_error<llvm::StringError>("Parsing failed.", 191fe6060f1SDimitry Andric std::error_code()); 192fe6060f1SDimitry Andric } 193fe6060f1SDimitry Andric 194fe6060f1SDimitry Andric // Process any TopLevelDecls generated by #pragma weak. 195fe6060f1SDimitry Andric for (Decl *D : S.WeakTopLevelDecls()) { 196fe6060f1SDimitry Andric DeclGroupRef DGR(D); 197fe6060f1SDimitry Andric Consumer->HandleTopLevelDecl(DGR); 198fe6060f1SDimitry Andric } 199fe6060f1SDimitry Andric 200fe6060f1SDimitry Andric LocalInstantiations.perform(); 201fe6060f1SDimitry Andric GlobalInstantiations.perform(); 202fe6060f1SDimitry Andric 203fe6060f1SDimitry Andric Consumer->HandleTranslationUnit(C); 204fe6060f1SDimitry Andric 205fe6060f1SDimitry Andric return LastPTU; 206fe6060f1SDimitry Andric } 207fe6060f1SDimitry Andric 208fe6060f1SDimitry Andric static CodeGenerator *getCodeGen(FrontendAction *Act) { 209fe6060f1SDimitry Andric IncrementalAction *IncrAct = static_cast<IncrementalAction *>(Act); 210fe6060f1SDimitry Andric FrontendAction *WrappedAct = IncrAct->getWrapped(); 211fe6060f1SDimitry Andric if (!WrappedAct->hasIRSupport()) 212fe6060f1SDimitry Andric return nullptr; 213fe6060f1SDimitry Andric return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator(); 214fe6060f1SDimitry Andric } 215fe6060f1SDimitry Andric 216fe6060f1SDimitry Andric llvm::Expected<PartialTranslationUnit &> 217fe6060f1SDimitry Andric IncrementalParser::Parse(llvm::StringRef input) { 218fe6060f1SDimitry Andric Preprocessor &PP = CI->getPreprocessor(); 219fe6060f1SDimitry Andric assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?"); 220fe6060f1SDimitry Andric 221fe6060f1SDimitry Andric std::ostringstream SourceName; 222fe6060f1SDimitry Andric SourceName << "input_line_" << InputCount++; 223fe6060f1SDimitry Andric 224fe6060f1SDimitry Andric // Create an uninitialized memory buffer, copy code in and append "\n" 225fe6060f1SDimitry Andric size_t InputSize = input.size(); // don't include trailing 0 226fe6060f1SDimitry Andric // MemBuffer size should *not* include terminating zero 227fe6060f1SDimitry Andric std::unique_ptr<llvm::MemoryBuffer> MB( 228fe6060f1SDimitry Andric llvm::WritableMemoryBuffer::getNewUninitMemBuffer(InputSize + 1, 229fe6060f1SDimitry Andric SourceName.str())); 230fe6060f1SDimitry Andric char *MBStart = const_cast<char *>(MB->getBufferStart()); 231fe6060f1SDimitry Andric memcpy(MBStart, input.data(), InputSize); 232fe6060f1SDimitry Andric MBStart[InputSize] = '\n'; 233fe6060f1SDimitry Andric 234fe6060f1SDimitry Andric SourceManager &SM = CI->getSourceManager(); 235fe6060f1SDimitry Andric 236fe6060f1SDimitry Andric // FIXME: Create SourceLocation, which will allow clang to order the overload 237fe6060f1SDimitry Andric // candidates for example 238fe6060f1SDimitry Andric SourceLocation NewLoc = SM.getLocForStartOfFile(SM.getMainFileID()); 239fe6060f1SDimitry Andric 240fe6060f1SDimitry Andric // Create FileID for the current buffer. 241fe6060f1SDimitry Andric FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0, 242fe6060f1SDimitry Andric /*LoadedOffset=*/0, NewLoc); 243fe6060f1SDimitry Andric 244fe6060f1SDimitry Andric // NewLoc only used for diags. 24504eeddc0SDimitry Andric if (PP.EnterSourceFile(FID, /*DirLookup=*/nullptr, NewLoc)) 246fe6060f1SDimitry Andric return llvm::make_error<llvm::StringError>("Parsing failed. " 247fe6060f1SDimitry Andric "Cannot enter source file.", 248fe6060f1SDimitry Andric std::error_code()); 249fe6060f1SDimitry Andric 250fe6060f1SDimitry Andric auto PTU = ParseOrWrapTopLevelDecl(); 251fe6060f1SDimitry Andric if (!PTU) 252fe6060f1SDimitry Andric return PTU.takeError(); 253fe6060f1SDimitry Andric 254fe6060f1SDimitry Andric if (PP.getLangOpts().DelayedTemplateParsing) { 255fe6060f1SDimitry Andric // Microsoft-specific: 256fe6060f1SDimitry Andric // Late parsed templates can leave unswallowed "macro"-like tokens. 257fe6060f1SDimitry Andric // They will seriously confuse the Parser when entering the next 258fe6060f1SDimitry Andric // source file. So lex until we are EOF. 259fe6060f1SDimitry Andric Token Tok; 260fe6060f1SDimitry Andric do { 261fe6060f1SDimitry Andric PP.Lex(Tok); 262fe6060f1SDimitry Andric } while (Tok.isNot(tok::eof)); 263fe6060f1SDimitry Andric } 264fe6060f1SDimitry Andric 265fe6060f1SDimitry Andric Token AssertTok; 266fe6060f1SDimitry Andric PP.Lex(AssertTok); 267fe6060f1SDimitry Andric assert(AssertTok.is(tok::eof) && 268fe6060f1SDimitry Andric "Lexer must be EOF when starting incremental parse!"); 269fe6060f1SDimitry Andric 270fe6060f1SDimitry Andric if (CodeGenerator *CG = getCodeGen(Act.get())) { 271fe6060f1SDimitry Andric std::unique_ptr<llvm::Module> M(CG->ReleaseModule()); 272fe6060f1SDimitry Andric CG->StartModule("incr_module_" + std::to_string(PTUs.size()), 273fe6060f1SDimitry Andric M->getContext()); 274fe6060f1SDimitry Andric 275fe6060f1SDimitry Andric PTU->TheModule = std::move(M); 276fe6060f1SDimitry Andric } 277fe6060f1SDimitry Andric 278fe6060f1SDimitry Andric return PTU; 279fe6060f1SDimitry Andric } 280349cc55cSDimitry Andric 28181ad6265SDimitry Andric void IncrementalParser::CleanUpPTU(PartialTranslationUnit &PTU) { 28281ad6265SDimitry Andric TranslationUnitDecl *MostRecentTU = PTU.TUPart; 28381ad6265SDimitry Andric TranslationUnitDecl *FirstTU = MostRecentTU->getFirstDecl(); 28481ad6265SDimitry Andric if (StoredDeclsMap *Map = FirstTU->getPrimaryContext()->getLookupPtr()) { 28581ad6265SDimitry Andric for (auto I = Map->begin(); I != Map->end(); ++I) { 28681ad6265SDimitry Andric StoredDeclsList &List = I->second; 28781ad6265SDimitry Andric DeclContextLookupResult R = List.getLookupResult(); 28881ad6265SDimitry Andric for (NamedDecl *D : R) { 28981ad6265SDimitry Andric if (D->getTranslationUnitDecl() == MostRecentTU) { 29081ad6265SDimitry Andric List.remove(D); 29181ad6265SDimitry Andric } 29281ad6265SDimitry Andric } 29381ad6265SDimitry Andric if (List.isNull()) 29481ad6265SDimitry Andric Map->erase(I); 29581ad6265SDimitry Andric } 29681ad6265SDimitry Andric } 29781ad6265SDimitry Andric } 29881ad6265SDimitry Andric 299349cc55cSDimitry Andric llvm::StringRef IncrementalParser::GetMangledName(GlobalDecl GD) const { 300349cc55cSDimitry Andric CodeGenerator *CG = getCodeGen(Act.get()); 301349cc55cSDimitry Andric assert(CG); 302349cc55cSDimitry Andric return CG->GetMangledName(GD); 303349cc55cSDimitry Andric } 304349cc55cSDimitry Andric 305fe6060f1SDimitry Andric } // end namespace clang 306