clang 17.0.0git
IncrementalParser.cpp
Go to the documentation of this file.
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
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
32namespace 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///
44private:
45 bool IsTerminating = false;
46
47public:
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",
60 return Act;
62 [[fallthrough]];
64 [[fallthrough]];
66 Act = CreateFrontendAction(CI);
67 break;
69 [[fallthrough]];
71 [[fallthrough]];
73 [[fallthrough]];
75 [[fallthrough]];
77 [[fallthrough]];
79 Act.reset(new EmitLLVMOnlyAction(&LLVMCtx));
80 break;
81 }
82 return Act;
83 }()) {}
84 FrontendAction *getWrapped() const { return WrappedAction.get(); }
86 return TU_Incremental;
87 }
88 void ExecuteAction() override {
90 assert(CI.hasPreprocessor() && "No PP!");
91
92 // FIXME: Move the truncation aspect of this into Sema, we delayed this till
93 // here so the source manager would be initialized.
97
98 // Use a code completion consumer?
99 CodeCompleteConsumer *CompletionConsumer = nullptr;
101 CompletionConsumer = &CI.getCodeCompletionConsumer();
102
103 Preprocessor &PP = CI.getPreprocessor();
105
106 if (!CI.hasSema())
107 CI.createSema(getTranslationUnitKind(), CompletionConsumer);
108 }
109
110 // Do not terminate after processing the input. This allows us to keep various
111 // clang objects alive and to incrementally grow the current TU.
112 void EndSourceFile() override {
113 // The WrappedAction can be nullptr if we issued an error in the ctor.
114 if (IsTerminating && getWrapped())
116 }
117
119 assert(!IsTerminating && "Already finalized!");
120 IsTerminating = true;
122 }
123};
124
125IncrementalParser::IncrementalParser(std::unique_ptr<CompilerInstance> Instance,
126 llvm::LLVMContext &LLVMCtx,
127 llvm::Error &Err)
128 : CI(std::move(Instance)) {
129 llvm::ErrorAsOutParameter EAO(&Err);
130 Act = std::make_unique<IncrementalAction>(*CI, LLVMCtx, Err);
131 if (Err)
132 return;
133 CI->ExecuteAction(*Act);
134 Consumer = &CI->getASTConsumer();
135 P.reset(
136 new Parser(CI->getPreprocessor(), CI->getSema(), /*SkipBodies=*/false));
137 P->Initialize();
138}
139
141 P.reset();
142 Act->FinalizeAction();
143}
144
146IncrementalParser::ParseOrWrapTopLevelDecl() {
147 // Recover resources if we crash before exiting this method.
148 Sema &S = CI->getSema();
149 llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S);
150 Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true);
151 Sema::LocalEagerInstantiationScope LocalInstantiations(S);
152
153 PTUs.emplace_back(PartialTranslationUnit());
154 PartialTranslationUnit &LastPTU = PTUs.back();
155 // Add a new PTU.
156 ASTContext &C = S.getASTContext();
157 C.addTranslationUnitDecl();
158 LastPTU.TUPart = C.getTranslationUnitDecl();
159
160 // Skip previous eof due to last incremental input.
161 if (P->getCurToken().is(tok::eof)) {
162 P->ConsumeToken();
163 // FIXME: Clang does not call ExitScope on finalizing the regular TU, we
164 // might want to do that around HandleEndOfTranslationUnit.
165 P->ExitScope();
166 S.CurContext = nullptr;
167 // Start a new PTU.
168 P->EnterScope(Scope::DeclScope);
169 S.ActOnTranslationUnitScope(P->getCurScope());
170 }
171
173 Sema::ModuleImportState ImportState;
174 for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF;
175 AtEOF = P->ParseTopLevelDecl(ADecl, ImportState)) {
176 if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
177 return llvm::make_error<llvm::StringError>("Parsing failed. "
178 "The consumer rejected a decl",
179 std::error_code());
180 }
181
182 DiagnosticsEngine &Diags = getCI()->getDiagnostics();
183 if (Diags.hasErrorOccurred()) {
184 PartialTranslationUnit MostRecentPTU = {C.getTranslationUnitDecl(),
185 nullptr};
186 CleanUpPTU(MostRecentPTU);
187
188 Diags.Reset(/*soft=*/true);
189 Diags.getClient()->clear();
190 return llvm::make_error<llvm::StringError>("Parsing failed.",
191 std::error_code());
192 }
193
194 // Process any TopLevelDecls generated by #pragma weak.
195 for (Decl *D : S.WeakTopLevelDecls()) {
196 DeclGroupRef DGR(D);
197 Consumer->HandleTopLevelDecl(DGR);
198 }
199
200 LocalInstantiations.perform();
201 GlobalInstantiations.perform();
202
203 Consumer->HandleTranslationUnit(C);
204
205 return LastPTU;
206}
207
209 IncrementalAction *IncrAct = static_cast<IncrementalAction *>(Act);
210 FrontendAction *WrappedAct = IncrAct->getWrapped();
211 if (!WrappedAct->hasIRSupport())
212 return nullptr;
213 return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator();
214}
215
217IncrementalParser::Parse(llvm::StringRef input) {
218 Preprocessor &PP = CI->getPreprocessor();
219 assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?");
220
221 std::ostringstream SourceName;
222 SourceName << "input_line_" << InputCount++;
223
224 // Create an uninitialized memory buffer, copy code in and append "\n"
225 size_t InputSize = input.size(); // don't include trailing 0
226 // MemBuffer size should *not* include terminating zero
227 std::unique_ptr<llvm::MemoryBuffer> MB(
228 llvm::WritableMemoryBuffer::getNewUninitMemBuffer(InputSize + 1,
229 SourceName.str()));
230 char *MBStart = const_cast<char *>(MB->getBufferStart());
231 memcpy(MBStart, input.data(), InputSize);
232 MBStart[InputSize] = '\n';
233
234 SourceManager &SM = CI->getSourceManager();
235
236 // FIXME: Create SourceLocation, which will allow clang to order the overload
237 // candidates for example
238 SourceLocation NewLoc = SM.getLocForStartOfFile(SM.getMainFileID());
239
240 // Create FileID for the current buffer.
241 FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0,
242 /*LoadedOffset=*/0, NewLoc);
243
244 // NewLoc only used for diags.
245 if (PP.EnterSourceFile(FID, /*DirLookup=*/nullptr, NewLoc))
246 return llvm::make_error<llvm::StringError>("Parsing failed. "
247 "Cannot enter source file.",
248 std::error_code());
249
250 auto PTU = ParseOrWrapTopLevelDecl();
251 if (!PTU)
252 return PTU.takeError();
253
254 if (PP.getLangOpts().DelayedTemplateParsing) {
255 // Microsoft-specific:
256 // Late parsed templates can leave unswallowed "macro"-like tokens.
257 // They will seriously confuse the Parser when entering the next
258 // source file. So lex until we are EOF.
259 Token Tok;
260 do {
261 PP.Lex(Tok);
262 } while (Tok.isNot(tok::eof));
263 }
264
265 Token AssertTok;
266 PP.Lex(AssertTok);
267 assert(AssertTok.is(tok::eof) &&
268 "Lexer must be EOF when starting incremental parse!");
269
270 if (CodeGenerator *CG = getCodeGen(Act.get())) {
271 std::unique_ptr<llvm::Module> M(CG->ReleaseModule());
272 CG->StartModule("incr_module_" + std::to_string(PTUs.size()),
273 M->getContext());
274
275 PTU->TheModule = std::move(M);
276 }
277
278 return PTU;
279}
280
282 TranslationUnitDecl *MostRecentTU = PTU.TUPart;
283 TranslationUnitDecl *FirstTU = MostRecentTU->getFirstDecl();
284 if (StoredDeclsMap *Map = FirstTU->getPrimaryContext()->getLookupPtr()) {
285 for (auto I = Map->begin(); I != Map->end(); ++I) {
286 StoredDeclsList &List = I->second;
287 DeclContextLookupResult R = List.getLookupResult();
288 for (NamedDecl *D : R) {
289 if (D->getTranslationUnitDecl() == MostRecentTU) {
290 List.remove(D);
291 }
292 }
293 if (List.isNull())
294 Map->erase(I);
295 }
296 }
297}
298
300 CodeGenerator *CG = getCodeGen(Act.get());
301 assert(CG);
302 return CG->GetMangledName(GD);
303}
304
305} // end namespace clang
#define SM(sm)
Definition: Cuda.cpp:78
Defines the clang::FrontendAction interface and various convenience abstract classes (clang::ASTFront...
__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)
virtual void HandleTranslationUnit(ASTContext &Ctx)
HandleTranslationUnit - This method is called when the ASTs for entire translation unit have been par...
Definition: ASTConsumer.h:66
virtual bool HandleTopLevelDecl(DeclGroupRef D)
HandleTopLevelDecl - Handle the specified top-level declaration.
Definition: ASTConsumer.cpp:18
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:182
Abstract interface for a consumer of code-completion information.
The primary public interface to the Clang code generator.
Definition: ModuleBuilder.h:48
llvm::StringRef GetMangledName(GlobalDecl GD)
Given a global declaration, return a mangled name for this declaration which has been added to this c...
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
DiagnosticsEngine & getDiagnostics() const
Get the current diagnostics engine.
Preprocessor & getPreprocessor() const
Return the current preprocessor.
FrontendOptions & getFrontendOpts()
bool hasCodeCompletionConsumer() const
void createCodeCompletionConsumer()
Create a code completion consumer using the invocation; note that this will cause the source manager ...
CodeCompleteConsumer & getCodeCompletionConsumer() const
void createSema(TranslationUnitKind TUKind, CodeCompleteConsumer *CompletionConsumer)
Create the Sema object to be used for parsing.
The results of name lookup within a DeclContext.
Definition: DeclBase.h:1334
DeclContext * getPrimaryContext()
getPrimaryContext - There may be many different declarations of the same entity (including forward de...
Definition: DeclBase.cpp:1264
StoredDeclsMap * getLookupPtr() const
Retrieve the internal representation of the lookup structure.
Definition: DeclBase.h:2492
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
Abstract base class for actions which can be performed by the frontend.
virtual bool hasIRSupport() const
Does this action support use with IR files?
CompilerInstance & getCompilerInstance() const
ParsedSourceLocation CodeCompletionAt
If given, enable code completion at the provided location.
frontend::ActionKind ProgramAction
The frontend action to perform.
GlobalDecl - represents a global declaration.
Definition: GlobalDecl.h:56
A custom action enabling the incremental processing functionality.
void ExecuteAction() override
Callback to run the program action, using the initialized compiler instance.
TranslationUnitKind getTranslationUnitKind() override
For AST-based actions, the kind of translation unit we're handling.
IncrementalAction(CompilerInstance &CI, llvm::LLVMContext &LLVMCtx, llvm::Error &Err)
FrontendAction * getWrapped() const
void EndSourceFile() override
Perform any per-file post processing, deallocate per-file objects, and run statistics and output file...
llvm::StringRef GetMangledName(GlobalDecl GD) const
Uses the CodeGenModule mangled name cache and avoids recomputing.
IncrementalParser(std::unique_ptr< CompilerInstance > Instance, llvm::LLVMContext &LLVMCtx, llvm::Error &Err)
llvm::Expected< PartialTranslationUnit & > Parse(llvm::StringRef Input)
Parses incremental input by creating an in-memory file.
void CleanUpPTU(PartialTranslationUnit &PTU)
const CompilerInstance * getCI() const
This represents a decl that may have a name.
Definition: Decl.h:247
Parser - This implements a parser for the C family of languages.
Definition: Parser.h:61
OpaquePtr< DeclGroupRef > DeclGroupPtrTy
Definition: Parser.h:464
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:128
bool isIncrementalProcessingEnabled() const
Returns true if incremental processing is enabled.
void Lex(Token &Result)
Lex the next token for this preprocessor.
bool EnterSourceFile(FileID FID, ConstSearchDirIterator Dir, SourceLocation Loc, bool IsFirstIncludeOfFile=true)
Add a source file to the top of the include stack and start lexing tokens from it instead of the curr...
void EnterMainSourceFile()
Enter the specified FileID as the main source file, which implicitly adds the builtin defines etc.
const LangOptions & getLangOpts() const
decl_type * getFirstDecl()
Return the first declaration of this declaration or itself if this is the only declaration.
Definition: Redeclarable.h:216
@ DeclScope
This is a scope that can contain a declaration.
Definition: Scope.h:60
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:358
ModuleImportState
An enumeration to represent the transition of states in parsing module fragments and imports.
Definition: Sema.h:3148
Encodes a location in the source.
This class handles loading and caching of source files into memory.
An array of decls optimized for the common case of only containing one entry.
Token - This structure provides full information about a lexed token.
Definition: Token.h:35
bool is(tok::TokenKind K) const
is/isNot - Predicates to check if this token is a specific kind, as in "if (Tok.is(tok::l_brace)) {....
Definition: Token.h:98
bool isNot(tok::TokenKind K) const
Definition: Token.h:99
The top declaration context.
Definition: Decl.h:82
A frontend action which simply wraps some other runtime-specified frontend action.
bool hasCodeCompletionSupport() const override
Does this action support use with code completion?
std::unique_ptr< FrontendAction > WrappedAction
void EndSourceFile() override
Perform any per-file post processing, deallocate per-file objects, and run statistics and output file...
@ PrintPreprocessedInput
-E mode.
@ ParseSyntaxOnly
Parse and perform semantic analysis.
@ EmitBC
Emit a .bc file.
@ PluginAction
Run a plugin action,.
@ EmitObj
Emit a .o file.
@ ASTPrint
Parse ASTs and print them.
@ ASTDump
Parse ASTs and dump them.
@ EmitAssembly
Emit a .s file.
@ EmitLLVMOnly
Generate LLVM IR, but do not emit anything.
static CodeGenerator * getCodeGen(FrontendAction *Act)
std::unique_ptr< FrontendAction > CreateFrontendAction(CompilerInstance &CI)
Construct the FrontendAction of a compiler invocation based on the options specified for the compiler...
@ C
Languages that the frontend can parse and compile.
TranslationUnitKind
Describes the kind of translation unit being processed.
Definition: LangOptions.h:917
@ TU_Incremental
The translation unit is a is a complete translation unit that we might incrementally extend later.
Definition: LangOptions.h:930
Definition: Format.h:4608
The class keeps track of various objects created as part of processing incremental inputs.