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