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