xref: /openbsd-src/gnu/llvm/clang/lib/Interpreter/IncrementalParser.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1a9ac8606Spatrick //===--------- IncrementalParser.cpp - Incremental Compilation  -----------===//
2a9ac8606Spatrick //
3a9ac8606Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a9ac8606Spatrick // See https://llvm.org/LICENSE.txt for license information.
5a9ac8606Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a9ac8606Spatrick //
7a9ac8606Spatrick //===----------------------------------------------------------------------===//
8a9ac8606Spatrick //
9a9ac8606Spatrick // This file implements the class which performs incremental code compilation.
10a9ac8606Spatrick //
11a9ac8606Spatrick //===----------------------------------------------------------------------===//
12a9ac8606Spatrick 
13a9ac8606Spatrick #include "IncrementalParser.h"
14a9ac8606Spatrick 
15a9ac8606Spatrick #include "clang/AST/DeclContextInternals.h"
16a9ac8606Spatrick #include "clang/CodeGen/BackendUtil.h"
17a9ac8606Spatrick #include "clang/CodeGen/CodeGenAction.h"
18a9ac8606Spatrick #include "clang/CodeGen/ModuleBuilder.h"
19a9ac8606Spatrick #include "clang/Frontend/CompilerInstance.h"
20a9ac8606Spatrick #include "clang/Frontend/FrontendAction.h"
21a9ac8606Spatrick #include "clang/FrontendTool/Utils.h"
22a9ac8606Spatrick #include "clang/Parse/Parser.h"
23a9ac8606Spatrick #include "clang/Sema/Sema.h"
24a9ac8606Spatrick 
25a9ac8606Spatrick #include "llvm/Option/ArgList.h"
26a9ac8606Spatrick #include "llvm/Support/CrashRecoveryContext.h"
27a9ac8606Spatrick #include "llvm/Support/Error.h"
28a9ac8606Spatrick #include "llvm/Support/Timer.h"
29a9ac8606Spatrick 
30a9ac8606Spatrick #include <sstream>
31a9ac8606Spatrick 
32a9ac8606Spatrick namespace clang {
33a9ac8606Spatrick 
34a9ac8606Spatrick /// A custom action enabling the incremental processing functionality.
35a9ac8606Spatrick ///
36a9ac8606Spatrick /// The usual \p FrontendAction expects one call to ExecuteAction and once it
37a9ac8606Spatrick /// sees a call to \p EndSourceFile it deletes some of the important objects
38a9ac8606Spatrick /// such as \p Preprocessor and \p Sema assuming no further input will come.
39a9ac8606Spatrick ///
40a9ac8606Spatrick /// \p IncrementalAction ensures it keep its underlying action's objects alive
41a9ac8606Spatrick /// as long as the \p IncrementalParser needs them.
42a9ac8606Spatrick ///
43a9ac8606Spatrick class IncrementalAction : public WrapperFrontendAction {
44a9ac8606Spatrick private:
45a9ac8606Spatrick   bool IsTerminating = false;
46a9ac8606Spatrick 
47a9ac8606Spatrick public:
IncrementalAction(CompilerInstance & CI,llvm::LLVMContext & LLVMCtx,llvm::Error & Err)48a9ac8606Spatrick   IncrementalAction(CompilerInstance &CI, llvm::LLVMContext &LLVMCtx,
49a9ac8606Spatrick                     llvm::Error &Err)
50a9ac8606Spatrick       : WrapperFrontendAction([&]() {
51a9ac8606Spatrick           llvm::ErrorAsOutParameter EAO(&Err);
52a9ac8606Spatrick           std::unique_ptr<FrontendAction> Act;
53a9ac8606Spatrick           switch (CI.getFrontendOpts().ProgramAction) {
54a9ac8606Spatrick           default:
55a9ac8606Spatrick             Err = llvm::createStringError(
56a9ac8606Spatrick                 std::errc::state_not_recoverable,
57a9ac8606Spatrick                 "Driver initialization failed. "
58a9ac8606Spatrick                 "Incremental mode for action %d is not supported",
59a9ac8606Spatrick                 CI.getFrontendOpts().ProgramAction);
60a9ac8606Spatrick             return Act;
61a9ac8606Spatrick           case frontend::ASTDump:
62*12c85518Srobert             [[fallthrough]];
63a9ac8606Spatrick           case frontend::ASTPrint:
64*12c85518Srobert             [[fallthrough]];
65a9ac8606Spatrick           case frontend::ParseSyntaxOnly:
66a9ac8606Spatrick             Act = CreateFrontendAction(CI);
67a9ac8606Spatrick             break;
68*12c85518Srobert           case frontend::PluginAction:
69*12c85518Srobert             [[fallthrough]];
70a9ac8606Spatrick           case frontend::EmitAssembly:
71*12c85518Srobert             [[fallthrough]];
72*12c85518Srobert           case frontend::EmitBC:
73*12c85518Srobert             [[fallthrough]];
74a9ac8606Spatrick           case frontend::EmitObj:
75*12c85518Srobert             [[fallthrough]];
76*12c85518Srobert           case frontend::PrintPreprocessedInput:
77*12c85518Srobert             [[fallthrough]];
78a9ac8606Spatrick           case frontend::EmitLLVMOnly:
79a9ac8606Spatrick             Act.reset(new EmitLLVMOnlyAction(&LLVMCtx));
80a9ac8606Spatrick             break;
81a9ac8606Spatrick           }
82a9ac8606Spatrick           return Act;
83a9ac8606Spatrick         }()) {}
getWrapped() const84a9ac8606Spatrick   FrontendAction *getWrapped() const { return WrappedAction.get(); }
getTranslationUnitKind()85a9ac8606Spatrick   TranslationUnitKind getTranslationUnitKind() override {
86a9ac8606Spatrick     return TU_Incremental;
87a9ac8606Spatrick   }
ExecuteAction()88a9ac8606Spatrick   void ExecuteAction() override {
89a9ac8606Spatrick     CompilerInstance &CI = getCompilerInstance();
90a9ac8606Spatrick     assert(CI.hasPreprocessor() && "No PP!");
91a9ac8606Spatrick 
92a9ac8606Spatrick     // FIXME: Move the truncation aspect of this into Sema, we delayed this till
93a9ac8606Spatrick     // here so the source manager would be initialized.
94a9ac8606Spatrick     if (hasCodeCompletionSupport() &&
95a9ac8606Spatrick         !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
96a9ac8606Spatrick       CI.createCodeCompletionConsumer();
97a9ac8606Spatrick 
98a9ac8606Spatrick     // Use a code completion consumer?
99a9ac8606Spatrick     CodeCompleteConsumer *CompletionConsumer = nullptr;
100a9ac8606Spatrick     if (CI.hasCodeCompletionConsumer())
101a9ac8606Spatrick       CompletionConsumer = &CI.getCodeCompletionConsumer();
102a9ac8606Spatrick 
103a9ac8606Spatrick     Preprocessor &PP = CI.getPreprocessor();
104a9ac8606Spatrick     PP.EnterMainSourceFile();
105a9ac8606Spatrick 
106a9ac8606Spatrick     if (!CI.hasSema())
107a9ac8606Spatrick       CI.createSema(getTranslationUnitKind(), CompletionConsumer);
108a9ac8606Spatrick   }
109a9ac8606Spatrick 
110a9ac8606Spatrick   // Do not terminate after processing the input. This allows us to keep various
111a9ac8606Spatrick   // clang objects alive and to incrementally grow the current TU.
EndSourceFile()112a9ac8606Spatrick   void EndSourceFile() override {
113a9ac8606Spatrick     // The WrappedAction can be nullptr if we issued an error in the ctor.
114a9ac8606Spatrick     if (IsTerminating && getWrapped())
115a9ac8606Spatrick       WrapperFrontendAction::EndSourceFile();
116a9ac8606Spatrick   }
117a9ac8606Spatrick 
FinalizeAction()118a9ac8606Spatrick   void FinalizeAction() {
119a9ac8606Spatrick     assert(!IsTerminating && "Already finalized!");
120a9ac8606Spatrick     IsTerminating = true;
121a9ac8606Spatrick     EndSourceFile();
122a9ac8606Spatrick   }
123a9ac8606Spatrick };
124a9ac8606Spatrick 
IncrementalParser(std::unique_ptr<CompilerInstance> Instance,llvm::LLVMContext & LLVMCtx,llvm::Error & Err)125a9ac8606Spatrick IncrementalParser::IncrementalParser(std::unique_ptr<CompilerInstance> Instance,
126a9ac8606Spatrick                                      llvm::LLVMContext &LLVMCtx,
127a9ac8606Spatrick                                      llvm::Error &Err)
128a9ac8606Spatrick     : CI(std::move(Instance)) {
129a9ac8606Spatrick   llvm::ErrorAsOutParameter EAO(&Err);
130a9ac8606Spatrick   Act = std::make_unique<IncrementalAction>(*CI, LLVMCtx, Err);
131a9ac8606Spatrick   if (Err)
132a9ac8606Spatrick     return;
133a9ac8606Spatrick   CI->ExecuteAction(*Act);
134a9ac8606Spatrick   Consumer = &CI->getASTConsumer();
135a9ac8606Spatrick   P.reset(
136a9ac8606Spatrick       new Parser(CI->getPreprocessor(), CI->getSema(), /*SkipBodies=*/false));
137a9ac8606Spatrick   P->Initialize();
138a9ac8606Spatrick }
139a9ac8606Spatrick 
~IncrementalParser()140*12c85518Srobert IncrementalParser::~IncrementalParser() {
141*12c85518Srobert   P.reset();
142*12c85518Srobert   Act->FinalizeAction();
143*12c85518Srobert }
144a9ac8606Spatrick 
145a9ac8606Spatrick llvm::Expected<PartialTranslationUnit &>
ParseOrWrapTopLevelDecl()146a9ac8606Spatrick IncrementalParser::ParseOrWrapTopLevelDecl() {
147a9ac8606Spatrick   // Recover resources if we crash before exiting this method.
148a9ac8606Spatrick   Sema &S = CI->getSema();
149a9ac8606Spatrick   llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S);
150a9ac8606Spatrick   Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true);
151a9ac8606Spatrick   Sema::LocalEagerInstantiationScope LocalInstantiations(S);
152a9ac8606Spatrick 
153a9ac8606Spatrick   PTUs.emplace_back(PartialTranslationUnit());
154a9ac8606Spatrick   PartialTranslationUnit &LastPTU = PTUs.back();
155a9ac8606Spatrick   // Add a new PTU.
156a9ac8606Spatrick   ASTContext &C = S.getASTContext();
157a9ac8606Spatrick   C.addTranslationUnitDecl();
158a9ac8606Spatrick   LastPTU.TUPart = C.getTranslationUnitDecl();
159a9ac8606Spatrick 
160a9ac8606Spatrick   // Skip previous eof due to last incremental input.
161a9ac8606Spatrick   if (P->getCurToken().is(tok::eof)) {
162a9ac8606Spatrick     P->ConsumeToken();
163a9ac8606Spatrick     // FIXME: Clang does not call ExitScope on finalizing the regular TU, we
164a9ac8606Spatrick     // might want to do that around HandleEndOfTranslationUnit.
165a9ac8606Spatrick     P->ExitScope();
166a9ac8606Spatrick     S.CurContext = nullptr;
167a9ac8606Spatrick     // Start a new PTU.
168a9ac8606Spatrick     P->EnterScope(Scope::DeclScope);
169a9ac8606Spatrick     S.ActOnTranslationUnitScope(P->getCurScope());
170a9ac8606Spatrick   }
171a9ac8606Spatrick 
172a9ac8606Spatrick   Parser::DeclGroupPtrTy ADecl;
173*12c85518Srobert   Sema::ModuleImportState ImportState;
174*12c85518Srobert   for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF;
175*12c85518Srobert        AtEOF = P->ParseTopLevelDecl(ADecl, ImportState)) {
176a9ac8606Spatrick     if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
177a9ac8606Spatrick       return llvm::make_error<llvm::StringError>("Parsing failed. "
178a9ac8606Spatrick                                                  "The consumer rejected a decl",
179a9ac8606Spatrick                                                  std::error_code());
180a9ac8606Spatrick   }
181a9ac8606Spatrick 
182a9ac8606Spatrick   DiagnosticsEngine &Diags = getCI()->getDiagnostics();
183a9ac8606Spatrick   if (Diags.hasErrorOccurred()) {
184*12c85518Srobert     PartialTranslationUnit MostRecentPTU = {C.getTranslationUnitDecl(),
185*12c85518Srobert                                             nullptr};
186*12c85518Srobert     CleanUpPTU(MostRecentPTU);
187a9ac8606Spatrick 
188*12c85518Srobert     Diags.Reset(/*soft=*/true);
189*12c85518Srobert     Diags.getClient()->clear();
190a9ac8606Spatrick     return llvm::make_error<llvm::StringError>("Parsing failed.",
191a9ac8606Spatrick                                                std::error_code());
192a9ac8606Spatrick   }
193a9ac8606Spatrick 
194a9ac8606Spatrick   // Process any TopLevelDecls generated by #pragma weak.
195a9ac8606Spatrick   for (Decl *D : S.WeakTopLevelDecls()) {
196a9ac8606Spatrick     DeclGroupRef DGR(D);
197a9ac8606Spatrick     Consumer->HandleTopLevelDecl(DGR);
198a9ac8606Spatrick   }
199a9ac8606Spatrick 
200a9ac8606Spatrick   LocalInstantiations.perform();
201a9ac8606Spatrick   GlobalInstantiations.perform();
202a9ac8606Spatrick 
203a9ac8606Spatrick   Consumer->HandleTranslationUnit(C);
204a9ac8606Spatrick 
205a9ac8606Spatrick   return LastPTU;
206a9ac8606Spatrick }
207a9ac8606Spatrick 
getCodeGen(FrontendAction * Act)208a9ac8606Spatrick static CodeGenerator *getCodeGen(FrontendAction *Act) {
209a9ac8606Spatrick   IncrementalAction *IncrAct = static_cast<IncrementalAction *>(Act);
210a9ac8606Spatrick   FrontendAction *WrappedAct = IncrAct->getWrapped();
211a9ac8606Spatrick   if (!WrappedAct->hasIRSupport())
212a9ac8606Spatrick     return nullptr;
213a9ac8606Spatrick   return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator();
214a9ac8606Spatrick }
215a9ac8606Spatrick 
216a9ac8606Spatrick llvm::Expected<PartialTranslationUnit &>
Parse(llvm::StringRef input)217a9ac8606Spatrick IncrementalParser::Parse(llvm::StringRef input) {
218a9ac8606Spatrick   Preprocessor &PP = CI->getPreprocessor();
219a9ac8606Spatrick   assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?");
220a9ac8606Spatrick 
221a9ac8606Spatrick   std::ostringstream SourceName;
222a9ac8606Spatrick   SourceName << "input_line_" << InputCount++;
223a9ac8606Spatrick 
224a9ac8606Spatrick   // Create an uninitialized memory buffer, copy code in and append "\n"
225a9ac8606Spatrick   size_t InputSize = input.size(); // don't include trailing 0
226a9ac8606Spatrick   // MemBuffer size should *not* include terminating zero
227a9ac8606Spatrick   std::unique_ptr<llvm::MemoryBuffer> MB(
228a9ac8606Spatrick       llvm::WritableMemoryBuffer::getNewUninitMemBuffer(InputSize + 1,
229a9ac8606Spatrick                                                         SourceName.str()));
230a9ac8606Spatrick   char *MBStart = const_cast<char *>(MB->getBufferStart());
231a9ac8606Spatrick   memcpy(MBStart, input.data(), InputSize);
232a9ac8606Spatrick   MBStart[InputSize] = '\n';
233a9ac8606Spatrick 
234a9ac8606Spatrick   SourceManager &SM = CI->getSourceManager();
235a9ac8606Spatrick 
236a9ac8606Spatrick   // FIXME: Create SourceLocation, which will allow clang to order the overload
237a9ac8606Spatrick   // candidates for example
238a9ac8606Spatrick   SourceLocation NewLoc = SM.getLocForStartOfFile(SM.getMainFileID());
239a9ac8606Spatrick 
240a9ac8606Spatrick   // Create FileID for the current buffer.
241a9ac8606Spatrick   FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0,
242a9ac8606Spatrick                                /*LoadedOffset=*/0, NewLoc);
243a9ac8606Spatrick 
244a9ac8606Spatrick   // NewLoc only used for diags.
245*12c85518Srobert   if (PP.EnterSourceFile(FID, /*DirLookup=*/nullptr, NewLoc))
246a9ac8606Spatrick     return llvm::make_error<llvm::StringError>("Parsing failed. "
247a9ac8606Spatrick                                                "Cannot enter source file.",
248a9ac8606Spatrick                                                std::error_code());
249a9ac8606Spatrick 
250a9ac8606Spatrick   auto PTU = ParseOrWrapTopLevelDecl();
251a9ac8606Spatrick   if (!PTU)
252a9ac8606Spatrick     return PTU.takeError();
253a9ac8606Spatrick 
254a9ac8606Spatrick   if (PP.getLangOpts().DelayedTemplateParsing) {
255a9ac8606Spatrick     // Microsoft-specific:
256a9ac8606Spatrick     // Late parsed templates can leave unswallowed "macro"-like tokens.
257a9ac8606Spatrick     // They will seriously confuse the Parser when entering the next
258a9ac8606Spatrick     // source file. So lex until we are EOF.
259a9ac8606Spatrick     Token Tok;
260a9ac8606Spatrick     do {
261a9ac8606Spatrick       PP.Lex(Tok);
262a9ac8606Spatrick     } while (Tok.isNot(tok::eof));
263a9ac8606Spatrick   }
264a9ac8606Spatrick 
265a9ac8606Spatrick   Token AssertTok;
266a9ac8606Spatrick   PP.Lex(AssertTok);
267a9ac8606Spatrick   assert(AssertTok.is(tok::eof) &&
268a9ac8606Spatrick          "Lexer must be EOF when starting incremental parse!");
269a9ac8606Spatrick 
270a9ac8606Spatrick   if (CodeGenerator *CG = getCodeGen(Act.get())) {
271a9ac8606Spatrick     std::unique_ptr<llvm::Module> M(CG->ReleaseModule());
272a9ac8606Spatrick     CG->StartModule("incr_module_" + std::to_string(PTUs.size()),
273a9ac8606Spatrick                     M->getContext());
274a9ac8606Spatrick 
275a9ac8606Spatrick     PTU->TheModule = std::move(M);
276a9ac8606Spatrick   }
277a9ac8606Spatrick 
278a9ac8606Spatrick   return PTU;
279a9ac8606Spatrick }
280*12c85518Srobert 
CleanUpPTU(PartialTranslationUnit & PTU)281*12c85518Srobert void IncrementalParser::CleanUpPTU(PartialTranslationUnit &PTU) {
282*12c85518Srobert   TranslationUnitDecl *MostRecentTU = PTU.TUPart;
283*12c85518Srobert   TranslationUnitDecl *FirstTU = MostRecentTU->getFirstDecl();
284*12c85518Srobert   if (StoredDeclsMap *Map = FirstTU->getPrimaryContext()->getLookupPtr()) {
285*12c85518Srobert     for (auto I = Map->begin(); I != Map->end(); ++I) {
286*12c85518Srobert       StoredDeclsList &List = I->second;
287*12c85518Srobert       DeclContextLookupResult R = List.getLookupResult();
288*12c85518Srobert       for (NamedDecl *D : R) {
289*12c85518Srobert         if (D->getTranslationUnitDecl() == MostRecentTU) {
290*12c85518Srobert           List.remove(D);
291*12c85518Srobert         }
292*12c85518Srobert       }
293*12c85518Srobert       if (List.isNull())
294*12c85518Srobert         Map->erase(I);
295*12c85518Srobert     }
296*12c85518Srobert   }
297*12c85518Srobert }
298*12c85518Srobert 
GetMangledName(GlobalDecl GD) const299*12c85518Srobert llvm::StringRef IncrementalParser::GetMangledName(GlobalDecl GD) const {
300*12c85518Srobert   CodeGenerator *CG = getCodeGen(Act.get());
301*12c85518Srobert   assert(CG);
302*12c85518Srobert   return CG->GetMangledName(GD);
303*12c85518Srobert }
304*12c85518Srobert 
305a9ac8606Spatrick } // end namespace clang
306