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/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/Parse/Parser.h"
22 #include "clang/Sema/Sema.h"
23 
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 /// A custom action enabling the incremental processing functionality.
34 ///
35 /// The usual \p FrontendAction expects one call to ExecuteAction and once it
36 /// sees a call to \p EndSourceFile it deletes some of the important objects
37 /// such as \p Preprocessor and \p Sema assuming no further input will come.
38 ///
39 /// \p IncrementalAction ensures it keep its underlying action's objects alive
40 /// as long as the \p IncrementalParser needs them.
41 ///
42 class IncrementalAction : public WrapperFrontendAction {
43 private:
44   bool IsTerminating = false;
45 
46 public:
47   IncrementalAction(CompilerInstance &CI, llvm::LLVMContext &LLVMCtx,
48                     llvm::Error &Err)
49       : WrapperFrontendAction([&]() {
50           llvm::ErrorAsOutParameter EAO(&Err);
51           std::unique_ptr<FrontendAction> Act;
52           switch (CI.getFrontendOpts().ProgramAction) {
53           default:
54             Err = llvm::createStringError(
55                 std::errc::state_not_recoverable,
56                 "Driver initialization failed. "
57                 "Incremental mode for action is not supported");
58             return Act;
59           case frontend::ASTDump:
60             LLVM_FALLTHROUGH;
61           case frontend::ASTPrint:
62             LLVM_FALLTHROUGH;
63           case frontend::ParseSyntaxOnly:
64             Act = CreateFrontendAction(CI);
65             break;
66           case frontend::EmitObj:
67             LLVM_FALLTHROUGH;
68           case frontend::EmitLLVMOnly:
69             Act.reset(new EmitLLVMOnlyAction(&LLVMCtx));
70             break;
71           }
72           return Act;
73         }()) {}
74   FrontendAction *getWrapped() const { return WrappedAction.get(); }
75   void ExecuteAction() override {
76     CompilerInstance &CI = getCompilerInstance();
77     assert(CI.hasPreprocessor() && "No PP!");
78 
79     // FIXME: Move the truncation aspect of this into Sema, we delayed this till
80     // here so the source manager would be initialized.
81     if (hasCodeCompletionSupport() &&
82         !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
83       CI.createCodeCompletionConsumer();
84 
85     // Use a code completion consumer?
86     CodeCompleteConsumer *CompletionConsumer = nullptr;
87     if (CI.hasCodeCompletionConsumer())
88       CompletionConsumer = &CI.getCodeCompletionConsumer();
89 
90     Preprocessor &PP = CI.getPreprocessor();
91     PP.enableIncrementalProcessing();
92     PP.EnterMainSourceFile();
93 
94     if (!CI.hasSema())
95       CI.createSema(getTranslationUnitKind(), CompletionConsumer);
96   }
97 
98   // Do not terminate after processing the input. This allows us to keep various
99   // clang objects alive and to incrementally grow the current TU.
100   void EndSourceFile() override {
101     // The WrappedAction can be nullptr if we issued an error in the ctor.
102     if (IsTerminating && getWrapped())
103       WrapperFrontendAction::EndSourceFile();
104   }
105 
106   void FinalizeAction() {
107     assert(!IsTerminating && "Already finalized!");
108     IsTerminating = true;
109     EndSourceFile();
110   }
111 };
112 
113 IncrementalParser::IncrementalParser(std::unique_ptr<CompilerInstance> Instance,
114                                      llvm::LLVMContext &LLVMCtx,
115                                      llvm::Error &Err)
116     : CI(std::move(Instance)) {
117   llvm::ErrorAsOutParameter EAO(&Err);
118   Act = std::make_unique<IncrementalAction>(*CI, LLVMCtx, Err);
119   if (Err)
120     return;
121   CI->ExecuteAction(*Act);
122   Consumer = &CI->getASTConsumer();
123   P.reset(
124       new Parser(CI->getPreprocessor(), CI->getSema(), /*SkipBodies=*/false));
125   P->Initialize();
126 }
127 
128 IncrementalParser::~IncrementalParser() { Act->FinalizeAction(); }
129 
130 llvm::Expected<Transaction &> IncrementalParser::ParseOrWrapTopLevelDecl() {
131   DiagnosticsEngine &Diags = getCI()->getDiagnostics();
132 
133   if (Diags.hasErrorOccurred())
134     llvm::report_fatal_error("Previous input had errors, "
135                              "recovery not yet supported",
136                              /*GenCrashDiag=*/false);
137 
138   // Recover resources if we crash before exiting this method.
139   Sema &S = CI->getSema();
140   llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S);
141   Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true);
142   Sema::LocalEagerInstantiationScope LocalInstantiations(S);
143 
144   // Skip previous eof due to last incremental input.
145   if (P->getCurToken().is(tok::eof))
146     P->ConsumeToken();
147 
148   Transactions.emplace_back(Transaction());
149   Transaction &LastTransaction = Transactions.back();
150 
151   Parser::DeclGroupPtrTy ADecl;
152   for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl); !AtEOF;
153        AtEOF = P->ParseTopLevelDecl(ADecl)) {
154     // If we got a null return and something *was* parsed, ignore it.  This
155     // is due to a top-level semicolon, an action override, or a parse error
156     // skipping something.
157     if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
158       return llvm::make_error<llvm::StringError>("Parsing failed. "
159                                                  "The consumer rejected a decl",
160                                                  std::error_code());
161     LastTransaction.Decls.push_back(ADecl.get());
162   }
163 
164   // Process any TopLevelDecls generated by #pragma weak.
165   for (Decl *D : S.WeakTopLevelDecls()) {
166     DeclGroupRef DGR(D);
167     LastTransaction.Decls.push_back(DGR);
168     Consumer->HandleTopLevelDecl(DGR);
169   }
170 
171   LocalInstantiations.perform();
172   GlobalInstantiations.perform();
173 
174   Consumer->HandleTranslationUnit(S.getASTContext());
175 
176   if (Diags.hasErrorOccurred())
177     return llvm::make_error<llvm::StringError>("Parsing failed.",
178                                                std::error_code());
179 
180   return LastTransaction;
181 }
182 
183 static CodeGenerator *getCodeGen(FrontendAction *Act) {
184   IncrementalAction *IncrAct = static_cast<IncrementalAction *>(Act);
185   FrontendAction *WrappedAct = IncrAct->getWrapped();
186   if (!WrappedAct->hasIRSupport())
187     return nullptr;
188   return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator();
189 }
190 
191 llvm::Expected<Transaction &> IncrementalParser::Parse(llvm::StringRef input) {
192   Preprocessor &PP = CI->getPreprocessor();
193   assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?");
194 
195   std::ostringstream SourceName;
196   SourceName << "input_line_" << InputCount++;
197 
198   // Create an uninitialized memory buffer, copy code in and append "\n"
199   size_t InputSize = input.size(); // don't include trailing 0
200   // MemBuffer size should *not* include terminating zero
201   std::unique_ptr<llvm::MemoryBuffer> MB(
202       llvm::WritableMemoryBuffer::getNewUninitMemBuffer(InputSize + 1,
203                                                         SourceName.str()));
204   char *MBStart = const_cast<char *>(MB->getBufferStart());
205   memcpy(MBStart, input.data(), InputSize);
206   MBStart[InputSize] = '\n';
207 
208   SourceManager &SM = CI->getSourceManager();
209 
210   // FIXME: Create SourceLocation, which will allow clang to order the overload
211   // candidates for example
212   SourceLocation NewLoc = SM.getLocForStartOfFile(SM.getMainFileID());
213 
214   // Create FileID for the current buffer.
215   FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0,
216                                /*LoadedOffset=*/0, NewLoc);
217 
218   // NewLoc only used for diags.
219   if (PP.EnterSourceFile(FID, /*DirLookup=*/0, NewLoc))
220     return llvm::make_error<llvm::StringError>("Parsing failed. "
221                                                "Cannot enter source file.",
222                                                std::error_code());
223 
224   auto ErrOrTransaction = ParseOrWrapTopLevelDecl();
225   if (auto Err = ErrOrTransaction.takeError())
226     return std::move(Err);
227 
228   if (PP.getLangOpts().DelayedTemplateParsing) {
229     // Microsoft-specific:
230     // Late parsed templates can leave unswallowed "macro"-like tokens.
231     // They will seriously confuse the Parser when entering the next
232     // source file. So lex until we are EOF.
233     Token Tok;
234     do {
235       PP.Lex(Tok);
236     } while (Tok.isNot(tok::eof));
237   }
238 
239   Token AssertTok;
240   PP.Lex(AssertTok);
241   assert(AssertTok.is(tok::eof) &&
242          "Lexer must be EOF when starting incremental parse!");
243 
244   if (CodeGenerator *CG = getCodeGen(Act.get())) {
245     std::unique_ptr<llvm::Module> M(CG->ReleaseModule());
246     CG->StartModule("incr_module_" + std::to_string(Transactions.size()),
247                     M->getContext());
248 
249     ErrOrTransaction->TheModule = std::move(M);
250   }
251 
252   return ErrOrTransaction;
253 }
254 } // end namespace clang
255