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 CodeGenerator *IncrementalParser::getCodeGen() const {
198   FrontendAction *WrappedAct = Act->getWrapped();
199   if (!WrappedAct->hasIRSupport())
200     return nullptr;
201   return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator();
202 }
203 
204 IncrementalParser::IncrementalParser() {}
205 
206 IncrementalParser::IncrementalParser(Interpreter &Interp,
207                                      std::unique_ptr<CompilerInstance> Instance,
208                                      llvm::LLVMContext &LLVMCtx,
209                                      llvm::Error &Err)
210     : CI(std::move(Instance)) {
211   llvm::ErrorAsOutParameter EAO(&Err);
212   Act = std::make_unique<IncrementalAction>(*CI, LLVMCtx, Err);
213   if (Err)
214     return;
215   CI->ExecuteAction(*Act);
216   std::unique_ptr<ASTConsumer> IncrConsumer =
217       std::make_unique<IncrementalASTConsumer>(Interp, CI->takeASTConsumer());
218   CI->setASTConsumer(std::move(IncrConsumer));
219   Consumer = &CI->getASTConsumer();
220   P.reset(
221       new Parser(CI->getPreprocessor(), CI->getSema(), /*SkipBodies=*/false));
222   P->Initialize();
223 
224   // An initial PTU is needed as CUDA includes some headers automatically
225   auto PTU = ParseOrWrapTopLevelDecl();
226   if (auto E = PTU.takeError()) {
227     consumeError(std::move(E)); // FIXME
228     return;                     // PTU.takeError();
229   }
230 
231   if (CodeGenerator *CG = getCodeGen()) {
232     std::unique_ptr<llvm::Module> M(CG->ReleaseModule());
233     CG->StartModule("incr_module_" + std::to_string(PTUs.size()),
234                     M->getContext());
235     PTU->TheModule = std::move(M);
236     assert(PTU->TheModule && "Failed to create initial PTU");
237   }
238 }
239 
240 IncrementalParser::~IncrementalParser() {
241   P.reset();
242   Act->FinalizeAction();
243 }
244 
245 llvm::Expected<PartialTranslationUnit &>
246 IncrementalParser::ParseOrWrapTopLevelDecl() {
247   // Recover resources if we crash before exiting this method.
248   Sema &S = CI->getSema();
249   llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S);
250   Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true);
251   Sema::LocalEagerInstantiationScope LocalInstantiations(S);
252 
253   PTUs.emplace_back(PartialTranslationUnit());
254   PartialTranslationUnit &LastPTU = PTUs.back();
255   // Add a new PTU.
256   ASTContext &C = S.getASTContext();
257   C.addTranslationUnitDecl();
258   LastPTU.TUPart = C.getTranslationUnitDecl();
259 
260   // Skip previous eof due to last incremental input.
261   if (P->getCurToken().is(tok::annot_repl_input_end)) {
262     P->ConsumeAnyToken();
263     // FIXME: Clang does not call ExitScope on finalizing the regular TU, we
264     // might want to do that around HandleEndOfTranslationUnit.
265     P->ExitScope();
266     S.CurContext = nullptr;
267     // Start a new PTU.
268     P->EnterScope(Scope::DeclScope);
269     S.ActOnTranslationUnitScope(P->getCurScope());
270   }
271 
272   Parser::DeclGroupPtrTy ADecl;
273   Sema::ModuleImportState ImportState;
274   for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF;
275        AtEOF = P->ParseTopLevelDecl(ADecl, ImportState)) {
276     if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
277       return llvm::make_error<llvm::StringError>("Parsing failed. "
278                                                  "The consumer rejected a decl",
279                                                  std::error_code());
280   }
281 
282   DiagnosticsEngine &Diags = getCI()->getDiagnostics();
283   if (Diags.hasErrorOccurred()) {
284     PartialTranslationUnit MostRecentPTU = {C.getTranslationUnitDecl(),
285                                             nullptr};
286     CleanUpPTU(MostRecentPTU);
287 
288     Diags.Reset(/*soft=*/true);
289     Diags.getClient()->clear();
290     return llvm::make_error<llvm::StringError>("Parsing failed.",
291                                                std::error_code());
292   }
293 
294   // Process any TopLevelDecls generated by #pragma weak.
295   for (Decl *D : S.WeakTopLevelDecls()) {
296     DeclGroupRef DGR(D);
297     Consumer->HandleTopLevelDecl(DGR);
298   }
299 
300   LocalInstantiations.perform();
301   GlobalInstantiations.perform();
302 
303   Consumer->HandleTranslationUnit(C);
304 
305   return LastPTU;
306 }
307 
308 llvm::Expected<PartialTranslationUnit &>
309 IncrementalParser::Parse(llvm::StringRef input) {
310   Preprocessor &PP = CI->getPreprocessor();
311   assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?");
312 
313   std::ostringstream SourceName;
314   SourceName << "input_line_" << InputCount++;
315 
316   // Create an uninitialized memory buffer, copy code in and append "\n"
317   size_t InputSize = input.size(); // don't include trailing 0
318   // MemBuffer size should *not* include terminating zero
319   std::unique_ptr<llvm::MemoryBuffer> MB(
320       llvm::WritableMemoryBuffer::getNewUninitMemBuffer(InputSize + 1,
321                                                         SourceName.str()));
322   char *MBStart = const_cast<char *>(MB->getBufferStart());
323   memcpy(MBStart, input.data(), InputSize);
324   MBStart[InputSize] = '\n';
325 
326   SourceManager &SM = CI->getSourceManager();
327 
328   // FIXME: Create SourceLocation, which will allow clang to order the overload
329   // candidates for example
330   SourceLocation NewLoc = SM.getLocForStartOfFile(SM.getMainFileID());
331 
332   // Create FileID for the current buffer.
333   FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0,
334                                /*LoadedOffset=*/0, NewLoc);
335 
336   // NewLoc only used for diags.
337   if (PP.EnterSourceFile(FID, /*DirLookup=*/nullptr, NewLoc))
338     return llvm::make_error<llvm::StringError>("Parsing failed. "
339                                                "Cannot enter source file.",
340                                                std::error_code());
341 
342   auto PTU = ParseOrWrapTopLevelDecl();
343   if (!PTU)
344     return PTU.takeError();
345 
346   if (PP.getLangOpts().DelayedTemplateParsing) {
347     // Microsoft-specific:
348     // Late parsed templates can leave unswallowed "macro"-like tokens.
349     // They will seriously confuse the Parser when entering the next
350     // source file. So lex until we are EOF.
351     Token Tok;
352     do {
353       PP.Lex(Tok);
354     } while (Tok.isNot(tok::annot_repl_input_end));
355   } else {
356     Token AssertTok;
357     PP.Lex(AssertTok);
358     assert(AssertTok.is(tok::annot_repl_input_end) &&
359            "Lexer must be EOF when starting incremental parse!");
360   }
361 
362   if (std::unique_ptr<llvm::Module> M = GenModule())
363     PTU->TheModule = std::move(M);
364 
365   return PTU;
366 }
367 
368 std::unique_ptr<llvm::Module> IncrementalParser::GenModule() {
369   static unsigned ID = 0;
370   if (CodeGenerator *CG = getCodeGen()) {
371     std::unique_ptr<llvm::Module> M(CG->ReleaseModule());
372     CG->StartModule("incr_module_" + std::to_string(ID++), M->getContext());
373     return M;
374   }
375   return nullptr;
376 }
377 
378 void IncrementalParser::CleanUpPTU(PartialTranslationUnit &PTU) {
379   TranslationUnitDecl *MostRecentTU = PTU.TUPart;
380   TranslationUnitDecl *FirstTU = MostRecentTU->getFirstDecl();
381   if (StoredDeclsMap *Map = FirstTU->getPrimaryContext()->getLookupPtr()) {
382     for (auto I = Map->begin(); I != Map->end(); ++I) {
383       StoredDeclsList &List = I->second;
384       DeclContextLookupResult R = List.getLookupResult();
385       for (NamedDecl *D : R) {
386         if (D->getTranslationUnitDecl() == MostRecentTU) {
387           List.remove(D);
388         }
389       }
390       if (List.isNull())
391         Map->erase(I);
392     }
393   }
394 }
395 
396 llvm::StringRef IncrementalParser::GetMangledName(GlobalDecl GD) const {
397   CodeGenerator *CG = getCodeGen();
398   assert(CG);
399   return CG->GetMangledName(GD);
400 }
401 
402 } // end namespace clang
403