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 137fe6060f1SDimitry Andric IncrementalParser::~IncrementalParser() { Act->FinalizeAction(); } 138fe6060f1SDimitry Andric 139fe6060f1SDimitry Andric llvm::Expected<PartialTranslationUnit &> 140fe6060f1SDimitry Andric IncrementalParser::ParseOrWrapTopLevelDecl() { 141fe6060f1SDimitry Andric // Recover resources if we crash before exiting this method. 142fe6060f1SDimitry Andric Sema &S = CI->getSema(); 143fe6060f1SDimitry Andric llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S); 144fe6060f1SDimitry Andric Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true); 145fe6060f1SDimitry Andric Sema::LocalEagerInstantiationScope LocalInstantiations(S); 146fe6060f1SDimitry Andric 147fe6060f1SDimitry Andric PTUs.emplace_back(PartialTranslationUnit()); 148fe6060f1SDimitry Andric PartialTranslationUnit &LastPTU = PTUs.back(); 149fe6060f1SDimitry Andric // Add a new PTU. 150fe6060f1SDimitry Andric ASTContext &C = S.getASTContext(); 151fe6060f1SDimitry Andric C.addTranslationUnitDecl(); 152fe6060f1SDimitry Andric LastPTU.TUPart = C.getTranslationUnitDecl(); 153fe6060f1SDimitry Andric 154fe6060f1SDimitry Andric // Skip previous eof due to last incremental input. 155fe6060f1SDimitry Andric if (P->getCurToken().is(tok::eof)) { 156fe6060f1SDimitry Andric P->ConsumeToken(); 157fe6060f1SDimitry Andric // FIXME: Clang does not call ExitScope on finalizing the regular TU, we 158fe6060f1SDimitry Andric // might want to do that around HandleEndOfTranslationUnit. 159fe6060f1SDimitry Andric P->ExitScope(); 160fe6060f1SDimitry Andric S.CurContext = nullptr; 161fe6060f1SDimitry Andric // Start a new PTU. 162fe6060f1SDimitry Andric P->EnterScope(Scope::DeclScope); 163fe6060f1SDimitry Andric S.ActOnTranslationUnitScope(P->getCurScope()); 164fe6060f1SDimitry Andric } 165fe6060f1SDimitry Andric 166fe6060f1SDimitry Andric Parser::DeclGroupPtrTy ADecl; 167fe6060f1SDimitry Andric for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl); !AtEOF; 168fe6060f1SDimitry Andric AtEOF = P->ParseTopLevelDecl(ADecl)) { 169fe6060f1SDimitry Andric // If we got a null return and something *was* parsed, ignore it. This 170fe6060f1SDimitry Andric // is due to a top-level semicolon, an action override, or a parse error 171fe6060f1SDimitry Andric // skipping something. 172fe6060f1SDimitry Andric if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get())) 173fe6060f1SDimitry Andric return llvm::make_error<llvm::StringError>("Parsing failed. " 174fe6060f1SDimitry Andric "The consumer rejected a decl", 175fe6060f1SDimitry Andric std::error_code()); 176fe6060f1SDimitry Andric } 177fe6060f1SDimitry Andric 178fe6060f1SDimitry Andric DiagnosticsEngine &Diags = getCI()->getDiagnostics(); 179fe6060f1SDimitry Andric if (Diags.hasErrorOccurred()) { 180fe6060f1SDimitry Andric TranslationUnitDecl *MostRecentTU = C.getTranslationUnitDecl(); 181fe6060f1SDimitry Andric TranslationUnitDecl *PreviousTU = MostRecentTU->getPreviousDecl(); 182fe6060f1SDimitry Andric assert(PreviousTU && "Must have a TU from the ASTContext initialization!"); 183fe6060f1SDimitry Andric TranslationUnitDecl *FirstTU = MostRecentTU->getFirstDecl(); 184fe6060f1SDimitry Andric assert(FirstTU); 185fe6060f1SDimitry Andric FirstTU->RedeclLink.setLatest(PreviousTU); 186fe6060f1SDimitry Andric C.TUDecl = PreviousTU; 187fe6060f1SDimitry Andric S.TUScope->setEntity(PreviousTU); 188fe6060f1SDimitry Andric 189fe6060f1SDimitry Andric // Clean up the lookup table 190fe6060f1SDimitry Andric if (StoredDeclsMap *Map = PreviousTU->getLookupPtr()) { 191fe6060f1SDimitry Andric for (auto I = Map->begin(); I != Map->end(); ++I) { 192fe6060f1SDimitry Andric StoredDeclsList &List = I->second; 193fe6060f1SDimitry Andric DeclContextLookupResult R = List.getLookupResult(); 194fe6060f1SDimitry Andric for (NamedDecl *D : R) 195fe6060f1SDimitry Andric if (D->getTranslationUnitDecl() == MostRecentTU) 196fe6060f1SDimitry Andric List.remove(D); 197fe6060f1SDimitry Andric if (List.isNull()) 198fe6060f1SDimitry Andric Map->erase(I); 199fe6060f1SDimitry Andric } 200fe6060f1SDimitry Andric } 201fe6060f1SDimitry Andric 202fe6060f1SDimitry Andric // FIXME: Do not reset the pragma handlers. 203fe6060f1SDimitry Andric Diags.Reset(); 204fe6060f1SDimitry Andric return llvm::make_error<llvm::StringError>("Parsing failed.", 205fe6060f1SDimitry Andric std::error_code()); 206fe6060f1SDimitry Andric } 207fe6060f1SDimitry Andric 208fe6060f1SDimitry Andric // Process any TopLevelDecls generated by #pragma weak. 209fe6060f1SDimitry Andric for (Decl *D : S.WeakTopLevelDecls()) { 210fe6060f1SDimitry Andric DeclGroupRef DGR(D); 211fe6060f1SDimitry Andric Consumer->HandleTopLevelDecl(DGR); 212fe6060f1SDimitry Andric } 213fe6060f1SDimitry Andric 214fe6060f1SDimitry Andric LocalInstantiations.perform(); 215fe6060f1SDimitry Andric GlobalInstantiations.perform(); 216fe6060f1SDimitry Andric 217fe6060f1SDimitry Andric Consumer->HandleTranslationUnit(C); 218fe6060f1SDimitry Andric 219fe6060f1SDimitry Andric return LastPTU; 220fe6060f1SDimitry Andric } 221fe6060f1SDimitry Andric 222fe6060f1SDimitry Andric static CodeGenerator *getCodeGen(FrontendAction *Act) { 223fe6060f1SDimitry Andric IncrementalAction *IncrAct = static_cast<IncrementalAction *>(Act); 224fe6060f1SDimitry Andric FrontendAction *WrappedAct = IncrAct->getWrapped(); 225fe6060f1SDimitry Andric if (!WrappedAct->hasIRSupport()) 226fe6060f1SDimitry Andric return nullptr; 227fe6060f1SDimitry Andric return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator(); 228fe6060f1SDimitry Andric } 229fe6060f1SDimitry Andric 230fe6060f1SDimitry Andric llvm::Expected<PartialTranslationUnit &> 231fe6060f1SDimitry Andric IncrementalParser::Parse(llvm::StringRef input) { 232fe6060f1SDimitry Andric Preprocessor &PP = CI->getPreprocessor(); 233fe6060f1SDimitry Andric assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?"); 234fe6060f1SDimitry Andric 235fe6060f1SDimitry Andric std::ostringstream SourceName; 236fe6060f1SDimitry Andric SourceName << "input_line_" << InputCount++; 237fe6060f1SDimitry Andric 238fe6060f1SDimitry Andric // Create an uninitialized memory buffer, copy code in and append "\n" 239fe6060f1SDimitry Andric size_t InputSize = input.size(); // don't include trailing 0 240fe6060f1SDimitry Andric // MemBuffer size should *not* include terminating zero 241fe6060f1SDimitry Andric std::unique_ptr<llvm::MemoryBuffer> MB( 242fe6060f1SDimitry Andric llvm::WritableMemoryBuffer::getNewUninitMemBuffer(InputSize + 1, 243fe6060f1SDimitry Andric SourceName.str())); 244fe6060f1SDimitry Andric char *MBStart = const_cast<char *>(MB->getBufferStart()); 245fe6060f1SDimitry Andric memcpy(MBStart, input.data(), InputSize); 246fe6060f1SDimitry Andric MBStart[InputSize] = '\n'; 247fe6060f1SDimitry Andric 248fe6060f1SDimitry Andric SourceManager &SM = CI->getSourceManager(); 249fe6060f1SDimitry Andric 250fe6060f1SDimitry Andric // FIXME: Create SourceLocation, which will allow clang to order the overload 251fe6060f1SDimitry Andric // candidates for example 252fe6060f1SDimitry Andric SourceLocation NewLoc = SM.getLocForStartOfFile(SM.getMainFileID()); 253fe6060f1SDimitry Andric 254fe6060f1SDimitry Andric // Create FileID for the current buffer. 255fe6060f1SDimitry Andric FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0, 256fe6060f1SDimitry Andric /*LoadedOffset=*/0, NewLoc); 257fe6060f1SDimitry Andric 258fe6060f1SDimitry Andric // NewLoc only used for diags. 259*04eeddc0SDimitry Andric if (PP.EnterSourceFile(FID, /*DirLookup=*/nullptr, NewLoc)) 260fe6060f1SDimitry Andric return llvm::make_error<llvm::StringError>("Parsing failed. " 261fe6060f1SDimitry Andric "Cannot enter source file.", 262fe6060f1SDimitry Andric std::error_code()); 263fe6060f1SDimitry Andric 264fe6060f1SDimitry Andric auto PTU = ParseOrWrapTopLevelDecl(); 265fe6060f1SDimitry Andric if (!PTU) 266fe6060f1SDimitry Andric return PTU.takeError(); 267fe6060f1SDimitry Andric 268fe6060f1SDimitry Andric if (PP.getLangOpts().DelayedTemplateParsing) { 269fe6060f1SDimitry Andric // Microsoft-specific: 270fe6060f1SDimitry Andric // Late parsed templates can leave unswallowed "macro"-like tokens. 271fe6060f1SDimitry Andric // They will seriously confuse the Parser when entering the next 272fe6060f1SDimitry Andric // source file. So lex until we are EOF. 273fe6060f1SDimitry Andric Token Tok; 274fe6060f1SDimitry Andric do { 275fe6060f1SDimitry Andric PP.Lex(Tok); 276fe6060f1SDimitry Andric } while (Tok.isNot(tok::eof)); 277fe6060f1SDimitry Andric } 278fe6060f1SDimitry Andric 279fe6060f1SDimitry Andric Token AssertTok; 280fe6060f1SDimitry Andric PP.Lex(AssertTok); 281fe6060f1SDimitry Andric assert(AssertTok.is(tok::eof) && 282fe6060f1SDimitry Andric "Lexer must be EOF when starting incremental parse!"); 283fe6060f1SDimitry Andric 284fe6060f1SDimitry Andric if (CodeGenerator *CG = getCodeGen(Act.get())) { 285fe6060f1SDimitry Andric std::unique_ptr<llvm::Module> M(CG->ReleaseModule()); 286fe6060f1SDimitry Andric CG->StartModule("incr_module_" + std::to_string(PTUs.size()), 287fe6060f1SDimitry Andric M->getContext()); 288fe6060f1SDimitry Andric 289fe6060f1SDimitry Andric PTU->TheModule = std::move(M); 290fe6060f1SDimitry Andric } 291fe6060f1SDimitry Andric 292fe6060f1SDimitry Andric return PTU; 293fe6060f1SDimitry Andric } 294349cc55cSDimitry Andric 295349cc55cSDimitry Andric llvm::StringRef IncrementalParser::GetMangledName(GlobalDecl GD) const { 296349cc55cSDimitry Andric CodeGenerator *CG = getCodeGen(Act.get()); 297349cc55cSDimitry Andric assert(CG); 298349cc55cSDimitry Andric return CG->GetMangledName(GD); 299349cc55cSDimitry Andric } 300349cc55cSDimitry Andric 301fe6060f1SDimitry Andric } // end namespace clang 302