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 | |
25 | using namespace clang; |
26 | |
27 | const 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 | |
61 | bool ASTNodeKind::isBaseOf(ASTNodeKind Other) const { |
62 | return isBaseOf(Base: KindId, Derived: Other.KindId); |
63 | } |
64 | |
65 | bool ASTNodeKind::isBaseOf(ASTNodeKind Other, unsigned *Distance) const { |
66 | return isBaseOf(Base: KindId, Derived: Other.KindId, Distance); |
67 | } |
68 | |
69 | bool 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 | |
78 | bool 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 | |
91 | ASTNodeKind 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 | |
102 | StringRef ASTNodeKind::asStringRef() const { return AllKindInfo[KindId].Name; } |
103 | |
104 | ASTNodeKind 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 | |
111 | ASTNodeKind 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 | |
120 | ASTNodeKind 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 | |
130 | ASTNodeKind 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 | |
141 | ASTNodeKind 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 | |
162 | ASTNodeKind 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 | |
176 | ASTNodeKind 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 | |
186 | void 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(OS, 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 | |
221 | void 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 | |
237 | SourceRange 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 | |