forked from OSchip/llvm-project
Update `DynTypedNode` to support the conversion of `TypeLoc`s.
This provides better support for `TypeLoc`s to allow `TypeLoc`-related matchers to feature stricter typing and to avoid relying on the dynamic casting of `TypeLoc`s in matchers. Reviewed By: ymandel, tdl-g, sbenza Differential Revision: https://reviews.llvm.org/D110586
This commit is contained in:
parent
dafcbfdaa0
commit
56e72a40c1
|
@ -63,6 +63,7 @@ public:
|
|||
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 @@ private:
|
|||
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(TemplateName)
|
|||
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 @@ public:
|
|||
return getUnchecked<QualType>().getAsOpaquePtr() <
|
||||
Other.getUnchecked<QualType>().getAsOpaquePtr();
|
||||
|
||||
if (ASTNodeKind::getFromNodeKind<TypeLoc>().isSame(NodeKind)) {
|
||||
if (ASTNodeKind::getFromNodeKind<TypeLoc>().isBaseOf(NodeKind)) {
|
||||
auto TLA = getUnchecked<TypeLoc>();
|
||||
auto TLB = Other.getUnchecked<TypeLoc>();
|
||||
return std::make_pair(TLA.getType().getAsOpaquePtr(),
|
||||
|
@ -336,7 +341,7 @@ public:
|
|||
if (ASTNodeKind::getFromNodeKind<QualType>().isSame(NodeKind))
|
||||
return getUnchecked<QualType>() == Other.getUnchecked<QualType>();
|
||||
|
||||
if (ASTNodeKind::getFromNodeKind<TypeLoc>().isSame(NodeKind))
|
||||
if (ASTNodeKind::getFromNodeKind<TypeLoc>().isBaseOf(NodeKind))
|
||||
return getUnchecked<TypeLoc>() == Other.getUnchecked<TypeLoc>();
|
||||
|
||||
if (ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>().isSame(NodeKind))
|
||||
|
@ -365,7 +370,7 @@ public:
|
|||
}
|
||||
static unsigned getHashValue(const DynTypedNode &Val) {
|
||||
// FIXME: Add hashing support for the remaining types.
|
||||
if (ASTNodeKind::getFromNodeKind<TypeLoc>().isSame(Val.NodeKind)) {
|
||||
if (ASTNodeKind::getFromNodeKind<TypeLoc>().isBaseOf(Val.NodeKind)) {
|
||||
auto TL = Val.getUnchecked<TypeLoc>();
|
||||
return llvm::hash_combine(TL.getType().getAsOpaquePtr(),
|
||||
TL.getOpaqueData());
|
||||
|
@ -455,6 +460,29 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
/// 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 <typename T, typename BaseT,
|
||||
typename = std::enable_if_t<(sizeof(T) == sizeof(BaseT))>>
|
||||
struct DynCastValueConverter {
|
||||
static const T *get(ASTNodeKind NodeKind, const void *Storage) {
|
||||
if (ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind))
|
||||
return &getUnchecked(NodeKind, Storage);
|
||||
return nullptr;
|
||||
}
|
||||
static const T &getUnchecked(ASTNodeKind NodeKind, const void *Storage) {
|
||||
assert(ASTNodeKind::getFromNodeKind<T>().isBaseOf(NodeKind));
|
||||
return *static_cast<const T *>(reinterpret_cast<const BaseT *>(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 @@ template <>
|
|||
struct DynTypedNode::BaseConverter<QualType,
|
||||
void> : public ValueConverter<QualType> {};
|
||||
|
||||
template <>
|
||||
template <typename T>
|
||||
struct DynTypedNode::BaseConverter<
|
||||
TypeLoc, void> : public ValueConverter<TypeLoc> {};
|
||||
T, std::enable_if_t<std::is_base_of<TypeLoc, T>::value>>
|
||||
: public DynCastValueConverter<T, TypeLoc> {};
|
||||
|
||||
template <>
|
||||
struct DynTypedNode::BaseConverter<CXXBaseSpecifier, void>
|
||||
|
|
|
@ -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 @@ const ASTNodeKind::KindInfo ASTNodeKind::AllKindInfo[] = {
|
|||
{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 @@ ASTNodeKind ASTNodeKind::getFromNode(const Type &T) {
|
|||
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
|
||||
|
|
|
@ -199,5 +199,41 @@ TEST(DynTypedNode, QualType) {
|
|||
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<TypeLoc>("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<TypeLoc>("ptl");
|
||||
DynTypedNode TypeLocNode = DynTypedNode::create(tl);
|
||||
EXPECT_TRUE(TypeLocNode == TypeLocNode);
|
||||
EXPECT_FALSE(TypeLocNode < TypeLocNode);
|
||||
|
||||
const auto &ptl = *matches[0].getNodeAs<PointerTypeLoc>("ptl");
|
||||
EXPECT_EQ(&tl, &ptl);
|
||||
DynTypedNode PointerTypeLocNode = DynTypedNode::create(ptl);
|
||||
EXPECT_TRUE(PointerTypeLocNode == PointerTypeLocNode);
|
||||
EXPECT_FALSE(PointerTypeLocNode < PointerTypeLocNode);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace clang
|
||||
|
|
Loading…
Reference in New Issue