clang 23.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
16#include "clang/AST/Decl.h"
20#include "clang/Parse/Parser.h"
21#include "clang/Sema/Sema.h"
22#include "llvm/ADT/SmallVector.h"
23#include "llvm/IR/Module.h"
24#include "llvm/Support/CrashRecoveryContext.h"
25#include "llvm/Support/Error.h"
26
27#include <sstream>
28
29#define DEBUG_TYPE "clang-repl"
30
31namespace clang {
32
33// IncrementalParser::IncrementalParser() {}
34
36 IncrementalAction *Act, llvm::Error &Err,
37 std::list<PartialTranslationUnit> &PTUs)
38 : S(Instance.getSema()), Act(Act), PTUs(PTUs) {
39 llvm::ErrorAsOutParameter EAO(&Err);
40 Consumer = &S.getASTConsumer();
41 P.reset(new Parser(S.getPreprocessor(), S, /*SkipBodies=*/false));
42
43 if (ExternalASTSource *External = S.getASTContext().getExternalSource())
44 External->StartTranslationUnit(Consumer);
45
46 P->Initialize();
47}
48
50
52IncrementalParser::ParseOrWrapTopLevelDecl() {
53 // Recover resources if we crash before exiting this method.
54 llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S);
55 Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true,
56 /*AtEndOfTU=*/true);
57 Sema::LocalEagerInstantiationScope LocalInstantiations(S, /*AtEndOfTU=*/true);
58
59 // Add a new PTU.
61 C.addTranslationUnitDecl();
62
63 // Skip previous eof due to last incremental input.
64 if (P->getCurToken().is(tok::annot_repl_input_end)) {
65 P->ConsumeAnyToken();
66 // FIXME: Clang does not call ExitScope on finalizing the regular TU, we
67 // might want to do that around HandleEndOfTranslationUnit.
68 P->ExitScope();
69 S.CurContext = nullptr;
70 // Start a new PTU.
71 P->EnterScope(Scope::DeclScope);
72 S.ActOnTranslationUnitScope(P->getCurScope());
73 }
74
76 Sema::ModuleImportState ImportState;
77 for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF;
78 AtEOF = P->ParseTopLevelDecl(ADecl, ImportState)) {
79 if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
80 return llvm::make_error<llvm::StringError>("Parsing failed. "
81 "The consumer rejected a decl",
82 std::error_code());
83 }
84
85 DiagnosticsEngine &Diags = S.getDiagnostics();
86 if (Diags.hasErrorOccurred()) {
87 CleanUpPTU(C.getTranslationUnitDecl());
88
89 Diags.Reset(/*soft=*/true);
90 Diags.getClient()->clear();
91 return llvm::make_error<llvm::StringError>("Parsing failed.",
92 std::error_code());
93 }
94
95 // Process any TopLevelDecls generated by #pragma weak.
96 for (Decl *D : S.WeakTopLevelDecls()) {
97 DeclGroupRef DGR(D);
98 Consumer->HandleTopLevelDecl(DGR);
99 }
100
101 LocalInstantiations.perform();
102 GlobalInstantiations.perform();
103
104 Consumer->HandleTranslationUnit(C);
105
106 return C.getTranslationUnitDecl();
107}
108
110IncrementalParser::Parse(llvm::StringRef input) {
111 Preprocessor &PP = S.getPreprocessor();
112 assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?");
113
114 std::ostringstream SourceName;
115 SourceName << "input_line_" << InputCount++;
116
117 // Create an uninitialized memory buffer, copy code in and append "\n"
118 size_t InputSize = input.size(); // don't include trailing 0
119 // MemBuffer size should *not* include terminating zero
120 std::unique_ptr<llvm::MemoryBuffer> MB(
121 llvm::WritableMemoryBuffer::getNewUninitMemBuffer(InputSize + 1,
122 SourceName.str()));
123 char *MBStart = const_cast<char *>(MB->getBufferStart());
124 memcpy(MBStart, input.data(), InputSize);
125 MBStart[InputSize] = '\n';
126
127 SourceManager &SM = S.getSourceManager();
128
129 // FIXME: Create SourceLocation, which will allow clang to order the overload
130 // candidates for example
131 SourceLocation NewLoc = SM.getLocForStartOfFile(SM.getMainFileID());
132
133 // Create FileID for the current buffer.
134 FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0,
135 /*LoadedOffset=*/0, NewLoc);
136
137 // NewLoc only used for diags.
138 if (PP.EnterSourceFile(FID, /*DirLookup=*/nullptr, NewLoc))
139 return llvm::make_error<llvm::StringError>("Parsing failed. "
140 "Cannot enter source file.",
141 std::error_code());
142
143 auto PTU = ParseOrWrapTopLevelDecl();
144 if (!PTU)
145 return PTU.takeError();
146
147 if (PP.getLangOpts().DelayedTemplateParsing) {
148 // Microsoft-specific:
149 // Late parsed templates can leave unswallowed "macro"-like tokens.
150 // They will seriously confuse the Parser when entering the next
151 // source file. So lex until we are EOF.
152 Token Tok;
153 do {
154 PP.Lex(Tok);
155 } while (Tok.isNot(tok::annot_repl_input_end));
156 } else {
157 Token AssertTok;
158 PP.Lex(AssertTok);
159 assert(AssertTok.is(tok::annot_repl_input_end) &&
160 "Lexer must be EOF when starting incremental parse!");
161 }
162
163 return PTU;
164}
165
167 if (StoredDeclsMap *Map = MostRecentTU->getPrimaryContext()->getLookupPtr()) {
168 for (auto &&[Key, List] : *Map) {
169 DeclContextLookupResult R = List.getLookupResult();
170 std::vector<NamedDecl *> NamedDeclsToRemove;
171 bool RemoveAll = true;
172 for (NamedDecl *D : R) {
173 if (D->getTranslationUnitDecl() == MostRecentTU)
174 NamedDeclsToRemove.push_back(D);
175 else
176 RemoveAll = false;
177 }
178 if (LLVM_LIKELY(RemoveAll)) {
179 Map->erase(Key);
180 } else {
181 for (NamedDecl *D : NamedDeclsToRemove)
182 List.remove(D);
183 }
184 }
185 }
186
187 ExternCContextDecl *ECCD = S.getASTContext().getExternCContextDecl();
188 if (StoredDeclsMap *Map = ECCD->getPrimaryContext()->getLookupPtr()) {
189 for (auto &&[Key, List] : *Map) {
190 DeclContextLookupResult R = List.getLookupResult();
191 llvm::SmallVector<NamedDecl *, 4> NamedDeclsToRemove;
192 for (NamedDecl *D : R) {
193 // Implicitly generated C decl is not attached to the current TU but
194 // lexically attached to the recent TU, so we need to check the lexical
195 // context.
196 DeclContext *LDC = D->getLexicalDeclContext();
197 while (LDC && !isa<TranslationUnitDecl>(LDC))
198 LDC = LDC->getLexicalParent();
199 TranslationUnitDecl *TopTU = cast_or_null<TranslationUnitDecl>(LDC);
200 if (TopTU == MostRecentTU)
201 NamedDeclsToRemove.push_back(D);
202 }
203 for (NamedDecl *D : NamedDeclsToRemove) {
204 List.remove(D);
205 S.IdResolver.RemoveDecl(D);
206 }
207 }
208 }
209
210 // FIXME: We should de-allocate MostRecentTU
211 for (Decl *D : MostRecentTU->decls()) {
212 auto *ND = dyn_cast<NamedDecl>(D);
213 if (!ND || ND->getDeclName().isEmpty())
214 continue;
215 // Check if we need to clean up the IdResolver chain.
216 if (ND->getDeclName().getFETokenInfo() && !D->getLangOpts().ObjC &&
217 !D->getLangOpts().CPlusPlus)
218 S.IdResolver.RemoveDecl(ND);
219 }
220}
221
224 std::unique_ptr<llvm::Module> M /*={}*/) {
225 PTUs.emplace_back(PartialTranslationUnit());
226 PartialTranslationUnit &LastPTU = PTUs.back();
227 LastPTU.TUPart = TU;
228
229 if (!M)
230 M = Act->GenModule();
231
232 assert((!Act->getCodeGen() || M) && "Must have a llvm::Module at this point");
233
234 LastPTU.TheModule = std::move(M);
235 LLVM_DEBUG(llvm::dbgs() << "compile-ptu " << PTUs.size() - 1
236 << ": [TU=" << LastPTU.TUPart);
237 if (LastPTU.TheModule)
238 LLVM_DEBUG(llvm::dbgs() << ", M=" << LastPTU.TheModule.get() << " ("
239 << LastPTU.TheModule->getName() << ")");
240 LLVM_DEBUG(llvm::dbgs() << "]\n");
241 return LastPTU;
242}
243} // end namespace clang
Token Tok
The Token.
#define SM(sm)
__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:226
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
The results of name lookup within a DeclContext.
Definition DeclBase.h:1382
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition DeclBase.h:1449
DeclContext * getLexicalParent()
getLexicalParent - Returns the containing lexical DeclContext.
Definition DeclBase.h:2125
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:2373
StoredDeclsMap * getLookupPtr() const
Retrieve the internal representation of the lookup structure.
Definition DeclBase.h:2681
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
Declaration context for names declared as extern "C" in C++.
Definition Decl.h:247
Abstract interface for external sources of AST nodes.
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
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:274
Parser - This implements a parser for the C family of languages.
Definition Parser.h:172
OpaquePtr< DeclGroupRef > DeclGroupPtrTy
Definition Parser.h:220
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...
const LangOptions & getLangOpts() const
@ DeclScope
This is a scope that can contain a declaration.
Definition Scope.h:63
void ActOnTranslationUnitScope(Scope *S)
Scope actions.
Definition Sema.cpp:172
ASTContext & getASTContext() const
Definition Sema.h:939
DeclContext * CurContext
CurContext - This is the current declaration context of parsing.
Definition Sema.h:1437
ModuleImportState
An enumeration to represent the transition of states in parsing module fragments and imports.
Definition Sema.h:9934
Encodes a location in the source.
This class handles loading and caching of source files into memory.
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:105
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ External
External linkage, which indicates that the entity can be referred to from other translation units.
Definition Linkage.h:58
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.