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