/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/include/clang/AST/DeclContextInternals.h
Line | Count | Source (jump to first uncovered line) |
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/Decl.h" |
18 | | #include "clang/AST/DeclBase.h" |
19 | | #include "clang/AST/DeclCXX.h" |
20 | | #include "clang/AST/DeclarationName.h" |
21 | | #include "llvm/ADT/DenseMap.h" |
22 | | #include "llvm/ADT/PointerIntPair.h" |
23 | | #include "llvm/ADT/PointerUnion.h" |
24 | | #include "llvm/ADT/SmallVector.h" |
25 | | #include <algorithm> |
26 | | #include <cassert> |
27 | | |
28 | | namespace clang { |
29 | | |
30 | | class DependentDiagnostic; |
31 | | |
32 | | /// An array of decls optimized for the common case of only containing |
33 | | /// one entry. |
34 | | struct StoredDeclsList { |
35 | | /// When in vector form, this is what the Data pointer points to. |
36 | | using DeclsTy = SmallVector<NamedDecl *, 4>; |
37 | | |
38 | | /// A collection of declarations, with a flag to indicate if we have |
39 | | /// further external declarations. |
40 | | using DeclsAndHasExternalTy = llvm::PointerIntPair<DeclsTy *, 1, bool>; |
41 | | |
42 | | /// The stored data, which will be either a pointer to a NamedDecl, |
43 | | /// or a pointer to a vector with a flag to indicate if there are further |
44 | | /// external declarations. |
45 | | llvm::PointerUnion<NamedDecl *, DeclsAndHasExternalTy> Data; |
46 | | |
47 | | public: |
48 | 20.5M | StoredDeclsList() = default; |
49 | | |
50 | 18.9M | StoredDeclsList(StoredDeclsList &&RHS) : Data(RHS.Data) { |
51 | 18.9M | RHS.Data = (NamedDecl *)nullptr; |
52 | 18.9M | } |
53 | | |
54 | 29.9M | ~StoredDeclsList() { |
55 | | // If this is a vector-form, free the vector. |
56 | 29.9M | if (DeclsTy *Vector = getAsVector()) |
57 | 1.41M | delete Vector; |
58 | 29.9M | } |
59 | | |
60 | 21 | StoredDeclsList &operator=(StoredDeclsList &&RHS) { |
61 | 21 | if (DeclsTy *Vector = getAsVector()) |
62 | 0 | delete Vector; |
63 | 21 | Data = RHS.Data; |
64 | 21 | RHS.Data = (NamedDecl *)nullptr; |
65 | 21 | return *this; |
66 | 21 | } |
67 | | |
68 | 111M | bool isNull() const { return Data.isNull(); } |
69 | | |
70 | 55.7M | NamedDecl *getAsDecl() const { |
71 | 55.7M | return Data.dyn_cast<NamedDecl *>(); |
72 | 55.7M | } |
73 | | |
74 | 75.1M | DeclsAndHasExternalTy getAsVectorAndHasExternal() const { |
75 | 75.1M | return Data.dyn_cast<DeclsAndHasExternalTy>(); |
76 | 75.1M | } |
77 | | |
78 | 67.6M | DeclsTy *getAsVector() const { |
79 | 67.6M | return getAsVectorAndHasExternal().getPointer(); |
80 | 67.6M | } |
81 | | |
82 | 7.45M | bool hasExternalDecls() const { |
83 | 7.45M | return getAsVectorAndHasExternal().getInt(); |
84 | 7.45M | } |
85 | | |
86 | 2.77M | void setHasExternalDecls() { |
87 | 2.77M | if (DeclsTy *Vec = getAsVector()) |
88 | 1.46M | Data = DeclsAndHasExternalTy(Vec, true); |
89 | 1.30M | else { |
90 | 1.30M | DeclsTy *VT = new DeclsTy(); |
91 | 1.30M | if (NamedDecl *OldD = getAsDecl()) |
92 | 127k | VT->push_back(OldD); |
93 | 1.30M | Data = DeclsAndHasExternalTy(VT, true); |
94 | 1.30M | } |
95 | 2.77M | } |
96 | | |
97 | 12.9M | void setOnlyValue(NamedDecl *ND) { |
98 | 12.9M | assert(!getAsVector() && "Not inline"); |
99 | 12.9M | Data = ND; |
100 | | // Make sure that Data is a plain NamedDecl* so we can use its address |
101 | | // at getLookupResult. |
102 | 12.9M | assert(*(NamedDecl **)&Data == ND && |
103 | 12.9M | "PointerUnion mangles the NamedDecl pointer!"); |
104 | 12.9M | } |
105 | | |
106 | 28.0k | void remove(NamedDecl *D) { |
107 | 28.0k | assert(!isNull() && "removing from empty list"); |
108 | 28.0k | if (NamedDecl *Singleton = getAsDecl()) { |
109 | 3.76k | assert(Singleton == D && "list is different singleton"); |
110 | 3.76k | (void)Singleton; |
111 | 3.76k | Data = (NamedDecl *)nullptr; |
112 | 3.76k | return; |
113 | 3.76k | } |
114 | | |
115 | 24.2k | DeclsTy &Vec = *getAsVector(); |
116 | 24.2k | DeclsTy::iterator I = llvm::find(Vec, D); |
117 | 24.2k | assert(I != Vec.end() && "list does not contain decl"); |
118 | 24.2k | Vec.erase(I); |
119 | | |
120 | 24.2k | assert(llvm::find(Vec, D) == Vec.end() && "list still contains decl"); |
121 | 24.2k | } |
122 | | |
123 | | /// Remove any declarations which were imported from an external |
124 | | /// AST source. |
125 | 1.71M | void removeExternalDecls() { |
126 | 1.71M | if (isNull()) { |
127 | | // Nothing to do. |
128 | 524k | } else if (NamedDecl *Singleton = getAsDecl()) { |
129 | 6.41k | if (Singleton->isFromASTFile()) |
130 | 21 | *this = StoredDeclsList(); |
131 | 518k | } else { |
132 | 518k | DeclsTy &Vec = *getAsVector(); |
133 | 518k | Vec.erase(std::remove_if(Vec.begin(), Vec.end(), |
134 | 805k | [](Decl *D) { return D->isFromASTFile(); }), |
135 | 518k | Vec.end()); |
136 | | // Don't have any external decls any more. |
137 | 518k | Data = DeclsAndHasExternalTy(&Vec, false); |
138 | 518k | } |
139 | 1.71M | } |
140 | | |
141 | | /// getLookupResult - Return an array of all the decls that this list |
142 | | /// represents. |
143 | 50.2M | DeclContext::lookup_result getLookupResult() { |
144 | 50.2M | if (isNull()) |
145 | 3.57M | return DeclContext::lookup_result(); |
146 | | |
147 | | // If we have a single NamedDecl, return it. |
148 | 46.6M | if (NamedDecl *ND = getAsDecl()) { |
149 | 38.9M | assert(!isNull() && "Empty list isn't allowed"); |
150 | | |
151 | | // Data is a raw pointer to a NamedDecl*, return it. |
152 | 38.9M | return DeclContext::lookup_result(ND); |
153 | 38.9M | } |
154 | | |
155 | 7.72M | assert(getAsVector() && "Must have a vector at this point"); |
156 | 7.72M | DeclsTy &Vector = *getAsVector(); |
157 | | |
158 | | // Otherwise, we have a range result. |
159 | 7.72M | return DeclContext::lookup_result(Vector); |
160 | 7.72M | } |
161 | | |
162 | | /// HandleRedeclaration - If this is a redeclaration of an existing decl, |
163 | | /// replace the old one with D and return true. Otherwise return false. |
164 | 2.93M | bool HandleRedeclaration(NamedDecl *D, bool IsKnownNewer) { |
165 | | // Most decls only have one entry in their list, special case it. |
166 | 2.93M | if (NamedDecl *OldD = getAsDecl()) { |
167 | 1.18M | if (!D->declarationReplaces(OldD, IsKnownNewer)) |
168 | 898k | return false; |
169 | 282k | setOnlyValue(D); |
170 | 282k | return true; |
171 | 282k | } |
172 | | |
173 | | // Determine if this declaration is actually a redeclaration. |
174 | 1.75M | DeclsTy &Vec = *getAsVector(); |
175 | 1.75M | for (DeclsTy::iterator OD = Vec.begin(), ODEnd = Vec.end(); |
176 | 9.64M | OD != ODEnd; ++OD7.88M ) { |
177 | 8.04M | NamedDecl *OldD = *OD; |
178 | 8.04M | if (D->declarationReplaces(OldD, IsKnownNewer)) { |
179 | 155k | *OD = D; |
180 | 155k | return true; |
181 | 155k | } |
182 | 8.04M | } |
183 | | |
184 | 1.60M | return false; |
185 | 1.75M | } |
186 | | |
187 | | /// AddSubsequentDecl - This is called on the second and later decl when it is |
188 | | /// not a redeclaration to merge it into the appropriate place in our list. |
189 | 4.29M | void AddSubsequentDecl(NamedDecl *D) { |
190 | 4.29M | assert(!isNull() && "don't AddSubsequentDecl when we have no decls"); |
191 | | |
192 | | // If this is the second decl added to the list, convert this to vector |
193 | | // form. |
194 | 4.29M | if (NamedDecl *OldD = getAsDecl()) { |
195 | 901k | DeclsTy *VT = new DeclsTy(); |
196 | 901k | VT->push_back(OldD); |
197 | 901k | Data = DeclsAndHasExternalTy(VT, false); |
198 | 901k | } |
199 | | |
200 | 4.29M | DeclsTy &Vec = *getAsVector(); |
201 | | |
202 | | // Using directives end up in a special entry which contains only |
203 | | // other using directives, so all this logic is wasted for them. |
204 | | // But avoiding the logic wastes time in the far-more-common case |
205 | | // that we're *not* adding a new using directive. |
206 | | |
207 | | // Tag declarations always go at the end of the list so that an |
208 | | // iterator which points at the first tag will start a span of |
209 | | // decls that only contains tags. |
210 | 4.29M | if (D->hasTagIdentifierNamespace()) |
211 | 146k | Vec.push_back(D); |
212 | | |
213 | | // Resolved using declarations go at the front of the list so that |
214 | | // they won't show up in other lookup results. Unresolved using |
215 | | // declarations (which are always in IDNS_Using | IDNS_Ordinary) |
216 | | // follow that so that the using declarations will be contiguous. |
217 | 4.15M | else if (D->getIdentifierNamespace() & Decl::IDNS_Using) { |
218 | 7.20k | DeclsTy::iterator I = Vec.begin(); |
219 | 7.20k | if (D->getIdentifierNamespace() != Decl::IDNS_Using) { |
220 | 891 | while (I != Vec.end() && |
221 | 50 | (*I)->getIdentifierNamespace() == Decl::IDNS_Using) |
222 | 1 | ++I; |
223 | 890 | } |
224 | 7.20k | Vec.insert(I, D); |
225 | | |
226 | | // All other declarations go at the end of the list, but before any |
227 | | // tag declarations. But we can be clever about tag declarations |
228 | | // because there can only ever be one in a scope. |
229 | 4.14M | } else if (!Vec.empty() && Vec.back()->hasTagIdentifierNamespace()2.68M ) { |
230 | 34.4k | NamedDecl *TagD = Vec.back(); |
231 | 34.4k | Vec.back() = D; |
232 | 34.4k | Vec.push_back(TagD); |
233 | 34.4k | } else |
234 | 4.11M | Vec.push_back(D); |
235 | 4.29M | } |
236 | | }; |
237 | | |
238 | | class StoredDeclsMap |
239 | | : public llvm::SmallDenseMap<DeclarationName, StoredDeclsList, 4> { |
240 | | public: |
241 | | static void DestroyAll(StoredDeclsMap *Map, bool Dependent); |
242 | | |
243 | | private: |
244 | | friend class ASTContext; // walks the chain deleting these |
245 | | friend class DeclContext; |
246 | | |
247 | | llvm::PointerIntPair<StoredDeclsMap*, 1> Previous; |
248 | | }; |
249 | | |
250 | | class DependentStoredDeclsMap : public StoredDeclsMap { |
251 | | public: |
252 | 422k | DependentStoredDeclsMap() = default; |
253 | | |
254 | | private: |
255 | | friend class DeclContext; // iterates over diagnostics |
256 | | friend class DependentDiagnostic; |
257 | | |
258 | | DependentDiagnostic *FirstDiagnostic = nullptr; |
259 | | }; |
260 | | |
261 | | } // namespace clang |
262 | | |
263 | | #endif // LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H |