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};
60
61bool ASTNodeKind::isBaseOf(ASTNodeKind Other) const {
62 return isBaseOf(Base: KindId, Derived: Other.KindId);
63}
64
65bool ASTNodeKind::isBaseOf(ASTNodeKind Other, unsigned *Distance) const {
66 return isBaseOf(Base: KindId, Derived: Other.KindId, Distance);
67}
68
69bool ASTNodeKind::isBaseOf(NodeKindId Base, NodeKindId Derived) {
70 if (Base == NKI_None || Derived == NKI_None)
71 return false;
72 while (Derived != Base && Derived != NKI_None) {
73 Derived = AllKindInfo[Derived].ParentId;
74 }
75 return Derived == Base;
76}
77
78bool ASTNodeKind::isBaseOf(NodeKindId Base, NodeKindId Derived,
79 unsigned *Distance) {
80 if (Base == NKI_None || Derived == NKI_None) return false;
81 unsigned Dist = 0;
82 while (Derived != Base && Derived != NKI_None) {
83 Derived = AllKindInfo[Derived].ParentId;
84 ++Dist;
85 }
86 if (Distance)
87 *Distance = Dist;
88 return Derived == Base;
89}
90
91ASTNodeKind ASTNodeKind::getCladeKind() const {
92 NodeKindId LastId = KindId;
93 while (LastId) {
94 NodeKindId ParentId = AllKindInfo[LastId].ParentId;
95 if (ParentId == NKI_None)
96 return LastId;
97 LastId = ParentId;
98 }
99 return NKI_None;
100}
101
102StringRef ASTNodeKind::asStringRef() const { return AllKindInfo[KindId].Name; }
103
104ASTNodeKind ASTNodeKind::getMostDerivedType(ASTNodeKind Kind1,
105 ASTNodeKind Kind2) {
106 if (Kind1.isBaseOf(Other: Kind2)) return Kind2;
107 if (Kind2.isBaseOf(Other: Kind1)) return Kind1;
108 return ASTNodeKind();
109}
110
111ASTNodeKind ASTNodeKind::getMostDerivedCommonAncestor(ASTNodeKind Kind1,
112 ASTNodeKind Kind2) {
113 NodeKindId Parent = Kind1.KindId;
114 while (!isBaseOf(Base: Parent, Derived: Kind2.KindId) && Parent != NKI_None) {
115 Parent = AllKindInfo[Parent].ParentId;
116 }
117 return ASTNodeKind(Parent);
118}
119
120ASTNodeKind ASTNodeKind::getFromNode(const Decl &D) {
121 switch (D.getKind()) {
122#define DECL(DERIVED, BASE) \
123 case Decl::DERIVED: return ASTNodeKind(NKI_##DERIVED##Decl);
124#define ABSTRACT_DECL(D)
125#include "clang/AST/DeclNodes.inc"
126 };
127 llvm_unreachable("invalid decl kind");
128}
129
130ASTNodeKind ASTNodeKind::getFromNode(const Stmt &S) {
131 switch (S.getStmtClass()) {
132 case Stmt::NoStmtClass: return NKI_None;
133#define STMT(CLASS, PARENT) \
134 case Stmt::CLASS##Class: return ASTNodeKind(NKI_##CLASS);
135#define ABSTRACT_STMT(S)
136#include "clang/AST/StmtNodes.inc"
137 }
138 llvm_unreachable("invalid stmt kind");
139}
140
141ASTNodeKind ASTNodeKind::getFromNode(const Type &T) {
142 switch (T.getTypeClass()) {
143#define TYPE(Class, Base) \
144 case Type::Class: return ASTNodeKind(NKI_##Class##Type);
145#define ABSTRACT_TYPE(Class, Base)
146#include "clang/AST/TypeNodes.inc"
147 }
148 llvm_unreachable("invalid type kind");
149 }
150
151 ASTNodeKind ASTNodeKind::getFromNode(const TypeLoc &T) {
152 switch (T.getTypeLocClass()) {
153#define ABSTRACT_TYPELOC(CLASS, PARENT)
154#define TYPELOC(CLASS, PARENT) \
155 case TypeLoc::CLASS: \
156 return ASTNodeKind(NKI_##CLASS##TypeLoc);
157#include "clang/AST/TypeLocNodes.def"
158 }
159 llvm_unreachable("invalid typeloc kind");
160 }
161
162ASTNodeKind ASTNodeKind::getFromNode(const OMPClause &C) {
163 switch (C.getClauseKind()) {
164#define GEN_CLANG_CLAUSE_CLASS
165#define CLAUSE_CLASS(Enum, Str, Class) \
166 case llvm::omp::Clause::Enum: \
167 return ASTNodeKind(NKI_##Class);
168#define CLAUSE_NO_CLASS(Enum, Str) \
169 case llvm::omp::Clause::Enum: \
170 llvm_unreachable("unexpected OpenMP clause kind");
171#include "llvm/Frontend/OpenMP/OMP.inc"
172 }
173 llvm_unreachable("invalid omp clause kind");
174}
175
176ASTNodeKind ASTNodeKind::getFromNode(const Attr &A) {
177 switch (A.getKind()) {
178#define ATTR(A) \
179 case attr::A: \
180 return ASTNodeKind(NKI_##A##Attr);
181#include "clang/Basic/AttrList.inc"
182 }
183 llvm_unreachable("invalid attr kind");
184}
185
186void DynTypedNode::print(llvm::raw_ostream &OS,
187 const PrintingPolicy &PP) const {
188 if (const TemplateArgument *TA = get<TemplateArgument>())
189 TA->print(Policy: PP, Out&: OS, /*IncludeType*/ true);
190 else if (const TemplateArgumentLoc *TAL = get<TemplateArgumentLoc>())
191 TAL->getArgument().print(Policy: PP, Out&: OS, /*IncludeType*/ true);
192 else if (const TemplateName *TN = get<TemplateName>())
193 TN->print(OS, Policy: PP);
194 else if (const NestedNameSpecifier *NNS = get<NestedNameSpecifier>())
195 NNS->print(OS, Policy: PP);
196 else if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>()) {
197 if (const NestedNameSpecifier *NNS = NNSL->getNestedNameSpecifier())
198 NNS->print(OS, Policy: PP);
199 else
200 OS << "(empty NestedNameSpecifierLoc)";
201 } else if (const QualType *QT = get<QualType>())
202 QT->print(OS, Policy: PP);
203 else if (const TypeLoc *TL = get<TypeLoc>())
204 TL->getType().print(OS, Policy: PP);
205 else if (const Decl *D = get<Decl>())
206 D->print(Out&: OS, Policy: PP);
207 else if (const Stmt *S = get<Stmt>())
208 S->printPretty(OS, Helper: nullptr, Policy: PP);
209 else if (const Type *T = get<Type>())
210 QualType(T, 0).print(OS, Policy: PP);
211 else if (const Attr *A = get<Attr>())
212 A->printPretty(OS, Policy: PP);
213 else if (const ObjCProtocolLoc *P = get<ObjCProtocolLoc>())
214 P->getProtocol()->print(Out&: OS, Policy: PP);
215 else if (const ConceptReference *C = get<ConceptReference>())
216 C->print(OS, Policy: PP);
217 else
218 OS << "Unable to print values of type " << NodeKind.asStringRef() << "\n";
219}
220
221void DynTypedNode::dump(llvm::raw_ostream &OS,
222 const ASTContext &Context) const {
223 if (const Decl *D = get<Decl>())
224 D->dump(Out&: OS);
225 else if (const Stmt *S = get<Stmt>())
226 S->dump(OS, Context);
227 else if (const Type *T = get<Type>())
228 T->dump(OS, Context);
229 else if (const ConceptReference *C = get<ConceptReference>())
230 C->dump(OS);
231 else if (const TypeLoc *TL = get<TypeLoc>())
232 TL->dump(OS, Context);
233 else
234 OS << "Unable to dump values of type " << NodeKind.asStringRef() << "\n";
235}
236
237SourceRange DynTypedNode::getSourceRange() const {
238 if (const CXXCtorInitializer *CCI = get<CXXCtorInitializer>())
239 return CCI->getSourceRange();
240 if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>())
241 return NNSL->getSourceRange();
242 if (const TypeLoc *TL = get<TypeLoc>())
243 return TL->getSourceRange();
244 if (const Decl *D = get<Decl>())
245 return D->getSourceRange();
246 if (const Stmt *S = get<Stmt>())
247 return S->getSourceRange();
248 if (const TemplateArgumentLoc *TAL = get<TemplateArgumentLoc>())
249 return TAL->getSourceRange();
250 if (const auto *C = get<OMPClause>())
251 return SourceRange(C->getBeginLoc(), C->getEndLoc());
252 if (const auto *CBS = get<CXXBaseSpecifier>())
253 return CBS->getSourceRange();
254 if (const auto *A = get<Attr>())
255 return A->getRange();
256 if (const ObjCProtocolLoc *P = get<ObjCProtocolLoc>())
257 return P->getSourceRange();
258 if (const ConceptReference *C = get<ConceptReference>())
259 return C->getSourceRange();
260 return SourceRange();
261}
262