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
22namespace clang {
23
24auto 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
58NestedNameSpecifier::NestedNameSpecifier(const Type *T)
59 : NestedNameSpecifier({.SK: StoredKind::Type, .Ptr: T}) {
60 assert(getKind() == Kind::Type);
61}
62
63auto 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.
82NestedNameSpecifier::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.
91NestedNameSpecifier::NestedNameSpecifier(CXXRecordDecl *RD)
92 : NestedNameSpecifier({.SK: StoredKind::NamespaceOrSuper, .Ptr: RD}) {
93 assert(getKind() == Kind::MicrosoftSuper);
94}
95
96CXXRecordDecl *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
110NestedNameSpecifier 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
131bool NestedNameSpecifier::isCanonical() const {
132 return *this == getCanonical();
133}
134
135TypeLoc NestedNameSpecifierLoc::castAsTypeLoc() const {
136 return TypeLoc(Qualifier.getAsType(), LoadPointer(/*Offset=*/Offset: 0));
137}
138
139TypeLoc NestedNameSpecifierLoc::getAsTypeLoc() const {
140 if (Qualifier.getKind() != NestedNameSpecifier::Kind::Type)
141 return TypeLoc();
142 return castAsTypeLoc();
143}
144
145unsigned
146NestedNameSpecifierLoc::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
174NamespaceAndPrefixLoc NestedNameSpecifierLoc::castAsNamespaceAndPrefix() const {
175 auto [Namespace, Prefix] = Qualifier.getAsNamespaceAndPrefix();
176 return {.Namespace: Namespace, .Prefix: NestedNameSpecifierLoc(Prefix, Data)};
177}
178
179NamespaceAndPrefixLoc NestedNameSpecifierLoc::getAsNamespaceAndPrefix() const {
180 if (Qualifier.getKind() != NestedNameSpecifier::Kind::Namespace)
181 return {};
182 return castAsNamespaceAndPrefix();
183}
184
185unsigned 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
195unsigned NestedNameSpecifierLoc::getDataLength() const {
196 return getDataLength(Qualifier);
197}
198
199SourceRange 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
227SourceRange NestedNameSpecifierLoc::getSourceRange() const {
228 return SourceRange(getBeginLoc(), getEndLoc());
229}
230
231SourceLocation 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.
237SourceLocation 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.
243SourceLocation NestedNameSpecifierLoc::getLocalEndLoc() const {
244 return getLocalSourceRange().getEnd();
245}
246
247SourceRange NestedNameSpecifierLocBuilder::getSourceRange() const {
248 return NestedNameSpecifierLoc(Representation, Buffer).getSourceRange();
249}
250
251} // namespace clang
252
253namespace llvm {
254
255template <> 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
267template <> 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