| 1 | //===- NestedNameSpecifier.h - C++ nested name specifiers -------*- 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 completes the definition of the NestedNameSpecifier class. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H |
| 14 | #define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H |
| 15 | |
| 16 | #include "clang/AST/Decl.h" |
| 17 | #include "clang/AST/NestedNameSpecifierBase.h" |
| 18 | #include "clang/AST/Type.h" |
| 19 | #include "clang/AST/TypeLoc.h" |
| 20 | #include "llvm/ADT/DenseMapInfo.h" |
| 21 | |
| 22 | namespace clang { |
| 23 | |
| 24 | auto NestedNameSpecifier::getKind() const -> Kind { |
| 25 | if (!isStoredKind()) { |
| 26 | switch (getFlagKind()) { |
| 27 | case FlagKind::Null: |
| 28 | return Kind::Null; |
| 29 | case FlagKind::Global: |
| 30 | return Kind::Global; |
| 31 | case FlagKind::Invalid: |
| 32 | llvm_unreachable("use of invalid NestedNameSpecifier" ); |
| 33 | } |
| 34 | llvm_unreachable("unhandled FlagKind" ); |
| 35 | } |
| 36 | switch (auto [K, Ptr] = getStored(); K) { |
| 37 | case StoredKind::Type: |
| 38 | return Kind::Type; |
| 39 | case StoredKind::NamespaceWithGlobal: |
| 40 | case StoredKind::NamespaceWithNamespace: |
| 41 | return Kind::Namespace; |
| 42 | case StoredKind::NamespaceOrSuper: |
| 43 | switch (static_cast<const Decl *>(Ptr)->getKind()) { |
| 44 | case Decl::Namespace: |
| 45 | case Decl::NamespaceAlias: |
| 46 | return Kind::Namespace; |
| 47 | case Decl::CXXRecord: |
| 48 | case Decl::ClassTemplateSpecialization: |
| 49 | case Decl::ClassTemplatePartialSpecialization: |
| 50 | return Kind::MicrosoftSuper; |
| 51 | default: |
| 52 | llvm_unreachable("unexpected decl kind" ); |
| 53 | } |
| 54 | } |
| 55 | llvm_unreachable("unknown StoredKind" ); |
| 56 | } |
| 57 | |
| 58 | NestedNameSpecifier::NestedNameSpecifier(const Type *T) |
| 59 | : NestedNameSpecifier({.SK: StoredKind::Type, .Ptr: T}) { |
| 60 | assert(getKind() == Kind::Type); |
| 61 | } |
| 62 | |
| 63 | auto NestedNameSpecifier::MakeNamespacePtrKind( |
| 64 | const ASTContext &Ctx, const NamespaceBaseDecl *Namespace, |
| 65 | NestedNameSpecifier Prefix) -> PtrKind { |
| 66 | switch (Prefix.getKind()) { |
| 67 | case Kind::Null: |
| 68 | return {.SK: StoredKind::NamespaceOrSuper, .Ptr: Namespace}; |
| 69 | case Kind::Global: |
| 70 | return {.SK: StoredKind::NamespaceWithGlobal, .Ptr: Namespace}; |
| 71 | case Kind::Namespace: |
| 72 | return {.SK: StoredKind::NamespaceWithNamespace, |
| 73 | .Ptr: MakeNamespaceAndPrefixStorage(Ctx, Namespace, Prefix)}; |
| 74 | case Kind::MicrosoftSuper: |
| 75 | case Kind::Type: |
| 76 | llvm_unreachable("invalid prefix for namespace" ); |
| 77 | } |
| 78 | llvm_unreachable("unhandled kind" ); |
| 79 | } |
| 80 | |
| 81 | /// Builds a nested name specifier that names a namespace. |
| 82 | NestedNameSpecifier::NestedNameSpecifier(const ASTContext &Ctx, |
| 83 | const NamespaceBaseDecl *Namespace, |
| 84 | NestedNameSpecifier Prefix) |
| 85 | : NestedNameSpecifier(MakeNamespacePtrKind(Ctx, Namespace, Prefix)) { |
| 86 | assert(getKind() == Kind::Namespace); |
| 87 | } |
| 88 | |
| 89 | /// Builds a nested name specifier that names a class through microsoft's |
| 90 | /// __super specifier. |
| 91 | NestedNameSpecifier::NestedNameSpecifier(CXXRecordDecl *RD) |
| 92 | : NestedNameSpecifier({.SK: StoredKind::NamespaceOrSuper, .Ptr: RD}) { |
| 93 | assert(getKind() == Kind::MicrosoftSuper); |
| 94 | } |
| 95 | |
| 96 | CXXRecordDecl *NestedNameSpecifier::getAsRecordDecl() const { |
| 97 | switch (getKind()) { |
| 98 | case Kind::MicrosoftSuper: |
| 99 | return getAsMicrosoftSuper(); |
| 100 | case Kind::Type: |
| 101 | return getAsType()->getAsCXXRecordDecl(); |
| 102 | case Kind::Global: |
| 103 | case Kind::Namespace: |
| 104 | case Kind::Null: |
| 105 | return nullptr; |
| 106 | } |
| 107 | llvm_unreachable("Invalid NNS Kind!" ); |
| 108 | } |
| 109 | |
| 110 | NestedNameSpecifier NestedNameSpecifier::getCanonical() const { |
| 111 | switch (getKind()) { |
| 112 | case NestedNameSpecifier::Kind::Null: |
| 113 | case NestedNameSpecifier::Kind::Global: |
| 114 | case NestedNameSpecifier::Kind::MicrosoftSuper: |
| 115 | // These are canonical and unique. |
| 116 | return *this; |
| 117 | case NestedNameSpecifier::Kind::Namespace: { |
| 118 | // A namespace is canonical; build a nested-name-specifier with |
| 119 | // this namespace and no prefix. |
| 120 | const NamespaceBaseDecl *ND = getAsNamespaceAndPrefix().Namespace; |
| 121 | return NestedNameSpecifier( |
| 122 | {.SK: StoredKind::NamespaceOrSuper, .Ptr: ND->getNamespace()->getCanonicalDecl()}); |
| 123 | } |
| 124 | case NestedNameSpecifier::Kind::Type: |
| 125 | return NestedNameSpecifier( |
| 126 | getAsType()->getCanonicalTypeInternal().getTypePtr()); |
| 127 | } |
| 128 | llvm_unreachable("unhandled kind" ); |
| 129 | } |
| 130 | |
| 131 | bool NestedNameSpecifier::isCanonical() const { |
| 132 | return *this == getCanonical(); |
| 133 | } |
| 134 | |
| 135 | TypeLoc NestedNameSpecifierLoc::castAsTypeLoc() const { |
| 136 | return TypeLoc(Qualifier.getAsType(), LoadPointer(/*Offset=*/Offset: 0)); |
| 137 | } |
| 138 | |
| 139 | TypeLoc NestedNameSpecifierLoc::getAsTypeLoc() const { |
| 140 | if (Qualifier.getKind() != NestedNameSpecifier::Kind::Type) |
| 141 | return TypeLoc(); |
| 142 | return castAsTypeLoc(); |
| 143 | } |
| 144 | |
| 145 | unsigned |
| 146 | NestedNameSpecifierLoc::getLocalDataLength(NestedNameSpecifier Qualifier) { |
| 147 | // Location of the trailing '::'. |
| 148 | unsigned Length = sizeof(SourceLocation::UIntTy); |
| 149 | |
| 150 | switch (Qualifier.getKind()) { |
| 151 | case NestedNameSpecifier::Kind::Global: |
| 152 | // Nothing more to add. |
| 153 | break; |
| 154 | |
| 155 | case NestedNameSpecifier::Kind::Namespace: |
| 156 | case NestedNameSpecifier::Kind::MicrosoftSuper: |
| 157 | // The location of the identifier or namespace name. |
| 158 | Length += sizeof(SourceLocation::UIntTy); |
| 159 | break; |
| 160 | |
| 161 | case NestedNameSpecifier::Kind::Type: |
| 162 | // The "void*" that points at the TypeLoc data. |
| 163 | // Note: the 'template' keyword is part of the TypeLoc. |
| 164 | Length += sizeof(void *); |
| 165 | break; |
| 166 | |
| 167 | case NestedNameSpecifier::Kind::Null: |
| 168 | llvm_unreachable("Expected a non-NULL qualifier" ); |
| 169 | } |
| 170 | |
| 171 | return Length; |
| 172 | } |
| 173 | |
| 174 | NamespaceAndPrefixLoc NestedNameSpecifierLoc::castAsNamespaceAndPrefix() const { |
| 175 | auto [Namespace, Prefix] = Qualifier.getAsNamespaceAndPrefix(); |
| 176 | return {.Namespace: Namespace, .Prefix: NestedNameSpecifierLoc(Prefix, Data)}; |
| 177 | } |
| 178 | |
| 179 | NamespaceAndPrefixLoc NestedNameSpecifierLoc::getAsNamespaceAndPrefix() const { |
| 180 | if (Qualifier.getKind() != NestedNameSpecifier::Kind::Namespace) |
| 181 | return {}; |
| 182 | return castAsNamespaceAndPrefix(); |
| 183 | } |
| 184 | |
| 185 | unsigned NestedNameSpecifierLoc::getDataLength(NestedNameSpecifier Qualifier) { |
| 186 | unsigned Length = 0; |
| 187 | for (; Qualifier; Qualifier = Qualifier.getAsNamespaceAndPrefix().Prefix) { |
| 188 | Length += getLocalDataLength(Qualifier); |
| 189 | if (Qualifier.getKind() != NestedNameSpecifier::Kind::Namespace) |
| 190 | break; |
| 191 | } |
| 192 | return Length; |
| 193 | } |
| 194 | |
| 195 | unsigned NestedNameSpecifierLoc::getDataLength() const { |
| 196 | return getDataLength(Qualifier); |
| 197 | } |
| 198 | |
| 199 | SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const { |
| 200 | switch (auto Kind = Qualifier.getKind()) { |
| 201 | case NestedNameSpecifier::Kind::Null: |
| 202 | return SourceRange(); |
| 203 | case NestedNameSpecifier::Kind::Global: |
| 204 | return LoadSourceLocation(/*Offset=*/Offset: 0); |
| 205 | case NestedNameSpecifier::Kind::Namespace: |
| 206 | case NestedNameSpecifier::Kind::MicrosoftSuper: { |
| 207 | unsigned Offset = |
| 208 | Kind == NestedNameSpecifier::Kind::Namespace |
| 209 | ? getDataLength(Qualifier: Qualifier.getAsNamespaceAndPrefix().Prefix) |
| 210 | : 0; |
| 211 | return SourceRange( |
| 212 | LoadSourceLocation(Offset), |
| 213 | LoadSourceLocation(Offset: Offset + sizeof(SourceLocation::UIntTy))); |
| 214 | } |
| 215 | case NestedNameSpecifier::Kind::Type: { |
| 216 | // The "void*" that points at the TypeLoc data. |
| 217 | // Note: the 'template' keyword is part of the TypeLoc. |
| 218 | void *TypeData = LoadPointer(/*Offset=*/Offset: 0); |
| 219 | TypeLoc TL(Qualifier.getAsType(), TypeData); |
| 220 | return SourceRange(TL.getBeginLoc(), LoadSourceLocation(Offset: sizeof(void *))); |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | llvm_unreachable("Invalid NNS Kind!" ); |
| 225 | } |
| 226 | |
| 227 | SourceRange NestedNameSpecifierLoc::getSourceRange() const { |
| 228 | return SourceRange(getBeginLoc(), getEndLoc()); |
| 229 | } |
| 230 | |
| 231 | SourceLocation NestedNameSpecifierLoc::getEndLoc() const { |
| 232 | return getLocalSourceRange().getEnd(); |
| 233 | } |
| 234 | |
| 235 | /// Retrieve the location of the beginning of this |
| 236 | /// component of the nested-name-specifier. |
| 237 | SourceLocation NestedNameSpecifierLoc::getLocalBeginLoc() const { |
| 238 | return getLocalSourceRange().getBegin(); |
| 239 | } |
| 240 | |
| 241 | /// Retrieve the location of the end of this component of the |
| 242 | /// nested-name-specifier. |
| 243 | SourceLocation NestedNameSpecifierLoc::getLocalEndLoc() const { |
| 244 | return getLocalSourceRange().getEnd(); |
| 245 | } |
| 246 | |
| 247 | SourceRange NestedNameSpecifierLocBuilder::getSourceRange() const { |
| 248 | return NestedNameSpecifierLoc(Representation, Buffer).getSourceRange(); |
| 249 | } |
| 250 | |
| 251 | } // namespace clang |
| 252 | |
| 253 | namespace llvm { |
| 254 | |
| 255 | template <> struct DenseMapInfo<clang::NestedNameSpecifier> { |
| 256 | static clang::NestedNameSpecifier getEmptyKey() { return std::nullopt; } |
| 257 | |
| 258 | static clang::NestedNameSpecifier getTombstoneKey() { |
| 259 | return clang::NestedNameSpecifier::getInvalid(); |
| 260 | } |
| 261 | |
| 262 | static unsigned getHashValue(const clang::NestedNameSpecifier &V) { |
| 263 | return hash_combine(args: V.getAsVoidPointer()); |
| 264 | } |
| 265 | }; |
| 266 | |
| 267 | template <> struct DenseMapInfo<clang::NestedNameSpecifierLoc> { |
| 268 | using FirstInfo = DenseMapInfo<clang::NestedNameSpecifier>; |
| 269 | using SecondInfo = DenseMapInfo<void *>; |
| 270 | |
| 271 | static clang::NestedNameSpecifierLoc getEmptyKey() { |
| 272 | return clang::NestedNameSpecifierLoc(FirstInfo::getEmptyKey(), |
| 273 | SecondInfo::getEmptyKey()); |
| 274 | } |
| 275 | |
| 276 | static clang::NestedNameSpecifierLoc getTombstoneKey() { |
| 277 | return clang::NestedNameSpecifierLoc(FirstInfo::getTombstoneKey(), |
| 278 | SecondInfo::getTombstoneKey()); |
| 279 | } |
| 280 | |
| 281 | static unsigned getHashValue(const clang::NestedNameSpecifierLoc &PairVal) { |
| 282 | return hash_combine( |
| 283 | args: FirstInfo::getHashValue(V: PairVal.getNestedNameSpecifier()), |
| 284 | args: SecondInfo::getHashValue(PtrVal: PairVal.getOpaqueData())); |
| 285 | } |
| 286 | |
| 287 | static bool isEqual(const clang::NestedNameSpecifierLoc &LHS, |
| 288 | const clang::NestedNameSpecifierLoc &RHS) { |
| 289 | return LHS == RHS; |
| 290 | } |
| 291 | }; |
| 292 | } // namespace llvm |
| 293 | |
| 294 | #endif // LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H |
| 295 | |