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:
IncrementalAction(CompilerInstance & CI,llvm::LLVMContext & LLVMCtx,llvm::Error & Err)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 }()) {}
getWrapped() const80 FrontendAction *getWrapped() const { return WrappedAction.get(); }
getTranslationUnitKind()81 TranslationUnitKind getTranslationUnitKind() override {
82 return TU_Incremental;
83 }
ExecuteAction()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.
EndSourceFile()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
FinalizeAction()115 void FinalizeAction() {
116 assert(!IsTerminating && "Already finalized!");
117 IsTerminating = true;
118 EndSourceFile();
119 }
120 };
121
IncrementalParser(std::unique_ptr<CompilerInstance> Instance,llvm::LLVMContext & LLVMCtx,llvm::Error & Err)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
~IncrementalParser()137 IncrementalParser::~IncrementalParser() {
138 P.reset();
139 Act->FinalizeAction();
140 }
141
142 llvm::Expected<PartialTranslationUnit &>
ParseOrWrapTopLevelDecl()143 IncrementalParser::ParseOrWrapTopLevelDecl() {
144 // Recover resources if we crash before exiting this method.
145 Sema &S = CI->getSema();
146 llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S);
147 Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true);
148 Sema::LocalEagerInstantiationScope LocalInstantiations(S);
149
150 PTUs.emplace_back(PartialTranslationUnit());
151 PartialTranslationUnit &LastPTU = PTUs.back();
152 // Add a new PTU.
153 ASTContext &C = S.getASTContext();
154 C.addTranslationUnitDecl();
155 LastPTU.TUPart = C.getTranslationUnitDecl();
156
157 // Skip previous eof due to last incremental input.
158 if (P->getCurToken().is(tok::eof)) {
159 P->ConsumeToken();
160 // FIXME: Clang does not call ExitScope on finalizing the regular TU, we
161 // might want to do that around HandleEndOfTranslationUnit.
162 P->ExitScope();
163 S.CurContext = nullptr;
164 // Start a new PTU.
165 P->EnterScope(Scope::DeclScope);
166 S.ActOnTranslationUnitScope(P->getCurScope());
167 }
168
169 Parser::DeclGroupPtrTy ADecl;
170 Sema::ModuleImportState ImportState;
171 for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF;
172 AtEOF = P->ParseTopLevelDecl(ADecl, ImportState)) {
173 // If we got a null return and something *was* parsed, ignore it. This
174 // is due to a top-level semicolon, an action override, or a parse error
175 // skipping something.
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
getCodeGen(FrontendAction * Act)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 &>
Parse(llvm::StringRef input)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
CleanUpPTU(PartialTranslationUnit & PTU)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
GetMangledName(GlobalDecl GD) const299 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