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    {NKI_None, "<None>"},
29    {NKI_None, "TemplateArgument"},
30    {NKI_None, "TemplateArgumentLoc"},
31    {NKI_None, "LambdaCapture"},
32    {NKI_None, "TemplateName"},
33    {NKI_None, "NestedNameSpecifierLoc"},
34    {NKI_None, "QualType"},
35#define TYPELOC(CLASS, PARENT) {NKI_##PARENT, #CLASS "TypeLoc"},
36#include "clang/AST/TypeLocNodes.def"
37    {NKI_None, "TypeLoc"},
38    {NKI_None, "CXXBaseSpecifier"},
39    {NKI_None, "CXXCtorInitializer"},
40    {NKI_None, "NestedNameSpecifier"},
41    {NKI_None, "Decl"},
42#define DECL(DERIVED, BASE) { NKI_##BASE, #DERIVED "Decl" },
43#include "clang/AST/DeclNodes.inc"
44    {NKI_None, "Stmt"},
45#define STMT(DERIVED, BASE) { NKI_##BASE, #DERIVED },
46#include "clang/AST/StmtNodes.inc"
47    {NKI_None, "Type"},
48#define TYPE(DERIVED, BASE) { NKI_##BASE, #DERIVED "Type" },
49#include "clang/AST/TypeNodes.inc"
50    {NKI_None, "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    {NKI_None, "Attr"},
55#define ATTR(A) {NKI_Attr, #A "Attr"},
56#include "clang/Basic/AttrList.inc"
57    {NKI_None, "ObjCProtocolLoc"},
58    {NKI_None, "ConceptReference"},
59};
60
61bool ASTNodeKind::isBaseOf(ASTNodeKind Other) const {
62  return isBaseOf(KindId, Other.KindId);
63}
64
65bool ASTNodeKind::isBaseOf(ASTNodeKind Other, unsigned *Distance) const {
66  return isBaseOf(KindId, 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(Kind2)) return Kind2;
107  if (Kind2.isBaseOf(Kind1)) return Kind1;
108  return ASTNodeKind();
109}
110
111ASTNodeKind ASTNodeKind::getMostDerivedCommonAncestor(ASTNodeKind Kind1,
112                                                      ASTNodeKind Kind2) {
113  NodeKindId Parent = Kind1.KindId;
114  while (!isBaseOf(Parent, 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(PP, OS, /*IncludeType*/ true);
190  else if (const TemplateArgumentLoc *TAL = get<TemplateArgumentLoc>())
191    TAL->getArgument().print(PP, OS, /*IncludeType*/ true);
192  else if (const TemplateName *TN = get<TemplateName>())
193    TN->print(OS, PP);
194  else if (const NestedNameSpecifier *NNS = get<NestedNameSpecifier>())
195    NNS->print(OS, PP);
196  else if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>()) {
197    if (const NestedNameSpecifier *NNS = NNSL->getNestedNameSpecifier())
198      NNS->print(OS, PP);
199    else
200      OS << "(empty NestedNameSpecifierLoc)";
201  } else if (const QualType *QT = get<QualType>())
202    QT->print(OS, PP);
203  else if (const TypeLoc *TL = get<TypeLoc>())
204    TL->getType().print(OS, PP);
205  else if (const Decl *D = get<Decl>())
206    D->print(OS, PP);
207  else if (const Stmt *S = get<Stmt>())
208    S->printPretty(OS, nullptr, PP);
209  else if (const Type *T = get<Type>())
210    QualType(T, 0).print(OS, PP);
211  else if (const Attr *A = get<Attr>())
212    A->printPretty(OS, 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, 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(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
232    OS << "Unable to dump values of type " << NodeKind.asStringRef() << "\n";
233}
234
235SourceRange DynTypedNode::getSourceRange() const {
236  if (const CXXCtorInitializer *CCI = get<CXXCtorInitializer>())
237    return CCI->getSourceRange();
238  if (const NestedNameSpecifierLoc *NNSL = get<NestedNameSpecifierLoc>())
239    return NNSL->getSourceRange();
240  if (const TypeLoc *TL = get<TypeLoc>())
241    return TL->getSourceRange();
242  if (const Decl *D = get<Decl>())
243    return D->getSourceRange();
244  if (const Stmt *S = get<Stmt>())
245    return S->getSourceRange();
246  if (const TemplateArgumentLoc *TAL = get<TemplateArgumentLoc>())
247    return TAL->getSourceRange();
248  if (const auto *C = get<OMPClause>())
249    return SourceRange(C->getBeginLoc(), C->getEndLoc());
250  if (const auto *CBS = get<CXXBaseSpecifier>())
251    return CBS->getSourceRange();
252  if (const auto *A = get<Attr>())
253    return A->getRange();
254  if (const ObjCProtocolLoc *P = get<ObjCProtocolLoc>())
255    return P->getSourceRange();
256  if (const ConceptReference *C = get<ConceptReference>())
257    return C->getSourceRange();
258  return SourceRange();
259}
260