284 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// Provides a dynamic type identifier and a dynamically typed node container10// that can be used to store an AST base node at runtime in the same storage in11// 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_CLASS52#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_CLASS165#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 (NestedNameSpecifier NNS = NNSL->getNestedNameSpecifier())198 NNS.print(OS, PP);199 else200 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 else218 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 if (const TypeLoc *TL = get<TypeLoc>())232 TL->dump(OS, Context);233 else234 OS << "Unable to dump values of type " << NodeKind.asStringRef() << "\n";235}236 237SourceRange DynTypedNode::getSourceRange(bool IncludeQualifier) 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 if (IncludeQualifier)244 return TL->getSourceRange();245 switch (TL->getTypeLocClass()) {246 case TypeLoc::DependentName:247 return TL->castAs<DependentNameTypeLoc>().getNameLoc();248 case TypeLoc::TemplateSpecialization: {249 auto T = TL->castAs<TemplateSpecializationTypeLoc>();250 return SourceRange(T.getTemplateNameLoc(), T.getEndLoc());251 }252 case TypeLoc::Enum:253 case TypeLoc::Record:254 case TypeLoc::InjectedClassName:255 return TL->castAs<TagTypeLoc>().getNameLoc();256 case TypeLoc::Typedef:257 return TL->castAs<TypedefTypeLoc>().getNameLoc();258 case TypeLoc::UnresolvedUsing:259 return TL->castAs<UnresolvedUsingTypeLoc>().getNameLoc();260 case TypeLoc::Using:261 return TL->castAs<UsingTypeLoc>().getNameLoc();262 default:263 return TL->getSourceRange();264 }265 }266 if (const Decl *D = get<Decl>())267 return D->getSourceRange();268 if (const Stmt *S = get<Stmt>())269 return S->getSourceRange();270 if (const TemplateArgumentLoc *TAL = get<TemplateArgumentLoc>())271 return TAL->getSourceRange();272 if (const auto *C = get<OMPClause>())273 return SourceRange(C->getBeginLoc(), C->getEndLoc());274 if (const auto *CBS = get<CXXBaseSpecifier>())275 return CBS->getSourceRange();276 if (const auto *A = get<Attr>())277 return A->getRange();278 if (const ObjCProtocolLoc *P = get<ObjCProtocolLoc>())279 return P->getSourceRange();280 if (const ConceptReference *C = get<ConceptReference>())281 return C->getSourceRange();282 return SourceRange();283}284