diff --git a/clang/include/clang/AST/ASTTypeTraits.h b/clang/include/clang/AST/ASTTypeTraits.h --- a/clang/include/clang/AST/ASTTypeTraits.h +++ b/clang/include/clang/AST/ASTTypeTraits.h @@ -63,6 +63,7 @@ static ASTNodeKind getFromNode(const Decl &D); static ASTNodeKind getFromNode(const Stmt &S); static ASTNodeKind getFromNode(const Type &T); + static ASTNodeKind getFromNode(const TypeLoc &T); static ASTNodeKind getFromNode(const OMPClause &C); static ASTNodeKind getFromNode(const Attr &A); /// \} @@ -133,6 +134,8 @@ NKI_TemplateName, NKI_NestedNameSpecifierLoc, NKI_QualType, +#define TYPELOC(CLASS, PARENT) NKI_##CLASS##TypeLoc, +#include "clang/AST/TypeLocNodes.def" NKI_TypeLoc, NKI_LastKindWithoutPointerIdentity = NKI_TypeLoc, NKI_CXXBaseSpecifier, @@ -198,6 +201,8 @@ KIND_TO_KIND_ID(NestedNameSpecifier) KIND_TO_KIND_ID(NestedNameSpecifierLoc) KIND_TO_KIND_ID(QualType) +#define TYPELOC(CLASS, PARENT) KIND_TO_KIND_ID(CLASS##TypeLoc) +#include "clang/AST/TypeLocNodes.def" KIND_TO_KIND_ID(TypeLoc) KIND_TO_KIND_ID(Decl) KIND_TO_KIND_ID(Stmt) @@ -304,7 +309,7 @@ return getUnchecked().getAsOpaquePtr() < Other.getUnchecked().getAsOpaquePtr(); - if (ASTNodeKind::getFromNodeKind().isSame(NodeKind)) { + if (ASTNodeKind::getFromNodeKind().isBaseOf(NodeKind)) { auto TLA = getUnchecked(); auto TLB = Other.getUnchecked(); return std::make_pair(TLA.getType().getAsOpaquePtr(), @@ -336,7 +341,7 @@ if (ASTNodeKind::getFromNodeKind().isSame(NodeKind)) return getUnchecked() == Other.getUnchecked(); - if (ASTNodeKind::getFromNodeKind().isSame(NodeKind)) + if (ASTNodeKind::getFromNodeKind().isBaseOf(NodeKind)) return getUnchecked() == Other.getUnchecked(); if (ASTNodeKind::getFromNodeKind().isSame(NodeKind)) @@ -365,7 +370,7 @@ } static unsigned getHashValue(const DynTypedNode &Val) { // FIXME: Add hashing support for the remaining types. - if (ASTNodeKind::getFromNodeKind().isSame(Val.NodeKind)) { + if (ASTNodeKind::getFromNodeKind().isBaseOf(Val.NodeKind)) { auto TL = Val.getUnchecked(); return llvm::hash_combine(TL.getType().getAsOpaquePtr(), TL.getOpaqueData()); @@ -455,6 +460,29 @@ } }; + /// Converter that stores nodes by value. It must be possible to dynamically + /// cast the stored node within a type hierarchy without breaking (especially + /// through slicing). + template > + struct DynCastValueConverter { + static const T *get(ASTNodeKind NodeKind, const void *Storage) { + if (ASTNodeKind::getFromNodeKind().isBaseOf(NodeKind)) + return &getUnchecked(NodeKind, Storage); + return nullptr; + } + static const T &getUnchecked(ASTNodeKind NodeKind, const void *Storage) { + assert(ASTNodeKind::getFromNodeKind().isBaseOf(NodeKind)); + return *static_cast(reinterpret_cast(Storage)); + } + static DynTypedNode create(const T &Node) { + DynTypedNode Result; + Result.NodeKind = ASTNodeKind::getFromNode(Node); + new (&Result.Storage) T(Node); + return Result; + } + }; + ASTNodeKind NodeKind; /// Stores the data of the node. @@ -525,9 +553,10 @@ struct DynTypedNode::BaseConverter : public ValueConverter {}; -template <> +template struct DynTypedNode::BaseConverter< - TypeLoc, void> : public ValueConverter {}; + T, std::enable_if_t::value>> + : public DynCastValueConverter {}; template <> struct DynTypedNode::BaseConverter diff --git a/clang/lib/AST/ASTTypeTraits.cpp b/clang/lib/AST/ASTTypeTraits.cpp --- a/clang/lib/AST/ASTTypeTraits.cpp +++ b/clang/lib/AST/ASTTypeTraits.cpp @@ -18,6 +18,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/OpenMPClause.h" +#include "clang/AST/TypeLoc.h" using namespace clang; @@ -28,6 +29,8 @@ {NKI_None, "TemplateName"}, {NKI_None, "NestedNameSpecifierLoc"}, {NKI_None, "QualType"}, +#define TYPELOC(CLASS, PARENT) {NKI_##PARENT, #CLASS "TypeLoc"}, +#include "clang/AST/TypeLocNodes.def" {NKI_None, "TypeLoc"}, {NKI_None, "CXXBaseSpecifier"}, {NKI_None, "CXXCtorInitializer"}, @@ -127,6 +130,17 @@ llvm_unreachable("invalid type kind"); } + ASTNodeKind ASTNodeKind::getFromNode(const TypeLoc &T) { + switch (T.getTypeLocClass()) { +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + case TypeLoc::CLASS: \ + return ASTNodeKind(NKI_##CLASS##TypeLoc); +#include "clang/AST/TypeLocNodes.def" + } + llvm_unreachable("invalid typeloc kind"); + } + ASTNodeKind ASTNodeKind::getFromNode(const OMPClause &C) { switch (C.getClauseKind()) { #define GEN_CLANG_CLAUSE_CLASS diff --git a/clang/unittests/AST/ASTTypeTraitsTest.cpp b/clang/unittests/AST/ASTTypeTraitsTest.cpp --- a/clang/unittests/AST/ASTTypeTraitsTest.cpp +++ b/clang/unittests/AST/ASTTypeTraitsTest.cpp @@ -199,5 +199,41 @@ EXPECT_FALSE(Node < Node); } +TEST(DynTypedNode, TypeLoc) { + std::string code = R"cc(void example() { int abc; })cc"; + auto AST = clang::tooling::buildASTFromCode(code); + auto matches = + match(traverse(TK_AsIs, + varDecl(hasName("abc"), hasTypeLoc(typeLoc().bind("tl")))), + AST->getASTContext()); + EXPECT_EQ(matches.size(), 1u); + + const auto &tl = *matches[0].getNodeAs("tl"); + DynTypedNode Node = DynTypedNode::create(tl); + EXPECT_TRUE(Node == Node); + EXPECT_FALSE(Node < Node); +} + +TEST(DynTypedNode, PointerTypeLoc) { + std::string code = R"cc(void example() { int *abc; })cc"; + auto AST = clang::tooling::buildASTFromCode(code); + auto matches = + match(traverse(TK_AsIs, varDecl(hasName("abc"), + hasTypeLoc(typeLoc().bind("ptl")))), + AST->getASTContext()); + EXPECT_EQ(matches.size(), 1u); + + const auto &tl = *matches[0].getNodeAs("ptl"); + DynTypedNode TypeLocNode = DynTypedNode::create(tl); + EXPECT_TRUE(TypeLocNode == TypeLocNode); + EXPECT_FALSE(TypeLocNode < TypeLocNode); + + const auto &ptl = *matches[0].getNodeAs("ptl"); + EXPECT_EQ(&tl, &ptl); + DynTypedNode PointerTypeLocNode = DynTypedNode::create(ptl); + EXPECT_TRUE(PointerTypeLocNode == PointerTypeLocNode); + EXPECT_FALSE(PointerTypeLocNode < PointerTypeLocNode); +} + } // namespace } // namespace clang