clang 24.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#include "IncrementalAction.h"
15
17#include "clang/AST/Decl.h"
18#include "clang/AST/DeclCXX.h"
24#include "clang/Parse/Parser.h"
25#include "clang/Sema/Sema.h"
26#include "llvm/ADT/SmallVector.h"
27#include "llvm/IR/Module.h"
28#include "llvm/Support/CrashRecoveryContext.h"
29#include "llvm/Support/Error.h"
30
31#include <sstream>
32
33#define DEBUG_TYPE "clang-repl"
34
35namespace clang {
36
37// IncrementalParser::IncrementalParser() {}
38
40 IncrementalAction *Act, llvm::Error &Err,
41 std::list<PartialTranslationUnit> &PTUs)
42 : S(Instance.getSema()), Act(Act), PTUs(PTUs) {
43 llvm::ErrorAsOutParameter EAO(&Err);
44 Consumer = &S.getASTConsumer();
45 P.reset(new Parser(S.getPreprocessor(), S, /*SkipBodies=*/false));
46
47 if (ExternalASTSource *External = S.getASTContext().getExternalSource())
48 External->StartTranslationUnit(Consumer);
49
50 P->Initialize();
51}
52
54
56IncrementalParser::ParseOrWrapTopLevelDecl() {
57 // Recover resources if we crash before exiting this method.
58 llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S);
59 Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true,
60 /*AtEndOfTU=*/true);
61 Sema::LocalEagerInstantiationScope LocalInstantiations(S, /*AtEndOfTU=*/true);
62
63 // Add a new PTU.
65 C.addTranslationUnitDecl();
66
67 // Skip previous eof due to last incremental input.
68 if (P->getCurToken().is(tok::annot_repl_input_end)) {
69 P->ConsumeAnyToken();
70 // FIXME: Clang does not call ExitScope on finalizing the regular TU, we
71 // might want to do that around HandleEndOfTranslationUnit.
72 P->ExitScope();
73 S.CurContext = nullptr;
74 // Start a new PTU.
75 P->EnterScope(Scope::DeclScope);
76 S.ActOnTranslationUnitScope(P->getCurScope());
77 }
78
80 Sema::ModuleImportState ImportState;
81 for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF;
82 AtEOF = P->ParseTopLevelDecl(ADecl, ImportState)) {
83 if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
84 return llvm::make_error<llvm::StringError>("Parsing failed. "
85 "The consumer rejected a decl",
86 std::error_code());
87 }
88
89 DiagnosticsEngine &Diags = S.getDiagnostics();
90 if (Diags.hasErrorOccurred()) {
91 CleanUpPTU(C.getTranslationUnitDecl());
92
93 Diags.Reset(/*soft=*/true);
94 Diags.getClient()->clear();
95 return llvm::make_error<llvm::StringError>("Parsing failed.",
96 std::error_code());
97 }
98
99 // Process any TopLevelDecls generated by #pragma weak.
100 for (Decl *D : S.WeakTopLevelDecls()) {
101 DeclGroupRef DGR(D);
102 Consumer->HandleTopLevelDecl(DGR);
103 }
104
105 LocalInstantiations.perform();
106 GlobalInstantiations.perform();
107
108 Consumer->HandleTranslationUnit(C);
109
110 return C.getTranslationUnitDecl();
111}
112
114IncrementalParser::Parse(llvm::StringRef input) {
115 Preprocessor &PP = S.getPreprocessor();
116 assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?");
117
118 std::ostringstream SourceName;
119 SourceName << "input_line_" << InputCount++;
120
121 // Create an uninitialized memory buffer, copy code in and append "\n"
122 size_t InputSize = input.size(); // don't include trailing 0
123 // MemBuffer size should *not* include terminating zero
124 std::unique_ptr<llvm::MemoryBuffer> MB(
125 llvm::WritableMemoryBuffer::getNewUninitMemBuffer(InputSize + 1,
126 SourceName.str()));
127 char *MBStart = const_cast<char *>(MB->getBufferStart());
128 memcpy(MBStart, input.data(), InputSize);
129 MBStart[InputSize] = '\n';
130
131 SourceManager &SM = S.getSourceManager();
132
133 // FIXME: Create SourceLocation, which will allow clang to order the overload
134 // candidates for example
136
137 // Create FileID for the current buffer.
138 FileID FID;
139 // Create FileEntry and FileID for the current buffer.
141 SourceName.str(), InputSize, 0 /* mod time*/);
142 SM.overrideFileContents(FE, std::move(MB));
143
144 // Ensure HeaderFileInfo exists before lookup to prevent assertion
146 HS.getFileInfo(FE);
147
148 FID = SM.createFileID(FE, NewLoc, SrcMgr::C_User);
149
150 // NewLoc only used for diags.
151 if (PP.EnterSourceFile(FID, /*DirLookup=*/nullptr, NewLoc))
152 return llvm::make_error<llvm::StringError>("Parsing failed. "
153 "Cannot enter source file.",
154 std::error_code());
155
156 auto PTU = ParseOrWrapTopLevelDecl();
157 if (!PTU)
158 return PTU.takeError();
159
160 if (PP.getLangOpts().DelayedTemplateParsing) {
161 // Microsoft-specific:
162 // Late parsed templates can leave unswallowed "macro"-like tokens.
163 // They will seriously confuse the Parser when entering the next
164 // source file. So lex until we are EOF.
165 Token Tok;
166 do {
167 PP.Lex(Tok);
168 } while (Tok.isNot(tok::annot_repl_input_end));
169 } else {
170 Token AssertTok;
171 PP.Lex(AssertTok);
172 assert(AssertTok.is(tok::annot_repl_input_end) &&
173 "Lexer must be EOF when starting incremental parse!");
174 }
175
176 return PTU;
177}
178
179void IncrementalParser::withdrawMostRecentTU(
180 TranslationUnitDecl *MostRecentTU) {
181 TranslationUnitDecl *Prev = MostRecentTU->getPreviousDecl();
182 if (!Prev)
183 return;
184 assert(MostRecentTU->getMostRecentDecl() == MostRecentTU &&
185 "Not the most recent translation unit!");
186
187 // Rebuild A -> ... -> Prev -> MostRecentTU as A -> ... -> Prev.
188 MostRecentTU->getFirstDecl()->RedeclLink.setLatest(Prev);
189
190 // getTranslationUnitDecl() requires the active unit to be the latest one.
192 if (C.TraversalScope.size() == 1 && C.TraversalScope.back() == MostRecentTU)
193 C.TraversalScope = {Prev};
194 C.TUDecl = Prev;
195}
196
197/// Removes decls introduced in the discarding PTU and restores the
198/// redeclaration chain to previous state.
199class ASTDeclUnmerger : public DeclVisitor<ASTDeclUnmerger> {
200 Sema &S;
201 TranslationUnitDecl *DiscardedTU;
202
203 template <typename DeclT> void withdraw(Redeclarable<DeclT> *DBase) {
204 if (NamedDecl *Prev = findSurvivor(static_cast<DeclT *>(DBase)))
205 unlinkRedeclChain(S.getASTContext(), DBase, Prev);
206 }
207
208 /// The newest declaration of whatever D redeclares that still lives outside
209 /// the DiscardedTU, or null if DiscardedTU introduced the name.
210 NamedDecl *findSurvivor(NamedDecl *D) const {
211 for (Decl *Prev = D->getPreviousDecl(); Prev;
212 Prev = Prev->getPreviousDecl())
213 if (Prev->getTranslationUnitDecl() != DiscardedTU)
214 return dyn_cast<NamedDecl>(Prev);
215 return nullptr;
216 }
217
218 template <typename DeclT>
219 void unlinkRedeclChain(ASTContext &C, Redeclarable<DeclT> *DBase,
220 NamedDecl *PrevND) {
221 auto *Latest = static_cast<DeclT *>(DBase);
222 auto *Survivor = cast<DeclT>(PrevND);
223
224 // Rebuild First -> ... -> Survivor -> ... -> Latest as
225 // First -> ... -> Survivor.
226 Latest->getFirstDecl()->RedeclLink.setLatest(Survivor);
227
228 // The chain is circular: a withdrawn declaration still linked into it can
229 // never walk back around to itself, so redecls() on one would not
230 // terminate. Give each withdrawn declaration a chain of its own.
231 for (DeclT *Dead = Latest; Dead != Survivor;) {
232 DeclT *Next = Dead->getPreviousDecl();
233 Dead->First = Dead;
234 Dead->RedeclLink = Redeclarable<DeclT>::LatestDeclLink(C);
235 Dead = Next;
236 }
237 }
238
239 /// Remove entry from "C"'s lookup tables
240 void removeFromLookups(NamedDecl *D) {
241 if (D->getDeclName().isEmpty())
242 return;
243
244 if (D->getDeclName().isIdentifier() && D->getDeclName().getFETokenInfo() &&
245 !D->getLangOpts().ObjC && !D->getLangOpts().CPlusPlus)
246 S.IdResolver.RemoveDecl(D);
247
249 if (StoredDeclsMap *Map = ECCD->getPrimaryContext()->getLookupPtr()) {
250 auto It = Map->find(D->getDeclName());
251 if (It != Map->end())
252 It->second.remove(D);
253 }
254 }
255
256 /// Remove Decls defined in this DC from the lookup table
257 /// and restore the redeclaration chain to previous state
258 void VisitDeclContext(DeclContext *DC) {
259 llvm::SmallVector<Decl *, 8> Members(DC->decls());
261 for (Decl *M : Members) {
262 if (auto *ND = dyn_cast<NamedDecl>(M))
263 if (NamedDecl *Prev = findSurvivor(ND))
264 Survivors.push_back(Prev);
265 Visit(M); // restore redecls
266 DC->removeDecl(M); // remove from lookup
267 if (auto *ND = dyn_cast<NamedDecl>(M))
268 removeFromLookups(ND);
269 }
270
271 // Restore lookup for the surviving predecessor
272 // of any removed decl that had a surviving predecessor
273 DeclContext *Primary = DC->getPrimaryContext();
274 for (NamedDecl *Prev : Survivors)
275 Primary->makeDeclVisibleInContext(Prev);
276 }
277
278public:
280 : S(S), DiscardedTU(DiscardedTU) {}
281
282 void VisitDecl(Decl *D) {
283 if (auto *DC = dyn_cast<DeclContext>(D))
284 VisitDeclContext(DC);
285 }
286
287 void VisitFunctionDecl(FunctionDecl *D) { withdraw(D); }
289 void VisitTypedefNameDecl(TypedefNameDecl *D) { withdraw(D); }
290 void VisitUsingShadowDecl(UsingShadowDecl *D) { withdraw(D); }
291 void VisitVarDecl(VarDecl *D) { withdraw(D); }
292
294 NamedDecl *Prev = findSurvivor(D);
295 if (!Prev)
296 return;
297 unlinkRedeclChain(S.getASTContext(), D, Prev);
298
299 // A class definition is kept in DefinitionData outside the
300 // redeclaration chain
301 auto *RD = dyn_cast<CXXRecordDecl>(Prev);
302 if (!RD)
303 return;
304 if (CXXRecordDecl *Def = RD->getDefinition();
305 Def && Def->getTranslationUnitDecl() == DiscardedTU)
306 for (auto *R : RD->redecls())
307 cast<CXXRecordDecl>(R)->DefinitionData = nullptr;
308 }
309
314
316 // Handle cases of nested redeclarations like:
317 // PTU1: namespace outer { namespace ns { class Foo; } }
318 // PTU2: namespace outer { namespace ns { class Foo { ... }; error; } }
319 // Foo's redeclaration needs to be restored
320 VisitDeclContext(D);
321 withdraw(D);
322 }
323
324 void VisitTranslationUnitDecl(TranslationUnitDecl *D) { VisitDeclContext(D); }
325};
326
328 ASTDeclUnmerger(S, MostRecentTU).Visit(MostRecentTU);
329
330 // Lookup alone is not enough: the redeclaration chain still reaches these.
331 withdrawMostRecentTU(MostRecentTU);
332}
333
336 std::unique_ptr<llvm::Module> M /*={}*/) {
337 PTUs.emplace_back(PartialTranslationUnit());
338 PartialTranslationUnit &LastPTU = PTUs.back();
339 LastPTU.TUPart = TU;
340
341 if (!M)
342 M = Act->GenModule();
343
344 assert((!Act->getCodeGen() || M) && "Must have a llvm::Module at this point");
345
346 LastPTU.TheModule = std::move(M);
347 LLVM_DEBUG(llvm::dbgs() << "compile-ptu " << PTUs.size() - 1
348 << ": [TU=" << LastPTU.TUPart);
349 if (LastPTU.TheModule)
350 LLVM_DEBUG(llvm::dbgs() << ", M=" << LastPTU.TheModule.get() << " ("
351 << LastPTU.TheModule->getName() << ")");
352 LLVM_DEBUG(llvm::dbgs() << "]\n");
353 return LastPTU;
354}
355} // end namespace clang
Defines the clang::ASTContext interface.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Defines the C++ template declaration subclasses.
Token Tok
The Token.
FormatToken * Next
The next token in the unwrapped line.
__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)
virtual bool HandleTopLevelDecl(DeclGroupRef D)
HandleTopLevelDecl - Handle the specified top-level declaration.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:239
ExternCContextDecl * getExternCContextDecl() const
Removes decls introduced in the discarding PTU and restores the redeclaration chain to previous state...
void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D)
void VisitFunctionDecl(FunctionDecl *D)
ASTDeclUnmerger(Sema &S, TranslationUnitDecl *DiscardedTU)
void VisitTypedefNameDecl(TypedefNameDecl *D)
void VisitTranslationUnitDecl(TranslationUnitDecl *D)
void VisitNamespaceDecl(NamespaceDecl *D)
void VisitUsingShadowDecl(UsingShadowDecl *D)
void VisitNamespaceAliasDecl(NamespaceAliasDecl *D)
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
CXXRecordDecl * getDefinition() const
Definition DeclCXX.h:549
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition DeclBase.h:1466
void makeDeclVisibleInContext(NamedDecl *D)
Makes a declaration visible within this context.
void removeDecl(Decl *D)
Removes a declaration from this context.
DeclContext * getPrimaryContext()
getPrimaryContext - There may be many different declarations of the same entity (including forward de...
decl_range decls() const
decls_begin/decls_end - Iterate over the declarations stored in this context.
Definition DeclBase.h:2423
StoredDeclsMap * getLookupPtr() const
Retrieve the internal representation of the lookup structure.
Definition DeclBase.h:2731
A simple visitor class that helps create declaration visitors.
Definition DeclVisitor.h:68
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
Decl * getPreviousDecl()
Retrieve the previous declaration that declares the same entity as this declaration,...
Definition DeclBase.h:1078
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:550
TranslationUnitDecl * getTranslationUnitDecl()
Definition DeclBase.cpp:535
const LangOptions & getLangOpts() const LLVM_READONLY
Helper to get the language options from the ASTContext.
Definition DeclBase.cpp:556
void * getFETokenInfo() const
Get and set FETokenInfo.
bool isEmpty() const
Evaluates true when this declaration name is empty.
bool isIdentifier() const
Predicate functions for querying what type of name this is.
Declaration context for names declared as extern "C" in C++.
Definition Decl.h:248
Abstract interface for external sources of AST nodes.
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
Definition FileEntry.h:57
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
FileEntryRef getVirtualFileRef(StringRef Filename, off_t Size, time_t ModificationTime)
Retrieve a file entry for a "virtual" file that acts as if there were a file with the given name on d...
Represents a function declaration or definition.
Definition Decl.h:2059
Encapsulates the information needed to find the file referenced by a #include or #include_next,...
HeaderFileInfo & getFileInfo(FileEntryRef FE)
Return the HeaderFileInfo structure for the specified FileEntry, in preparation for updating it in so...
A custom action enabling the incremental processing functionality.
IncrementalParser(CompilerInstance &Instance, IncrementalAction *Act, llvm::Error &Err, std::list< PartialTranslationUnit > &PTUs)
IncrementalAction * Act
The FrontendAction used during incremental parsing.
std::list< PartialTranslationUnit > & PTUs
unsigned InputCount
Counts the number of direct user input lines that have been parsed.
void CleanUpPTU(TranslationUnitDecl *MostRecentTU)
PartialTranslationUnit & RegisterPTU(TranslationUnitDecl *TU, std::unique_ptr< llvm::Module > M={})
Register a PTU produced by Parse.
virtual llvm::Expected< TranslationUnitDecl * > Parse(llvm::StringRef Input)
Parses incremental input by creating an in-memory file.
std::unique_ptr< Parser > P
Parser.
ASTConsumer * Consumer
Consumer to process the produced top level decls. Owned by Act.
Sema & S
The Sema performing the incremental compilation.
This represents a decl that may have a name.
Definition Decl.h:275
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition Decl.h:341
Represents a C++ namespace alias.
Definition DeclCXX.h:3231
Represent a C++ namespace.
Definition Decl.h:593
Parser - This implements a parser for the C family of languages.
Definition Parser.h:256
OpaquePtr< DeclGroupRef > DeclGroupPtrTy
Definition Parser.h:304
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
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...
HeaderSearch & getHeaderSearchInfo() const
const LangOptions & getLangOpts() const
Declaration of a redeclarable template.
Provides common interface for the Decls that can be redeclared.
decl_type * getFirstDecl()
Return the first declaration of this declaration or itself if this is the only declaration.
DeclLink RedeclLink
Points to the next redeclaration in the chain.
static DeclLink LatestDeclLink(const ASTContext &Ctx)
@ DeclScope
This is a scope that can contain a declaration.
Definition Scope.h:63
Sema - This implements semantic analysis and AST building for C.
Definition Sema.h:863
void ActOnTranslationUnitScope(Scope *S)
Scope actions.
Definition Sema.cpp:173
ASTContext & getASTContext() const
Definition Sema.h:935
DeclContext * CurContext
CurContext - This is the current declaration context of parsing.
Definition Sema.h:1444
ModuleImportState
An enumeration to represent the transition of states in parsing module fragments and imports.
Definition Sema.h:9950
Encodes a location in the source.
This class handles loading and caching of source files into memory.
FileID createFileID(FileEntryRef SourceFile, SourceLocation IncludePos, SrcMgr::CharacteristicKind FileCharacter, int LoadedID=0, SourceLocation::UIntTy LoadedOffset=0)
Create a new FileID that represents the specified file being #included from the specified IncludePosi...
FileManager & getFileManager() const
FileID getMainFileID() const
Returns the FileID of the main source file.
void overrideFileContents(FileEntryRef SourceFile, const llvm::MemoryBufferRef &Buffer)
Override the contents of the given source file by providing an already-allocated buffer.
SourceLocation getLocForStartOfFile(FileID FID) const
Return the source location corresponding to the first byte of the specified file.
Represents the declaration of a struct/union/class/enum.
Definition Decl.h:3852
NamedDecl * getTemplatedDecl() const
Get the underlying, templated declaration.
Token - This structure provides full information about a lexed token.
Definition Token.h:36
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:104
The top declaration context.
Definition Decl.h:106
TranslationUnitDecl * getPreviousDecl()
Return the previous declaration of this declaration or NULL if this is the first declaration.
TranslationUnitDecl * getMostRecentDecl()
Returns the most recent (re)declaration of this declaration.
Base class for declarations which introduce a typedef-name.
Definition Decl.h:3697
Represents a shadow declaration implicitly introduced into a scope by a (resolved) using-declaration ...
Definition DeclCXX.h:3429
Represents a variable declaration or definition.
Definition Decl.h:933
Top level wrappers for InstallAPI frontend operations.
@ External
External linkage, which indicates that the entity can be referred to from other translation units.
Definition Linkage.h:58
U cast(CodeGen::Address addr)
Definition Address.h:327
The class keeps track of various objects created as part of processing incremental inputs.
std::unique_ptr< llvm::Module > TheModule
The llvm IR produced for the input.