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 #include "clang/AST/DeclContextInternals.h" 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/Interpreter/Interpreter.h" 22 #include "clang/Parse/Parser.h" 23 #include "clang/Sema/Sema.h" 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 class IncrementalASTConsumer final : public ASTConsumer { 34 Interpreter &Interp; 35 std::unique_ptr<ASTConsumer> Consumer; 36 37 public: 38 IncrementalASTConsumer(Interpreter &InterpRef, std::unique_ptr<ASTConsumer> C) 39 : Interp(InterpRef), Consumer(std::move(C)) {} 40 41 bool HandleTopLevelDecl(DeclGroupRef DGR) override final { 42 if (DGR.isNull()) 43 return true; 44 if (!Consumer) 45 return true; 46 47 for (Decl *D : DGR) 48 if (auto *TSD = llvm::dyn_cast<TopLevelStmtDecl>(D); 49 TSD && TSD->isSemiMissing()) 50 TSD->setStmt(Interp.SynthesizeExpr(cast<Expr>(TSD->getStmt()))); 51 52 return Consumer->HandleTopLevelDecl(DGR); 53 } 54 void HandleTranslationUnit(ASTContext &Ctx) override final { 55 Consumer->HandleTranslationUnit(Ctx); 56 } 57 void HandleInlineFunctionDefinition(FunctionDecl *D) override final { 58 Consumer->HandleInlineFunctionDefinition(D); 59 } 60 void HandleInterestingDecl(DeclGroupRef D) override final { 61 Consumer->HandleInterestingDecl(D); 62 } 63 void HandleTagDeclDefinition(TagDecl *D) override final { 64 Consumer->HandleTagDeclDefinition(D); 65 } 66 void HandleTagDeclRequiredDefinition(const TagDecl *D) override final { 67 Consumer->HandleTagDeclRequiredDefinition(D); 68 } 69 void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) override final { 70 Consumer->HandleCXXImplicitFunctionInstantiation(D); 71 } 72 void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override final { 73 Consumer->HandleTopLevelDeclInObjCContainer(D); 74 } 75 void HandleImplicitImportDecl(ImportDecl *D) override final { 76 Consumer->HandleImplicitImportDecl(D); 77 } 78 void CompleteTentativeDefinition(VarDecl *D) override final { 79 Consumer->CompleteTentativeDefinition(D); 80 } 81 void CompleteExternalDeclaration(VarDecl *D) override final { 82 Consumer->CompleteExternalDeclaration(D); 83 } 84 void AssignInheritanceModel(CXXRecordDecl *RD) override final { 85 Consumer->AssignInheritanceModel(RD); 86 } 87 void HandleCXXStaticMemberVarInstantiation(VarDecl *D) override final { 88 Consumer->HandleCXXStaticMemberVarInstantiation(D); 89 } 90 void HandleVTable(CXXRecordDecl *RD) override final { 91 Consumer->HandleVTable(RD); 92 } 93 ASTMutationListener *GetASTMutationListener() override final { 94 return Consumer->GetASTMutationListener(); 95 } 96 ASTDeserializationListener *GetASTDeserializationListener() override final { 97 return Consumer->GetASTDeserializationListener(); 98 } 99 void PrintStats() override final { Consumer->PrintStats(); } 100 bool shouldSkipFunctionBody(Decl *D) override final { 101 return Consumer->shouldSkipFunctionBody(D); 102 } 103 static bool classof(const clang::ASTConsumer *) { return true; } 104 }; 105 106 /// A custom action enabling the incremental processing functionality. 107 /// 108 /// The usual \p FrontendAction expects one call to ExecuteAction and once it 109 /// sees a call to \p EndSourceFile it deletes some of the important objects 110 /// such as \p Preprocessor and \p Sema assuming no further input will come. 111 /// 112 /// \p IncrementalAction ensures it keep its underlying action's objects alive 113 /// as long as the \p IncrementalParser needs them. 114 /// 115 class IncrementalAction : public WrapperFrontendAction { 116 private: 117 bool IsTerminating = false; 118 119 public: 120 IncrementalAction(CompilerInstance &CI, llvm::LLVMContext &LLVMCtx, 121 llvm::Error &Err) 122 : WrapperFrontendAction([&]() { 123 llvm::ErrorAsOutParameter EAO(&Err); 124 std::unique_ptr<FrontendAction> Act; 125 switch (CI.getFrontendOpts().ProgramAction) { 126 default: 127 Err = llvm::createStringError( 128 std::errc::state_not_recoverable, 129 "Driver initialization failed. " 130 "Incremental mode for action %d is not supported", 131 CI.getFrontendOpts().ProgramAction); 132 return Act; 133 case frontend::ASTDump: 134 [[fallthrough]]; 135 case frontend::ASTPrint: 136 [[fallthrough]]; 137 case frontend::ParseSyntaxOnly: 138 Act = CreateFrontendAction(CI); 139 break; 140 case frontend::PluginAction: 141 [[fallthrough]]; 142 case frontend::EmitAssembly: 143 [[fallthrough]]; 144 case frontend::EmitBC: 145 [[fallthrough]]; 146 case frontend::EmitObj: 147 [[fallthrough]]; 148 case frontend::PrintPreprocessedInput: 149 [[fallthrough]]; 150 case frontend::EmitLLVMOnly: 151 Act.reset(new EmitLLVMOnlyAction(&LLVMCtx)); 152 break; 153 } 154 return Act; 155 }()) {} 156 FrontendAction *getWrapped() const { return WrappedAction.get(); } 157 TranslationUnitKind getTranslationUnitKind() override { 158 return TU_Incremental; 159 } 160 void ExecuteAction() override { 161 CompilerInstance &CI = getCompilerInstance(); 162 assert(CI.hasPreprocessor() && "No PP!"); 163 164 // FIXME: Move the truncation aspect of this into Sema, we delayed this till 165 // here so the source manager would be initialized. 166 if (hasCodeCompletionSupport() && 167 !CI.getFrontendOpts().CodeCompletionAt.FileName.empty()) 168 CI.createCodeCompletionConsumer(); 169 170 // Use a code completion consumer? 171 CodeCompleteConsumer *CompletionConsumer = nullptr; 172 if (CI.hasCodeCompletionConsumer()) 173 CompletionConsumer = &CI.getCodeCompletionConsumer(); 174 175 Preprocessor &PP = CI.getPreprocessor(); 176 PP.EnterMainSourceFile(); 177 178 if (!CI.hasSema()) 179 CI.createSema(getTranslationUnitKind(), CompletionConsumer); 180 } 181 182 // Do not terminate after processing the input. This allows us to keep various 183 // clang objects alive and to incrementally grow the current TU. 184 void EndSourceFile() override { 185 // The WrappedAction can be nullptr if we issued an error in the ctor. 186 if (IsTerminating && getWrapped()) 187 WrapperFrontendAction::EndSourceFile(); 188 } 189 190 void FinalizeAction() { 191 assert(!IsTerminating && "Already finalized!"); 192 IsTerminating = true; 193 EndSourceFile(); 194 } 195 }; 196 197 IncrementalParser::IncrementalParser(Interpreter &Interp, 198 std::unique_ptr<CompilerInstance> Instance, 199 llvm::LLVMContext &LLVMCtx, 200 llvm::Error &Err) 201 : CI(std::move(Instance)) { 202 llvm::ErrorAsOutParameter EAO(&Err); 203 Act = std::make_unique<IncrementalAction>(*CI, LLVMCtx, Err); 204 if (Err) 205 return; 206 CI->ExecuteAction(*Act); 207 std::unique_ptr<ASTConsumer> IncrConsumer = 208 std::make_unique<IncrementalASTConsumer>(Interp, CI->takeASTConsumer()); 209 CI->setASTConsumer(std::move(IncrConsumer)); 210 Consumer = &CI->getASTConsumer(); 211 P.reset( 212 new Parser(CI->getPreprocessor(), CI->getSema(), /*SkipBodies=*/false)); 213 P->Initialize(); 214 } 215 216 IncrementalParser::~IncrementalParser() { 217 P.reset(); 218 Act->FinalizeAction(); 219 } 220 221 llvm::Expected<PartialTranslationUnit &> 222 IncrementalParser::ParseOrWrapTopLevelDecl() { 223 // Recover resources if we crash before exiting this method. 224 Sema &S = CI->getSema(); 225 llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S); 226 Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true); 227 Sema::LocalEagerInstantiationScope LocalInstantiations(S); 228 229 PTUs.emplace_back(PartialTranslationUnit()); 230 PartialTranslationUnit &LastPTU = PTUs.back(); 231 // Add a new PTU. 232 ASTContext &C = S.getASTContext(); 233 C.addTranslationUnitDecl(); 234 LastPTU.TUPart = C.getTranslationUnitDecl(); 235 236 // Skip previous eof due to last incremental input. 237 if (P->getCurToken().is(tok::annot_repl_input_end)) { 238 P->ConsumeAnyToken(); 239 // FIXME: Clang does not call ExitScope on finalizing the regular TU, we 240 // might want to do that around HandleEndOfTranslationUnit. 241 P->ExitScope(); 242 S.CurContext = nullptr; 243 // Start a new PTU. 244 P->EnterScope(Scope::DeclScope); 245 S.ActOnTranslationUnitScope(P->getCurScope()); 246 } 247 248 Parser::DeclGroupPtrTy ADecl; 249 Sema::ModuleImportState ImportState; 250 for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF; 251 AtEOF = P->ParseTopLevelDecl(ADecl, ImportState)) { 252 if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get())) 253 return llvm::make_error<llvm::StringError>("Parsing failed. " 254 "The consumer rejected a decl", 255 std::error_code()); 256 } 257 258 DiagnosticsEngine &Diags = getCI()->getDiagnostics(); 259 if (Diags.hasErrorOccurred()) { 260 PartialTranslationUnit MostRecentPTU = {C.getTranslationUnitDecl(), 261 nullptr}; 262 CleanUpPTU(MostRecentPTU); 263 264 Diags.Reset(/*soft=*/true); 265 Diags.getClient()->clear(); 266 return llvm::make_error<llvm::StringError>("Parsing failed.", 267 std::error_code()); 268 } 269 270 // Process any TopLevelDecls generated by #pragma weak. 271 for (Decl *D : S.WeakTopLevelDecls()) { 272 DeclGroupRef DGR(D); 273 Consumer->HandleTopLevelDecl(DGR); 274 } 275 276 LocalInstantiations.perform(); 277 GlobalInstantiations.perform(); 278 279 Consumer->HandleTranslationUnit(C); 280 281 return LastPTU; 282 } 283 284 static CodeGenerator *getCodeGen(FrontendAction *Act) { 285 IncrementalAction *IncrAct = static_cast<IncrementalAction *>(Act); 286 FrontendAction *WrappedAct = IncrAct->getWrapped(); 287 if (!WrappedAct->hasIRSupport()) 288 return nullptr; 289 return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator(); 290 } 291 292 llvm::Expected<PartialTranslationUnit &> 293 IncrementalParser::Parse(llvm::StringRef input) { 294 Preprocessor &PP = CI->getPreprocessor(); 295 assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?"); 296 297 std::ostringstream SourceName; 298 SourceName << "input_line_" << InputCount++; 299 300 // Create an uninitialized memory buffer, copy code in and append "\n" 301 size_t InputSize = input.size(); // don't include trailing 0 302 // MemBuffer size should *not* include terminating zero 303 std::unique_ptr<llvm::MemoryBuffer> MB( 304 llvm::WritableMemoryBuffer::getNewUninitMemBuffer(InputSize + 1, 305 SourceName.str())); 306 char *MBStart = const_cast<char *>(MB->getBufferStart()); 307 memcpy(MBStart, input.data(), InputSize); 308 MBStart[InputSize] = '\n'; 309 310 SourceManager &SM = CI->getSourceManager(); 311 312 // FIXME: Create SourceLocation, which will allow clang to order the overload 313 // candidates for example 314 SourceLocation NewLoc = SM.getLocForStartOfFile(SM.getMainFileID()); 315 316 // Create FileID for the current buffer. 317 FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0, 318 /*LoadedOffset=*/0, NewLoc); 319 320 // NewLoc only used for diags. 321 if (PP.EnterSourceFile(FID, /*DirLookup=*/nullptr, NewLoc)) 322 return llvm::make_error<llvm::StringError>("Parsing failed. " 323 "Cannot enter source file.", 324 std::error_code()); 325 326 auto PTU = ParseOrWrapTopLevelDecl(); 327 if (!PTU) 328 return PTU.takeError(); 329 330 if (PP.getLangOpts().DelayedTemplateParsing) { 331 // Microsoft-specific: 332 // Late parsed templates can leave unswallowed "macro"-like tokens. 333 // They will seriously confuse the Parser when entering the next 334 // source file. So lex until we are EOF. 335 Token Tok; 336 do { 337 PP.Lex(Tok); 338 } while (Tok.isNot(tok::annot_repl_input_end)); 339 } else { 340 Token AssertTok; 341 PP.Lex(AssertTok); 342 assert(AssertTok.is(tok::annot_repl_input_end) && 343 "Lexer must be EOF when starting incremental parse!"); 344 } 345 346 if (std::unique_ptr<llvm::Module> M = GenModule()) 347 PTU->TheModule = std::move(M); 348 349 return PTU; 350 } 351 352 std::unique_ptr<llvm::Module> IncrementalParser::GenModule() { 353 static unsigned ID = 0; 354 if (CodeGenerator *CG = getCodeGen(Act.get())) { 355 std::unique_ptr<llvm::Module> M(CG->ReleaseModule()); 356 CG->StartModule("incr_module_" + std::to_string(ID++), M->getContext()); 357 return M; 358 } 359 return nullptr; 360 } 361 362 void IncrementalParser::CleanUpPTU(PartialTranslationUnit &PTU) { 363 TranslationUnitDecl *MostRecentTU = PTU.TUPart; 364 TranslationUnitDecl *FirstTU = MostRecentTU->getFirstDecl(); 365 if (StoredDeclsMap *Map = FirstTU->getPrimaryContext()->getLookupPtr()) { 366 for (auto I = Map->begin(); I != Map->end(); ++I) { 367 StoredDeclsList &List = I->second; 368 DeclContextLookupResult R = List.getLookupResult(); 369 for (NamedDecl *D : R) { 370 if (D->getTranslationUnitDecl() == MostRecentTU) { 371 List.remove(D); 372 } 373 } 374 if (List.isNull()) 375 Map->erase(I); 376 } 377 } 378 } 379 380 llvm::StringRef IncrementalParser::GetMangledName(GlobalDecl GD) const { 381 CodeGenerator *CG = getCodeGen(Act.get()); 382 assert(CG); 383 return CG->GetMangledName(GD); 384 } 385 386 } // end namespace clang 387