xref: /freebsd/contrib/llvm-project/clang/include/clang/AST/DeclContextInternals.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
17 #include "clang/AST/ASTContext.h"
18 #include "clang/AST/Decl.h"
19 #include "clang/AST/DeclBase.h"
20 #include "clang/AST/DeclCXX.h"
21 #include "clang/AST/DeclarationName.h"
22 #include "llvm/ADT/DenseMap.h"
23 #include "llvm/ADT/PointerIntPair.h"
24 #include "llvm/ADT/PointerUnion.h"
25 #include <cassert>
26 
27 namespace clang {
28 
29 class DependentDiagnostic;
30 
31 /// An array of decls optimized for the common case of only containing
32 /// one entry.
33 class StoredDeclsList {
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 
erase_if(Fn ShouldErase)45   template <typename Fn> DeclListNode::Decls *erase_if(Fn ShouldErase) {
46     Decls List = Data.getPointer();
47 
48     if (!List)
49       return nullptr;
50 
51     ASTContext &C = getASTContext();
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 
erase(NamedDecl * ND)96   void erase(NamedDecl *ND) {
97     erase_if([ND](NamedDecl *D) { return D == ND; });
98   }
99 
100 public:
101   StoredDeclsList() = default;
102 
StoredDeclsList(StoredDeclsList && RHS)103   StoredDeclsList(StoredDeclsList &&RHS) : Data(RHS.Data) {
104     RHS.Data.setPointer(nullptr);
105     RHS.Data.setInt(false);
106   }
107 
MaybeDeallocList()108   void MaybeDeallocList() {
109     if (isNull())
110       return;
111     // If this is a list-form, free the list.
112     ASTContext &C = getASTContext();
113     Decls List = Data.getPointer();
114     while (DeclListNode *ToDealloc = List.dyn_cast<DeclListNode *>()) {
115       List = ToDealloc->Rest;
116       C.DeallocateDeclListNode(ToDealloc);
117     }
118   }
119 
~StoredDeclsList()120   ~StoredDeclsList() {
121     MaybeDeallocList();
122   }
123 
124   StoredDeclsList &operator=(StoredDeclsList &&RHS) {
125     MaybeDeallocList();
126 
127     Data = RHS.Data;
128     RHS.Data.setPointer(nullptr);
129     RHS.Data.setInt(false);
130     return *this;
131   }
132 
isNull()133   bool isNull() const { return Data.getPointer().isNull(); }
134 
getASTContext()135   ASTContext &getASTContext() {
136     assert(!isNull() && "No ASTContext.");
137     if (NamedDecl *ND = getAsDecl())
138       return ND->getASTContext();
139     return getAsList()->D->getASTContext();
140   }
141 
getAsListAndHasExternal()142   DeclsAndHasExternalTy getAsListAndHasExternal() const { return Data; }
143 
getAsDecl()144   NamedDecl *getAsDecl() const {
145     return getAsListAndHasExternal().getPointer().dyn_cast<NamedDecl *>();
146   }
147 
getAsList()148   DeclListNode *getAsList() const {
149     return getAsListAndHasExternal().getPointer().dyn_cast<DeclListNode*>();
150   }
151 
hasExternalDecls()152   bool hasExternalDecls() const {
153     return getAsListAndHasExternal().getInt();
154   }
155 
setHasExternalDecls()156   void setHasExternalDecls() {
157     Data.setInt(true);
158   }
159 
remove(NamedDecl * D)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.
removeExternalDecls()166   void removeExternalDecls() {
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 
replaceExternalDecls(ArrayRef<NamedDecl * > Decls)173   void replaceExternalDecls(ArrayRef<NamedDecl*> Decls) {
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.
getLookupResult()215   DeclContext::lookup_result getLookupResult() const {
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.
addOrReplaceDecl(NamedDecl * D)221   void addOrReplaceDecl(NamedDecl *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.
prependDeclNoReplace(NamedDecl * D)271   void prependDeclNoReplace(NamedDecl *D) {
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 
dump()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 
302 class StoredDeclsMap
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;
308 public:
309   static void DestroyAll(StoredDeclsMap *Map, bool Dependent);
310 };
311 
312 class DependentStoredDeclsMap : public StoredDeclsMap {
313   friend class DeclContext; // iterates over diagnostics
314   friend class DependentDiagnostic;
315 
316   DependentDiagnostic *FirstDiagnostic = nullptr;
317 public:
318   DependentStoredDeclsMap() = default;
319 };
320 
321 } // namespace clang
322 
323 #endif // LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H
324