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