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: 62fe6060f1SDimitry Andric LLVM_FALLTHROUGH; 63fe6060f1SDimitry Andric case frontend::ASTPrint: 64fe6060f1SDimitry Andric LLVM_FALLTHROUGH; 65fe6060f1SDimitry Andric case frontend::ParseSyntaxOnly: 66fe6060f1SDimitry Andric Act = CreateFrontendAction(CI); 67fe6060f1SDimitry Andric break; 68349cc55cSDimitry Andric case frontend::PluginAction: 69349cc55cSDimitry Andric LLVM_FALLTHROUGH; 70fe6060f1SDimitry Andric case frontend::EmitAssembly: 71fe6060f1SDimitry Andric LLVM_FALLTHROUGH; 72fe6060f1SDimitry Andric case frontend::EmitObj: 73fe6060f1SDimitry Andric LLVM_FALLTHROUGH; 74fe6060f1SDimitry Andric case frontend::EmitLLVMOnly: 75fe6060f1SDimitry Andric Act.reset(new EmitLLVMOnlyAction(&LLVMCtx)); 76fe6060f1SDimitry Andric break; 77fe6060f1SDimitry Andric } 78fe6060f1SDimitry Andric return Act; 79fe6060f1SDimitry Andric }()) {} 80fe6060f1SDimitry Andric FrontendAction *getWrapped() const { return WrappedAction.get(); } 81fe6060f1SDimitry Andric TranslationUnitKind getTranslationUnitKind() override { 82fe6060f1SDimitry Andric return TU_Incremental; 83fe6060f1SDimitry Andric } 84fe6060f1SDimitry Andric void ExecuteAction() override { 85fe6060f1SDimitry Andric CompilerInstance &CI = getCompilerInstance(); 86fe6060f1SDimitry Andric assert(CI.hasPreprocessor() && "No PP!"); 87fe6060f1SDimitry Andric 88fe6060f1SDimitry Andric // FIXME: Move the truncation aspect of this into Sema, we delayed this till 89fe6060f1SDimitry Andric // here so the source manager would be initialized. 90fe6060f1SDimitry Andric if (hasCodeCompletionSupport() && 91fe6060f1SDimitry Andric !CI.getFrontendOpts().CodeCompletionAt.FileName.empty()) 92fe6060f1SDimitry Andric CI.createCodeCompletionConsumer(); 93fe6060f1SDimitry Andric 94fe6060f1SDimitry Andric // Use a code completion consumer? 95fe6060f1SDimitry Andric CodeCompleteConsumer *CompletionConsumer = nullptr; 96fe6060f1SDimitry Andric if (CI.hasCodeCompletionConsumer()) 97fe6060f1SDimitry Andric CompletionConsumer = &CI.getCodeCompletionConsumer(); 98fe6060f1SDimitry Andric 99fe6060f1SDimitry Andric Preprocessor &PP = CI.getPreprocessor(); 100fe6060f1SDimitry Andric PP.enableIncrementalProcessing(); 101fe6060f1SDimitry Andric PP.EnterMainSourceFile(); 102fe6060f1SDimitry Andric 103fe6060f1SDimitry Andric if (!CI.hasSema()) 104fe6060f1SDimitry Andric CI.createSema(getTranslationUnitKind(), CompletionConsumer); 105fe6060f1SDimitry Andric } 106fe6060f1SDimitry Andric 107fe6060f1SDimitry Andric // Do not terminate after processing the input. This allows us to keep various 108fe6060f1SDimitry Andric // clang objects alive and to incrementally grow the current TU. 109fe6060f1SDimitry Andric void EndSourceFile() override { 110fe6060f1SDimitry Andric // The WrappedAction can be nullptr if we issued an error in the ctor. 111fe6060f1SDimitry Andric if (IsTerminating && getWrapped()) 112fe6060f1SDimitry Andric WrapperFrontendAction::EndSourceFile(); 113fe6060f1SDimitry Andric } 114fe6060f1SDimitry Andric 115fe6060f1SDimitry Andric void FinalizeAction() { 116fe6060f1SDimitry Andric assert(!IsTerminating && "Already finalized!"); 117fe6060f1SDimitry Andric IsTerminating = true; 118fe6060f1SDimitry Andric EndSourceFile(); 119fe6060f1SDimitry Andric } 120fe6060f1SDimitry Andric }; 121fe6060f1SDimitry Andric 122fe6060f1SDimitry Andric IncrementalParser::IncrementalParser(std::unique_ptr<CompilerInstance> Instance, 123fe6060f1SDimitry Andric llvm::LLVMContext &LLVMCtx, 124fe6060f1SDimitry Andric llvm::Error &Err) 125fe6060f1SDimitry Andric : CI(std::move(Instance)) { 126fe6060f1SDimitry Andric llvm::ErrorAsOutParameter EAO(&Err); 127fe6060f1SDimitry Andric Act = std::make_unique<IncrementalAction>(*CI, LLVMCtx, Err); 128fe6060f1SDimitry Andric if (Err) 129fe6060f1SDimitry Andric return; 130fe6060f1SDimitry Andric CI->ExecuteAction(*Act); 131fe6060f1SDimitry Andric Consumer = &CI->getASTConsumer(); 132fe6060f1SDimitry Andric P.reset( 133fe6060f1SDimitry Andric new Parser(CI->getPreprocessor(), CI->getSema(), /*SkipBodies=*/false)); 134fe6060f1SDimitry Andric P->Initialize(); 135fe6060f1SDimitry Andric } 136fe6060f1SDimitry Andric 137*81ad6265SDimitry Andric IncrementalParser::~IncrementalParser() { 138*81ad6265SDimitry Andric P.reset(); 139*81ad6265SDimitry Andric Act->FinalizeAction(); 140*81ad6265SDimitry Andric } 141fe6060f1SDimitry Andric 142fe6060f1SDimitry Andric llvm::Expected<PartialTranslationUnit &> 143fe6060f1SDimitry Andric IncrementalParser::ParseOrWrapTopLevelDecl() { 144fe6060f1SDimitry Andric // Recover resources if we crash before exiting this method. 145fe6060f1SDimitry Andric Sema &S = CI->getSema(); 146fe6060f1SDimitry Andric llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S); 147fe6060f1SDimitry Andric Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true); 148fe6060f1SDimitry Andric Sema::LocalEagerInstantiationScope LocalInstantiations(S); 149fe6060f1SDimitry Andric 150fe6060f1SDimitry Andric PTUs.emplace_back(PartialTranslationUnit()); 151fe6060f1SDimitry Andric PartialTranslationUnit &LastPTU = PTUs.back(); 152fe6060f1SDimitry Andric // Add a new PTU. 153fe6060f1SDimitry Andric ASTContext &C = S.getASTContext(); 154fe6060f1SDimitry Andric C.addTranslationUnitDecl(); 155fe6060f1SDimitry Andric LastPTU.TUPart = C.getTranslationUnitDecl(); 156fe6060f1SDimitry Andric 157fe6060f1SDimitry Andric // Skip previous eof due to last incremental input. 158fe6060f1SDimitry Andric if (P->getCurToken().is(tok::eof)) { 159fe6060f1SDimitry Andric P->ConsumeToken(); 160fe6060f1SDimitry Andric // FIXME: Clang does not call ExitScope on finalizing the regular TU, we 161fe6060f1SDimitry Andric // might want to do that around HandleEndOfTranslationUnit. 162fe6060f1SDimitry Andric P->ExitScope(); 163fe6060f1SDimitry Andric S.CurContext = nullptr; 164fe6060f1SDimitry Andric // Start a new PTU. 165fe6060f1SDimitry Andric P->EnterScope(Scope::DeclScope); 166fe6060f1SDimitry Andric S.ActOnTranslationUnitScope(P->getCurScope()); 167fe6060f1SDimitry Andric } 168fe6060f1SDimitry Andric 169fe6060f1SDimitry Andric Parser::DeclGroupPtrTy ADecl; 170*81ad6265SDimitry Andric Sema::ModuleImportState ImportState; 171*81ad6265SDimitry Andric for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF; 172*81ad6265SDimitry Andric AtEOF = P->ParseTopLevelDecl(ADecl, ImportState)) { 173fe6060f1SDimitry Andric // If we got a null return and something *was* parsed, ignore it. This 174fe6060f1SDimitry Andric // is due to a top-level semicolon, an action override, or a parse error 175fe6060f1SDimitry Andric // skipping something. 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()) { 184*81ad6265SDimitry Andric PartialTranslationUnit MostRecentPTU = {C.getTranslationUnitDecl(), 185*81ad6265SDimitry Andric nullptr}; 186*81ad6265SDimitry Andric CleanUpPTU(MostRecentPTU); 187fe6060f1SDimitry Andric 188*81ad6265SDimitry Andric Diags.Reset(/*soft=*/true); 189*81ad6265SDimitry 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 281*81ad6265SDimitry Andric void IncrementalParser::CleanUpPTU(PartialTranslationUnit &PTU) { 282*81ad6265SDimitry Andric TranslationUnitDecl *MostRecentTU = PTU.TUPart; 283*81ad6265SDimitry Andric TranslationUnitDecl *FirstTU = MostRecentTU->getFirstDecl(); 284*81ad6265SDimitry Andric if (StoredDeclsMap *Map = FirstTU->getPrimaryContext()->getLookupPtr()) { 285*81ad6265SDimitry Andric for (auto I = Map->begin(); I != Map->end(); ++I) { 286*81ad6265SDimitry Andric StoredDeclsList &List = I->second; 287*81ad6265SDimitry Andric DeclContextLookupResult R = List.getLookupResult(); 288*81ad6265SDimitry Andric for (NamedDecl *D : R) { 289*81ad6265SDimitry Andric if (D->getTranslationUnitDecl() == MostRecentTU) { 290*81ad6265SDimitry Andric List.remove(D); 291*81ad6265SDimitry Andric } 292*81ad6265SDimitry Andric } 293*81ad6265SDimitry Andric if (List.isNull()) 294*81ad6265SDimitry Andric Map->erase(I); 295*81ad6265SDimitry Andric } 296*81ad6265SDimitry Andric } 297*81ad6265SDimitry Andric } 298*81ad6265SDimitry 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