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