clang 23.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
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
103 StoredDeclsList(StoredDeclsList &&RHS) : Data(RHS.Data) {
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
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
160 void remove(NamedDecl *D) {
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 the declaration is promoted intentionally, keep it.
178 if (ND->isFromASTFile() && ND->getModuleOwnershipKind() !=
180 return true;
181 // FIXME: Can we get rid of this loop completely?
182 return llvm::any_of(Decls, [ND](NamedDecl *D) {
183 // Only replace the local declaration if the external declaration has
184 // higher visiblities.
185 return D->getModuleOwnershipKind() <= ND->getModuleOwnershipKind() &&
186 D->declarationReplaces(ND, /*IsKnownNewer=*/false);
187 });
188 });
189
190 // Don't have any pending external decls any more.
191 Data.setInt(false);
192
193 if (Decls.empty())
194 return;
195
196 // Convert Decls into a list, in order.
197 ASTContext &C = Decls.front()->getASTContext();
198 DeclListNode::Decls DeclsAsList = Decls.back();
199 for (size_t I = Decls.size() - 1; I != 0; --I) {
200 DeclListNode *Node = C.AllocateDeclListNode(Decls[I - 1]);
201 Node->Rest = DeclsAsList;
202 DeclsAsList = Node;
203 }
204
205 if (!Data.getPointer()) {
206 Data.setPointer(DeclsAsList);
207 return;
208 }
209
210 // Append the Decls.
211 DeclListNode *Node = C.AllocateDeclListNode(cast<NamedDecl *>(*Tail));
212 Node->Rest = DeclsAsList;
213 *Tail = Node;
214 }
215
216 /// Return the list of all the decls.
218 return DeclContext::lookup_result(Data.getPointer());
219 }
220
221 /// If this is a redeclaration of an existing decl, replace the old one with
222 /// D. Otherwise, append D.
224 const bool IsKnownNewer = true;
225
226 if (isNull()) {
227 Data.setPointer(D);
228 return;
229 }
230
231 // Most decls only have one entry in their list, special case it.
232 if (NamedDecl *OldD = getAsDecl()) {
233 if (D->declarationReplaces(OldD, IsKnownNewer)) {
234 Data.setPointer(D);
235 return;
236 }
237
238 // Add D after OldD.
239 ASTContext &C = D->getASTContext();
240 DeclListNode *Node = C.AllocateDeclListNode(OldD);
241 Node->Rest = D;
242 Data.setPointer(Node);
243 return;
244 }
245
246 // FIXME: Move the assert before the single decl case when we fix the
247 // duplication coming from the ASTReader reading builtin types.
248 assert(!llvm::is_contained(getLookupResult(), D) && "Already exists!");
249 // Determine if this declaration is actually a redeclaration.
250 for (DeclListNode *N = getAsList(); /*return in loop*/;
251 N = N->Rest.dyn_cast<DeclListNode *>()) {
252 if (D->declarationReplaces(N->D, IsKnownNewer)) {
253 N->D = D;
254 return;
255 }
256 if (auto *ND = N->Rest.dyn_cast<NamedDecl *>()) {
257 if (D->declarationReplaces(ND, IsKnownNewer)) {
258 N->Rest = D;
259 return;
260 }
261
262 // Add D after ND.
263 ASTContext &C = D->getASTContext();
264 DeclListNode *Node = C.AllocateDeclListNode(ND);
265 N->Rest = Node;
266 Node->Rest = D;
267 return;
268 }
269 }
270 }
271
272 /// Add a declaration to the list without checking if it replaces anything.
274 if (isNull()) {
275 Data.setPointer(D);
276 return;
277 }
278
279 ASTContext &C = D->getASTContext();
280 DeclListNode *Node = C.AllocateDeclListNode(D);
281 Node->Rest = Data.getPointer();
282 Data.setPointer(Node);
283 }
284
285 LLVM_DUMP_METHOD void dump() const {
286 Decls D = Data.getPointer();
287 if (!D) {
288 llvm::errs() << "<null>\n";
289 return;
290 }
291
292 while (true) {
293 if (auto *Node = D.dyn_cast<DeclListNode*>()) {
294 llvm::errs() << '[' << Node->D << "] -> ";
295 D = Node->Rest;
296 } else {
297 llvm::errs() << '[' << cast<NamedDecl *>(D) << "]\n";
298 return;
299 }
300 }
301 }
302};
303
305 : public llvm::SmallDenseMap<DeclarationName, StoredDeclsList, 4> {
306 friend class ASTContext; // walks the chain deleting these
307 friend class DeclContext;
308
309 llvm::PointerIntPair<StoredDeclsMap*, 1> Previous;
310public:
311 static void DestroyAll(StoredDeclsMap *Map, bool Dependent);
312};
313
315 friend class DeclContext; // iterates over diagnostics
317
318 DependentDiagnostic *FirstDiagnostic = nullptr;
319public:
321};
322
323} // namespace clang
324
325#endif // LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H
Defines the clang::ASTContext interface.
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:226
DeclContextLookupResult lookup_result
Definition DeclBase.h:2590
A list storing NamedDecls in the lookup tables.
Definition DeclBase.h:1342
llvm::PointerUnion< NamedDecl *, DeclListNode * > Decls
Definition DeclBase.h:1346
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:547
ModuleOwnershipKind getModuleOwnershipKind() const
Get the kind of module ownership for this declaration.
Definition DeclBase.h:889
bool isFromASTFile() const
Determine whether this declaration came from an AST file (such as a precompiled header or module) rat...
Definition DeclBase.h:801
@ VisiblePromoted
This declaration has an owning module, and is not visible to the current TU but we promoted it to be ...
Definition DeclBase.h:237
A dependently-generated diagnostic.
This represents a decl that may have a name.
Definition Decl.h:274
bool declarationReplaces(const NamedDecl *OldD, bool IsKnownNewer=true) const
Determine whether this declaration, if known to be well-formed within its context,...
Definition Decl.cpp:1871
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)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ Dependent
Parse the block as a dependent block, which may be used in some template instantiations but not other...
Definition Parser.h:142
U cast(CodeGen::Address addr)
Definition Address.h:327