clang 20.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
18#include "clang/Parse/Parser.h"
19#include "clang/Sema/Sema.h"
20#include "llvm/Support/CrashRecoveryContext.h"
21#include "llvm/Support/Error.h"
22
23#include <sstream>
24
25namespace clang {
26
27// IncrementalParser::IncrementalParser() {}
28
30 llvm::Error &Err)
31 : S(Instance.getSema()) {
32 llvm::ErrorAsOutParameter EAO(&Err);
34 P.reset(new Parser(S.getPreprocessor(), S, /*SkipBodies=*/false));
35 P->Initialize();
36}
37
39
41IncrementalParser::ParseOrWrapTopLevelDecl() {
42 // Recover resources if we crash before exiting this method.
43 llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S);
44 Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true);
45 Sema::LocalEagerInstantiationScope LocalInstantiations(S);
46
47 // Add a new PTU.
49 C.addTranslationUnitDecl();
50
51 // Skip previous eof due to last incremental input.
52 if (P->getCurToken().is(tok::annot_repl_input_end)) {
53 P->ConsumeAnyToken();
54 // FIXME: Clang does not call ExitScope on finalizing the regular TU, we
55 // might want to do that around HandleEndOfTranslationUnit.
56 P->ExitScope();
57 S.CurContext = nullptr;
58 // Start a new PTU.
59 P->EnterScope(Scope::DeclScope);
60 S.ActOnTranslationUnitScope(P->getCurScope());
61 }
62
64 Sema::ModuleImportState ImportState;
65 for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF;
66 AtEOF = P->ParseTopLevelDecl(ADecl, ImportState)) {
67 if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
68 return llvm::make_error<llvm::StringError>("Parsing failed. "
69 "The consumer rejected a decl",
70 std::error_code());
71 }
72
73 DiagnosticsEngine &Diags = S.getDiagnostics();
74 if (Diags.hasErrorOccurred()) {
75 CleanUpPTU(C.getTranslationUnitDecl());
76
77 Diags.Reset(/*soft=*/true);
78 Diags.getClient()->clear();
79 return llvm::make_error<llvm::StringError>("Parsing failed.",
80 std::error_code());
81 }
82
83 // Process any TopLevelDecls generated by #pragma weak.
84 for (Decl *D : S.WeakTopLevelDecls()) {
85 DeclGroupRef DGR(D);
87 }
88
89 LocalInstantiations.perform();
90 GlobalInstantiations.perform();
91
93
94 return C.getTranslationUnitDecl();
95}
96
98IncrementalParser::Parse(llvm::StringRef input) {
100 assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?");
101
102 std::ostringstream SourceName;
103 SourceName << "input_line_" << InputCount++;
104
105 // Create an uninitialized memory buffer, copy code in and append "\n"
106 size_t InputSize = input.size(); // don't include trailing 0
107 // MemBuffer size should *not* include terminating zero
108 std::unique_ptr<llvm::MemoryBuffer> MB(
109 llvm::WritableMemoryBuffer::getNewUninitMemBuffer(InputSize + 1,
110 SourceName.str()));
111 char *MBStart = const_cast<char *>(MB->getBufferStart());
112 memcpy(MBStart, input.data(), InputSize);
113 MBStart[InputSize] = '\n';
114
116
117 // FIXME: Create SourceLocation, which will allow clang to order the overload
118 // candidates for example
119 SourceLocation NewLoc = SM.getLocForStartOfFile(SM.getMainFileID());
120
121 // Create FileID for the current buffer.
122 FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0,
123 /*LoadedOffset=*/0, NewLoc);
124
125 // NewLoc only used for diags.
126 if (PP.EnterSourceFile(FID, /*DirLookup=*/nullptr, NewLoc))
127 return llvm::make_error<llvm::StringError>("Parsing failed. "
128 "Cannot enter source file.",
129 std::error_code());
130
131 auto PTU = ParseOrWrapTopLevelDecl();
132 if (!PTU)
133 return PTU.takeError();
134
135 if (PP.getLangOpts().DelayedTemplateParsing) {
136 // Microsoft-specific:
137 // Late parsed templates can leave unswallowed "macro"-like tokens.
138 // They will seriously confuse the Parser when entering the next
139 // source file. So lex until we are EOF.
140 Token Tok;
141 do {
142 PP.Lex(Tok);
143 } while (Tok.isNot(tok::annot_repl_input_end));
144 } else {
145 Token AssertTok;
146 PP.Lex(AssertTok);
147 assert(AssertTok.is(tok::annot_repl_input_end) &&
148 "Lexer must be EOF when starting incremental parse!");
149 }
150
151 return PTU;
152}
153
155 if (StoredDeclsMap *Map = MostRecentTU->getPrimaryContext()->getLookupPtr()) {
156 for (auto &&[Key, List] : *Map) {
157 DeclContextLookupResult R = List.getLookupResult();
158 std::vector<NamedDecl *> NamedDeclsToRemove;
159 bool RemoveAll = true;
160 for (NamedDecl *D : R) {
161 if (D->getTranslationUnitDecl() == MostRecentTU)
162 NamedDeclsToRemove.push_back(D);
163 else
164 RemoveAll = false;
165 }
166 if (LLVM_LIKELY(RemoveAll)) {
167 Map->erase(Key);
168 } else {
169 for (NamedDecl *D : NamedDeclsToRemove)
170 List.remove(D);
171 }
172 }
173 }
174
175 // FIXME: We should de-allocate MostRecentTU
176 for (Decl *D : MostRecentTU->decls()) {
177 auto *ND = dyn_cast<NamedDecl>(D);
178 if (!ND)
179 continue;
180 // Check if we need to clean up the IdResolver chain.
181 if (ND->getDeclName().getFETokenInfo() && !D->getLangOpts().ObjC &&
182 !D->getLangOpts().CPlusPlus)
184 }
185}
186
187} // end namespace clang
#define SM(sm)
Definition: Cuda.cpp:84
const Decl * D
__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:67
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:188
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
The results of name lookup within a DeclContext.
Definition: DeclBase.h:1368
DeclContext * getPrimaryContext()
getPrimaryContext - There may be many different declarations of the same entity (including forward de...
Definition: DeclBase.cpp:1424
decl_range decls() const
decls_begin/decls_end - Iterate over the declarations stored in this context.
Definition: DeclBase.h:2349
StoredDeclsMap * getLookupPtr() const
Retrieve the internal representation of the lookup structure.
Definition: DeclBase.h:2657
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
void RemoveDecl(NamedDecl *D)
RemoveDecl - Unlink the decl from its shadowed decl chain.
IncrementalParser(CompilerInstance &Instance, llvm::Error &Err)
unsigned InputCount
Counts the number of direct user input lines that have been parsed.
void CleanUpPTU(TranslationUnitDecl *MostRecentTU)
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:253
Parser - This implements a parser for the C family of languages.
Definition: Parser.h:58
OpaquePtr< DeclGroupRef > DeclGroupPtrTy
Definition: Parser.h:513
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:138
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
Preprocessor & getPreprocessor() const
Definition: Sema.h:530
void ActOnTranslationUnitScope(Scope *S)
Scope actions.
Definition: Sema.cpp:148
DiagnosticsEngine & getDiagnostics() const
Definition: Sema.h:528
ASTContext & getASTContext() const
Definition: Sema.h:531
SmallVectorImpl< Decl * > & WeakTopLevelDecls()
WeakTopLevelDeclDecls - access to #pragma weak-generated Decls.
Definition: Sema.h:4456
ASTConsumer & getASTConsumer() const
Definition: Sema.h:532
DeclContext * CurContext
CurContext - This is the current declaration context of parsing.
Definition: Sema.h:1043
SourceManager & getSourceManager() const
Definition: Sema.h:529
ModuleImportState
An enumeration to represent the transition of states in parsing module fragments and imports.
Definition: Sema.h:9608
IdentifierResolver IdResolver
Definition: Sema.h:2996
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:99
bool isNot(tok::TokenKind K) const
Definition: Token.h:100
The top declaration context.
Definition: Decl.h:84
The JSON file list parser is used to communicate input to InstallAPI.