clang 22.0.0git
DeclContextInternals.h
Go to the documentation of this file.
1//===- DeclContextInternals.h - DeclContext Representation ------*- C++ -*-===//
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 defines the data structures used in the implementation
10// of DeclContext.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H
15#define LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H
16
18#include "clang/AST/Decl.h"
19#include "clang/AST/DeclBase.h"
20#include "clang/AST/DeclCXX.h"
22#include "llvm/ADT/DenseMap.h"
23#include "llvm/ADT/PointerIntPair.h"
24#include "llvm/ADT/PointerUnion.h"
25#include <cassert>
26
27namespace clang {
28
29class DependentDiagnostic;
30
31/// An array of decls optimized for the common case of only containing
32/// one entry.
34 using Decls = DeclListNode::Decls;
35
36 /// A collection of declarations, with a flag to indicate if we have
37 /// further external declarations.
38 using DeclsAndHasExternalTy = llvm::PointerIntPair<Decls, 1, bool>;
39
40 /// The stored data, which will be either a pointer to a NamedDecl,
41 /// or a pointer to a list with a flag to indicate if there are further
42 /// external declarations.
43 DeclsAndHasExternalTy Data;
44
45 template <typename Fn> DeclListNode::Decls *erase_if(Fn ShouldErase) {
46 Decls List = Data.getPointer();
47
48 if (!List)
49 return nullptr;
50
52 DeclListNode::Decls NewHead = nullptr;
53 DeclListNode::Decls *NewLast = nullptr;
54 DeclListNode::Decls *NewTail = &NewHead;
55 while (true) {
56 if (!ShouldErase(*DeclListNode::iterator(List))) {
57 NewLast = NewTail;
58 *NewTail = List;
59 if (auto *Node = List.dyn_cast<DeclListNode*>()) {
60 NewTail = &Node->Rest;
61 List = Node->Rest;
62 } else {
63 break;
64 }
65 } else if (DeclListNode *N = List.dyn_cast<DeclListNode*>()) {
66 List = N->Rest;
67 C.DeallocateDeclListNode(N);
68 } else {
69 // We're discarding the last declaration in the list. The last node we
70 // want to keep (if any) will be of the form DeclListNode(D, <rest>);
71 // replace it with just D.
72 if (NewLast) {
73 DeclListNode *Node = cast<DeclListNode *>(*NewLast);
74 *NewLast = Node->D;
75 C.DeallocateDeclListNode(Node);
76 }
77 break;
78 }
79 }
80 Data.setPointer(NewHead);
81
82 assert(llvm::none_of(getLookupResult(), ShouldErase) && "Still exists!");
83
84 if (!Data.getPointer())
85 // All declarations are erased.
86 return nullptr;
87 else if (isa<NamedDecl *>(NewHead))
88 // The list only contains a declaration, the header itself.
89 return (DeclListNode::Decls *)&Data;
90 else {
91 assert(NewLast && isa<NamedDecl *>(*NewLast) && "Not the tail?");
92 return NewLast;
93 }
94 }
95
96 void erase(NamedDecl *ND) {
97 erase_if([ND](NamedDecl *D) { return D == ND; });
98 }
99
100public:
101 StoredDeclsList() = default;
102
104 RHS.Data.setPointer(nullptr);
105 RHS.Data.setInt(false);
106 }
107
109 if (isNull())
110 return;
111 // If this is a list-form, free the list.
113 Decls List = Data.getPointer();
114 while (DeclListNode *ToDealloc = List.dyn_cast<DeclListNode *>()) {
115 List = ToDealloc->Rest;
116 C.DeallocateDeclListNode(ToDealloc);
117 }
118 }
119
122 }
123
126
127 Data = RHS.Data;
128 RHS.Data.setPointer(nullptr);
129 RHS.Data.setInt(false);
130 return *this;
131 }
132
133 bool isNull() const { return Data.getPointer().isNull(); }
134
136 assert(!isNull() && "No ASTContext.");
137 if (NamedDecl *ND = getAsDecl())
138 return ND->getASTContext();
139 return getAsList()->D->getASTContext();
140 }
141
142 DeclsAndHasExternalTy getAsListAndHasExternal() const { return Data; }
143
145 return getAsListAndHasExternal().getPointer().dyn_cast<NamedDecl *>();
146 }
147
149 return getAsListAndHasExternal().getPointer().dyn_cast<DeclListNode*>();
150 }
151
152 bool hasExternalDecls() const {
153 return getAsListAndHasExternal().getInt();
154 }
155
157 Data.setInt(true);
158 }
159
161 assert(!isNull() && "removing from empty list");
162 erase(D);
163 }
164
165 /// Remove any declarations which were imported from an external AST source.
167 erase_if([](NamedDecl *ND) { return ND->isFromASTFile(); });
168
169 // Don't have any pending external decls any more.
170 Data.setInt(false);
171 }
172
174 // Remove all declarations that are either external or are replaced with
175 // external declarations with higher visibilities.
176 DeclListNode::Decls *Tail = erase_if([Decls](NamedDecl *ND) {
177 if (ND->isFromASTFile())
178 return true;
179 // FIXME: Can we get rid of this loop completely?
180 return llvm::any_of(Decls, [ND](NamedDecl *D) {
181 // Only replace the local declaration if the external declaration has
182 // higher visiblities.
183 return D->getModuleOwnershipKind() <= ND->getModuleOwnershipKind() &&
184 D->declarationReplaces(ND, /*IsKnownNewer=*/false);
185 });
186 });
187
188 // Don't have any pending external decls any more.
189 Data.setInt(false);
190
191 if (Decls.empty())
192 return;
193
194 // Convert Decls into a list, in order.
195 ASTContext &C = Decls.front()->getASTContext();
196 DeclListNode::Decls DeclsAsList = Decls.back();
197 for (size_t I = Decls.size() - 1; I != 0; --I) {
198 DeclListNode *Node = C.AllocateDeclListNode(Decls[I - 1]);
199 Node->Rest = DeclsAsList;
200 DeclsAsList = Node;
201 }
202
203 if (!Data.getPointer()) {
204 Data.setPointer(DeclsAsList);
205 return;
206 }
207
208 // Append the Decls.
209 DeclListNode *Node = C.AllocateDeclListNode(cast<NamedDecl *>(*Tail));
210 Node->Rest = DeclsAsList;
211 *Tail = Node;
212 }
213
214 /// Return the list of all the decls.
216 return DeclContext::lookup_result(Data.getPointer());
217 }
218
219 /// If this is a redeclaration of an existing decl, replace the old one with
220 /// D. Otherwise, append D.
222 const bool IsKnownNewer = true;
223
224 if (isNull()) {
225 Data.setPointer(D);
226 return;
227 }
228
229 // Most decls only have one entry in their list, special case it.
230 if (NamedDecl *OldD = getAsDecl()) {
231 if (D->declarationReplaces(OldD, IsKnownNewer)) {
232 Data.setPointer(D);
233 return;
234 }
235
236 // Add D after OldD.
237 ASTContext &C = D->getASTContext();
238 DeclListNode *Node = C.AllocateDeclListNode(OldD);
239 Node->Rest = D;
240 Data.setPointer(Node);
241 return;
242 }
243
244 // FIXME: Move the assert before the single decl case when we fix the
245 // duplication coming from the ASTReader reading builtin types.
246 assert(!llvm::is_contained(getLookupResult(), D) && "Already exists!");
247 // Determine if this declaration is actually a redeclaration.
248 for (DeclListNode *N = getAsList(); /*return in loop*/;
249 N = N->Rest.dyn_cast<DeclListNode *>()) {
250 if (D->declarationReplaces(N->D, IsKnownNewer)) {
251 N->D = D;
252 return;
253 }
254 if (auto *ND = N->Rest.dyn_cast<NamedDecl *>()) {
255 if (D->declarationReplaces(ND, IsKnownNewer)) {
256 N->Rest = D;
257 return;
258 }
259
260 // Add D after ND.
261 ASTContext &C = D->getASTContext();
262 DeclListNode *Node = C.AllocateDeclListNode(ND);
263 N->Rest = Node;
264 Node->Rest = D;
265 return;
266 }
267 }
268 }
269
270 /// Add a declaration to the list without checking if it replaces anything.
272 if (isNull()) {
273 Data.setPointer(D);
274 return;
275 }
276
277 ASTContext &C = D->getASTContext();
278 DeclListNode *Node = C.AllocateDeclListNode(D);
279 Node->Rest = Data.getPointer();
280 Data.setPointer(Node);
281 }
282
283 LLVM_DUMP_METHOD void dump() const {
284 Decls D = Data.getPointer();
285 if (!D) {
286 llvm::errs() << "<null>\n";
287 return;
288 }
289
290 while (true) {
291 if (auto *Node = D.dyn_cast<DeclListNode*>()) {
292 llvm::errs() << '[' << Node->D << "] -> ";
293 D = Node->Rest;
294 } else {
295 llvm::errs() << '[' << cast<NamedDecl *>(D) << "]\n";
296 return;
297 }
298 }
299 }
300};
301
303 : public llvm::SmallDenseMap<DeclarationName, StoredDeclsList, 4> {
304 friend class ASTContext; // walks the chain deleting these
305 friend class DeclContext;
306
307 llvm::PointerIntPair<StoredDeclsMap*, 1> Previous;
308public:
309 static void DestroyAll(StoredDeclsMap *Map, bool Dependent);
310};
311
313 friend class DeclContext; // iterates over diagnostics
315
316 DependentDiagnostic *FirstDiagnostic = nullptr;
317public:
319};
320
321} // namespace clang
322
323#endif // LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H
Defines the clang::ASTContext interface.
DynTypedNode Node
const Decl * D
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
const char * Data
StateNode * Previous
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:188
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
DeclContextLookupResult lookup_result
Definition: DeclBase.h:2577
A list storing NamedDecls in the lookup tables.
Definition: DeclBase.h:1329
llvm::PointerUnion< NamedDecl *, DeclListNode * > Decls
Definition: DeclBase.h:1333
ASTContext & getASTContext() const LLVM_READONLY
Definition: DeclBase.cpp:524
bool isFromASTFile() const
Determine whether this declaration came from an AST file (such as a precompiled header or module) rat...
Definition: DeclBase.h:793
A dependently-generated diagnostic.
This represents a decl that may have a name.
Definition: Decl.h:273
An array of decls optimized for the common case of only containing one entry.
DeclsAndHasExternalTy getAsListAndHasExternal() const
DeclListNode * getAsList() const
StoredDeclsList(StoredDeclsList &&RHS)
void addOrReplaceDecl(NamedDecl *D)
If this is a redeclaration of an existing decl, replace the old one with D.
NamedDecl * getAsDecl() const
void prependDeclNoReplace(NamedDecl *D)
Add a declaration to the list without checking if it replaces anything.
void replaceExternalDecls(ArrayRef< NamedDecl * > Decls)
void removeExternalDecls()
Remove any declarations which were imported from an external AST source.
DeclContext::lookup_result getLookupResult() const
Return the list of all the decls.
LLVM_DUMP_METHOD void dump() const
StoredDeclsList & operator=(StoredDeclsList &&RHS)
static void DestroyAll(StoredDeclsMap *Map, bool Dependent)
Definition: DeclBase.cpp:2210
The JSON file list parser is used to communicate input to InstallAPI.
@ Dependent
Parse the block as a dependent block, which may be used in some template instantiations but not other...