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