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