1//===--- ASTTypeTraits.cpp --------------------------------------*- 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// Provides a dynamic type identifier and a dynamically typed node container
10// that can be used to store an AST base node at runtime in the same storage in
11// a type safe way.
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/AST/ASTTypeTraits.h"
16#include "clang/AST/ASTConcept.h"
17#include "clang/AST/ASTContext.h"
18#include "clang/AST/Attr.h"
19#include "clang/AST/DeclCXX.h"
20#include "clang/AST/DeclObjC.h"
21#include "clang/AST/NestedNameSpecifier.h"
22#include "clang/AST/OpenMPClause.h"
23#include "clang/AST/TypeLoc.h"
24
25using namespace clang;
26
27const ASTNodeKind::KindInfo ASTNodeKind::AllKindInfo[] = {
28 {.ParentId: NKI_None, .Name: "<None>"},
29 {.ParentId: NKI_None, .Name: "TemplateArgument"},
30 {.ParentId: NKI_None, .Name: "TemplateArgumentLoc"},
31 {.ParentId: NKI_None, .Name: "LambdaCapture"},
32 {.ParentId: NKI_None, .Name: "TemplateName"},
33 {.ParentId: NKI_None, .Name: "NestedNameSpecifierLoc"},
34 {.ParentId: NKI_None, .Name: "QualType"},
35#define TYPELOC(CLASS, PARENT) {NKI_##PARENT, #CLASS "TypeLoc"},
36#include "clang/AST/TypeLocNodes.def"
37 {.ParentId: NKI_None, .Name: "TypeLoc"},
38 {.ParentId: NKI_None, .Name: "CXXBaseSpecifier"},
39 {.ParentId: NKI_None, .Name: "CXXCtorInitializer"},
40 {.ParentId: NKI_None, .Name: "NestedNameSpecifier"},
41 {.ParentId: NKI_None, .Name: "Decl"},
42#define DECL(DERIVED, BASE) { NKI_##BASE, #DERIVED "Decl" },
43#include "clang/AST/DeclNodes.inc"
44 {.ParentId: NKI_None, .Name: "Stmt"},
45#define STMT(DERIVED, BASE) { NKI_##BASE, #DERIVED },
46#include "clang/AST/StmtNodes.inc"
47 {.ParentId: NKI_None, .Name: "Type"},
48#define TYPE(DERIVED, BASE) { NKI_##BASE, #DERIVED "Type" },
49#include "clang/AST/TypeNodes.inc"
50 {.ParentId: NKI_None, .Name: "OMPClause"},
51#define GEN_CLANG_CLAUSE_CLASS
52#define CLAUSE_CLASS(Enum, Str, Class) {NKI_OMPClause, #Class},
53#include "llvm/Frontend/OpenMP/OMP.inc"
54 {.ParentId: NKI_None, .Name: "Attr"},
55#define ATTR(A) {NKI_Attr, #A "Attr"},
56#include "clang/Basic/AttrList.inc"
57 {.ParentId: NKI_None, .Name: "ObjCProtocolLoc"},
58 {.ParentId: NKI_None, .Name: "ConceptReference"},
59 {.ParentId: NKI_None, .Name: "OffsetOfNode"},
60};
61
62bool ASTNodeKind::isBaseOf(ASTNodeKind Other) const {
63 return isBaseOf(Base: KindId, Derived: Other.KindId);
64}
65
66bool ASTNodeKind::isBaseOf(ASTNodeKind Other, unsigned *Distance) const {
67 return isBaseOf(Base: KindId, Derived: Other.KindId, Distance);
68}
69
70bool ASTNodeKind::isBaseOf(NodeKindId Base, NodeKindId Derived) {
71 if (Base == NKI_None || Derived == NKI_None)
72 return false;
73 while (Derived != Base && Derived != NKI_None) {
74 Derived = AllKindInfo[Derived].ParentId;
75 }
76 return Derived == Base;
77}
78
79bool ASTNodeKind::isBaseOf(NodeKindId Base, NodeKindId Derived,
80 unsigned *Distance) {
81 if (Base == NKI_None || Derived == NKI_None) return false;
82 unsigned Dist = 0;
83 while (Derived != Base && Derived != NKI_None) {
84 Derived = AllKindInfo[Derived].ParentId;
85 ++Dist;
86 }
87 if (Distance)
88 *Distance = Dist;
89 return Derived == Base;
90}
91
92ASTNodeKind ASTNodeKind::getCladeKind() const {
93 NodeKindId LastId = KindId;
94 while (LastId) {
95 NodeKindId ParentId = AllKindInfo[LastId].ParentId;
96 if (ParentId == NKI_None)
97 return LastId;
98 LastId = ParentId;
99 }
100 return NKI_None;
101}
102
103StringRef ASTNodeKind::asStringRef() const { return AllKindInfo[KindId].Name; }
104
105ASTNodeKind ASTNodeKind::getMostDerivedType(ASTNodeKind Kind1,
106 ASTNodeKind Kind2) {
107 if (Kind1.isBaseOf(Other: Kind2)) return Kind2;
108 if (Kind2.isBaseOf(Other: Kind1)) return Kind1;
109 return ASTNodeKind();
110}
111
112ASTNodeKind ASTNodeKind::getMostDerivedCommonAncestor(ASTNodeKind Kind1,
113 ASTNodeKind Kind2) {
114 NodeKindId Parent = Kind1.KindId;
115 while (!isBaseOf(Base: Parent, Derived: Kind2.KindId) && Parent != NKI_None) {
116 Parent = AllKindInfo[Parent].ParentId;
117 }
118 return ASTNodeKind(Parent);
119}
120
121ASTNodeKind ASTNodeKind::getFromNode(const Decl &D) {
122 switch (D.getKind()) {
123#define DECL(DERIVED, BASE) \
124 case Decl::DERIVED: return ASTNodeKind(NKI_##DERIVED##Decl);
125#define ABSTRACT_DECL(D)
126#include "clang/AST/DeclNodes.inc"
127 };
128 llvm_unreachable("invalid decl kind");
129}
130
131ASTNodeKind ASTNodeKind::getFromNode(const Stmt &S) {
132 switch (S.getStmtClass()) {
133 case Stmt::NoStmtClass: return NKI_None;
134#define STMT(CLASS, PARENT) \
135 case Stmt::CLASS##Class: return ASTNodeKind(NKI_##CLASS);
136#define ABSTRACT_STMT(S)
137#include "clang/AST/StmtNodes.inc"
138 }
139 llvm_unreachable("invalid stmt kind");
140}
141
142ASTNodeKind ASTNodeKind::getFromNode(const Type &T) {
143 switch (T.getTypeClass()) {
144#define TYPE(Class, Base) \
145 case Type::Class: return ASTNodeKind(NKI_##Class##Type);
146#define ABSTRACT_TYPE(Class, Base)
147#include "clang/AST/TypeNodes.inc"
148 }
149 llvm_unreachable("invalid type kind");
150 }
151
152 ASTNodeKind ASTNodeKind::getFromNode(const TypeLoc &T) {
153 switch (T.getTypeLocClass()) {
154#define ABSTRACT_TYPELOC(CLASS, PARENT)
155#define TYPELOC(CLASS, PARENT) \
156 case TypeLoc::CLASS: \
157 return ASTNodeKind(NKI_##CLASS##TypeLoc);
158#include "clang/AST/TypeLocNodes.def"
159 }
160 llvm_unreachable("invalid typeloc kind");
161 }
162
163ASTNodeKind ASTNodeKind::getFromNode(const OMPClause &C) {
164 switch (C.getClauseKind()) {
165#define GEN_CLANG_CLAUSE_CLASS
166#define CLAUSE_CLASS(Enum, Str, Class) \
167 case llvm::omp::Clause::Enum: \
168 return ASTNodeKind(NKI_##Class);
169#define CLAUSE_NO_CLASS(Enum, Str) \
170 case llvm::omp::Clause::Enum: \
171 llvm_unreachable("unexpected OpenMP clause kind");
172#include "llvm/Frontend/OpenMP/OMP.inc"
173 }
174 llvm_unreachable("invalid omp clause kind");
175}
176
177ASTNodeKind ASTNodeKind::getFromNode(const Attr &A) {
178 switch (A.getKind()) {
179#define ATTR(A) \
180 case attr::A: \
181 return ASTNodeKind(NKI_##A##Attr);
182#include "clang/Basic/AttrList.inc"
183 }
184 llvm_unreachable("invalid attr kind");
185}
186
187void DynTypedNode::print(llvm::raw_ostream &OS,
188 const PrintingPolicy &PP) const {
189 if (const TemplateArgument *TA = get<TemplateArgument>())
190 TA->print(Policy: PP, Out&: OS, /*IncludeType*/ true);
191 else if (const TemplateArgumentLoc *TAL = get<TemplateArgumentLoc>())
192 TAL->getArgument().print(Policy: PP, Out&: OS, /*IncludeType*/ true);
193 else if (const TemplateName *TN = get<TemplateName>())
194 TN->print(OS, Policy: PP);
195 else if (const NestedNameSpecifier *NNS = get<NestedNameSpecifier>())
196 NNS->print(OS, Policy: PP);
197 else if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>()) {
198 if (NestedNameSpecifier NNS = NNSL->getNestedNameSpecifier())
199 NNS.print(OS, Policy: PP);
200 else
201 OS << "(empty NestedNameSpecifierLoc)";
202 } else if (const QualType *QT = get<QualType>())
203 QT->print(OS, Policy: PP);
204 else if (const TypeLoc *TL = get<TypeLoc>())
205 TL->getType().print(OS, Policy: PP);
206 else if (const Decl *D = get<Decl>())
207 D->print(Out&: OS, Policy: PP);
208 else if (const Stmt *S = get<Stmt>())
209 S->printPretty(OS, Helper: nullptr, Policy: PP);
210 else if (const Type *T = get<Type>())
211 QualType(T, 0).print(OS, Policy: PP);
212 else if (const Attr *A = get<Attr>())
213 A->printPretty(OS, Policy: PP);
214 else if (const ObjCProtocolLoc *P = get<ObjCProtocolLoc>())
215 P->getProtocol()->print(Out&: OS, Policy: PP);
216 else if (const ConceptReference *C = get<ConceptReference>())
217 C->print(OS, Policy: PP);
218 else
219 OS << "Unable to print values of type " << NodeKind.asStringRef() << "\n";
220}
221
222void DynTypedNode::dump(llvm::raw_ostream &OS,
223 const ASTContext &Context) const {
224 if (const Decl *D = get<Decl>())
225 D->dump(Out&: OS);
226 else if (const Stmt *S = get<Stmt>())
227 S->dump(OS, Context);
228 else if (const Type *T = get<Type>())
229 T->dump(OS, Context);
230 else if (const ConceptReference *C = get<ConceptReference>())
231 C->dump(OS);
232 else if (const TypeLoc *TL = get<TypeLoc>())
233 TL->dump(OS, Context);
234 else
235 OS << "Unable to dump values of type " << NodeKind.asStringRef() << "\n";
236}
237
238SourceRange DynTypedNode::getSourceRange(bool IncludeQualifier) const {
239 if (const CXXCtorInitializer *CCI = get<CXXCtorInitializer>())
240 return CCI->getSourceRange();
241 if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>())
242 return NNSL->getSourceRange();
243 if (const TypeLoc *TL = get<TypeLoc>()) {
244 if (IncludeQualifier)
245 return TL->getSourceRange();
246 switch (TL->getTypeLocClass()) {
247 case TypeLoc::DependentName:
248 return TL->castAs<DependentNameTypeLoc>().getNameLoc();
249 case TypeLoc::TemplateSpecialization: {
250 auto T = TL->castAs<TemplateSpecializationTypeLoc>();
251 return SourceRange(T.getTemplateNameLoc(), T.getEndLoc());
252 }
253 case TypeLoc::Enum:
254 case TypeLoc::Record:
255 case TypeLoc::InjectedClassName:
256 return TL->castAs<TagTypeLoc>().getNameLoc();
257 case TypeLoc::Typedef:
258 return TL->castAs<TypedefTypeLoc>().getNameLoc();
259 case TypeLoc::UnresolvedUsing:
260 return TL->castAs<UnresolvedUsingTypeLoc>().getNameLoc();
261 case TypeLoc::Using:
262 return TL->castAs<UsingTypeLoc>().getNameLoc();
263 default:
264 return TL->getSourceRange();
265 }
266 }
267 if (const Decl *D = get<Decl>())
268 return D->getSourceRange();
269 if (const Stmt *S = get<Stmt>())
270 return S->getSourceRange();
271 if (const TemplateArgumentLoc *TAL = get<TemplateArgumentLoc>())
272 return TAL->getSourceRange();
273 if (const auto *C = get<OMPClause>())
274 return SourceRange(C->getBeginLoc(), C->getEndLoc());
275 if (const auto *CBS = get<CXXBaseSpecifier>())
276 return CBS->getSourceRange();
277 if (const auto *A = get<Attr>())
278 return A->getRange();
279 if (const ObjCProtocolLoc *P = get<ObjCProtocolLoc>())
280 return P->getSourceRange();
281 if (const ConceptReference *C = get<ConceptReference>())
282 return C->getSourceRange();
283 if (const OffsetOfNode *O = get<OffsetOfNode>())
284 return O->getSourceRange();
285 return SourceRange();
286}
287