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