forked from OSchip/llvm-project
[AST] Add introspection support for more base nodes
Fix the logic of detecting pseudo-virtual getBeginLoc etc on Stmt and Decl subclasses. Adjust the test infrastructure to filter out invalid source locations. This makes the tests more clear about which nodes have which locations. Differential Revision: https://reviews.llvm.org/D99231
This commit is contained in:
parent
d2bb3cbbf8
commit
f347f0e0b8
|
@ -23,6 +23,10 @@ namespace clang {
|
||||||
|
|
||||||
class Stmt;
|
class Stmt;
|
||||||
class Decl;
|
class Decl;
|
||||||
|
class CXXCtorInitializer;
|
||||||
|
class NestedNameSpecifierLoc;
|
||||||
|
class TemplateArgumentLoc;
|
||||||
|
class CXXBaseSpecifier;
|
||||||
|
|
||||||
namespace tooling {
|
namespace tooling {
|
||||||
|
|
||||||
|
@ -80,6 +84,10 @@ struct NodeLocationAccessors {
|
||||||
namespace NodeIntrospection {
|
namespace NodeIntrospection {
|
||||||
NodeLocationAccessors GetLocations(clang::Stmt const *Object);
|
NodeLocationAccessors GetLocations(clang::Stmt const *Object);
|
||||||
NodeLocationAccessors GetLocations(clang::Decl const *Object);
|
NodeLocationAccessors GetLocations(clang::Decl const *Object);
|
||||||
|
NodeLocationAccessors GetLocations(clang::CXXCtorInitializer const *Object);
|
||||||
|
NodeLocationAccessors GetLocations(clang::NestedNameSpecifierLoc const *);
|
||||||
|
NodeLocationAccessors GetLocations(clang::TemplateArgumentLoc const *);
|
||||||
|
NodeLocationAccessors GetLocations(clang::CXXBaseSpecifier const *);
|
||||||
NodeLocationAccessors GetLocations(clang::DynTypedNode const &Node);
|
NodeLocationAccessors GetLocations(clang::DynTypedNode const &Node);
|
||||||
} // namespace NodeIntrospection
|
} // namespace NodeIntrospection
|
||||||
} // namespace tooling
|
} // namespace tooling
|
||||||
|
|
|
@ -41,6 +41,22 @@ NodeLocationAccessors NodeIntrospection::GetLocations(clang::Stmt const *) {
|
||||||
NodeLocationAccessors NodeIntrospection::GetLocations(clang::Decl const *) {
|
NodeLocationAccessors NodeIntrospection::GetLocations(clang::Decl const *) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
NodeLocationAccessors NodeIntrospection::GetLocations(
|
||||||
|
clang::CXXCtorInitializer const *) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
NodeLocationAccessors NodeIntrospection::GetLocations(
|
||||||
|
clang::NestedNameSpecifierLoc const*) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
NodeLocationAccessors NodeIntrospection::GetLocations(
|
||||||
|
clang::TemplateArgumentLoc const*) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
NodeLocationAccessors NodeIntrospection::GetLocations(
|
||||||
|
clang::CXXBaseSpecifier const*) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
NodeLocationAccessors
|
NodeLocationAccessors
|
||||||
NodeIntrospection::GetLocations(clang::DynTypedNode const &) {
|
NodeIntrospection::GetLocations(clang::DynTypedNode const &) {
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -26,7 +26,11 @@ ASTSrcLocProcessor::ASTSrcLocProcessor(StringRef JsonPath)
|
||||||
isDefinition(),
|
isDefinition(),
|
||||||
isSameOrDerivedFrom(
|
isSameOrDerivedFrom(
|
||||||
// TODO: Extend this with other clades
|
// TODO: Extend this with other clades
|
||||||
namedDecl(hasAnyName("clang::Stmt", "clang::Decl"))
|
namedDecl(hasAnyName("clang::Stmt", "clang::Decl",
|
||||||
|
"clang::CXXCtorInitializer",
|
||||||
|
"clang::NestedNameSpecifierLoc",
|
||||||
|
"clang::TemplateArgumentLoc",
|
||||||
|
"clang::CXXBaseSpecifier"))
|
||||||
.bind("nodeClade")),
|
.bind("nodeClade")),
|
||||||
optionally(isDerivedFrom(cxxRecordDecl().bind("derivedFrom"))))
|
optionally(isDerivedFrom(cxxRecordDecl().bind("derivedFrom"))))
|
||||||
.bind("className"),
|
.bind("className"),
|
||||||
|
@ -116,22 +120,30 @@ CaptureMethods(std::string TypeString, const clang::CXXRecordDecl *ASTClass,
|
||||||
InnerMatcher...);
|
InnerMatcher...);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto BoundNodesVec =
|
auto BoundNodesVec = match(
|
||||||
match(findAll(publicAccessor(ofClass(equalsNode(ASTClass)),
|
findAll(
|
||||||
returns(asString(TypeString)))
|
publicAccessor(
|
||||||
.bind("classMethod")),
|
ofClass(cxxRecordDecl(
|
||||||
*ASTClass, *Result.Context);
|
equalsNode(ASTClass),
|
||||||
|
optionally(isDerivedFrom(
|
||||||
|
cxxRecordDecl(hasAnyName("clang::Stmt", "clang::Decl"))
|
||||||
|
.bind("stmtOrDeclBase"))))),
|
||||||
|
returns(asString(TypeString)))
|
||||||
|
.bind("classMethod")),
|
||||||
|
*ASTClass, *Result.Context);
|
||||||
|
|
||||||
std::vector<std::string> Methods;
|
std::vector<std::string> Methods;
|
||||||
for (const auto &BN : BoundNodesVec) {
|
for (const auto &BN : BoundNodesVec) {
|
||||||
|
const auto *StmtOrDeclBase =
|
||||||
|
BN.getNodeAs<clang::CXXRecordDecl>("stmtOrDeclBase");
|
||||||
if (const auto *Node = BN.getNodeAs<clang::NamedDecl>("classMethod")) {
|
if (const auto *Node = BN.getNodeAs<clang::NamedDecl>("classMethod")) {
|
||||||
// Only record the getBeginLoc etc on Stmt etc, because it will call
|
// Only record the getBeginLoc etc on Stmt etc, because it will call
|
||||||
// more-derived implementations pseudo-virtually.
|
// more-derived implementations pseudo-virtually.
|
||||||
if ((ASTClass->getName() != "Stmt" && ASTClass->getName() != "Decl") &&
|
if (StmtOrDeclBase &&
|
||||||
(Node->getName() == "getBeginLoc" || Node->getName() == "getEndLoc" ||
|
(Node->getName() == "getBeginLoc" || Node->getName() == "getEndLoc" ||
|
||||||
Node->getName() == "getSourceRange")) {
|
Node->getName() == "getSourceRange"))
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
// Only record the getExprLoc on Expr, because it will call
|
// Only record the getExprLoc on Expr, because it will call
|
||||||
// more-derived implementations pseudo-virtually.
|
// more-derived implementations pseudo-virtually.
|
||||||
if (ASTClass->getName() != "Expr" && Node->getName() == "getExprLoc") {
|
if (ASTClass->getName() != "Expr" && Node->getName() == "getExprLoc") {
|
||||||
|
|
|
@ -180,6 +180,22 @@ NodeLocationAccessors NodeIntrospection::GetLocations(clang::Stmt const *) {
|
||||||
NodeLocationAccessors NodeIntrospection::GetLocations(clang::Decl const *) {
|
NodeLocationAccessors NodeIntrospection::GetLocations(clang::Decl const *) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
NodeLocationAccessors NodeIntrospection::GetLocations(
|
||||||
|
clang::CXXCtorInitializer const *) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
NodeLocationAccessors NodeIntrospection::GetLocations(
|
||||||
|
clang::NestedNameSpecifierLoc const*) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
NodeLocationAccessors NodeIntrospection::GetLocations(
|
||||||
|
clang::TemplateArgumentLoc const*) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
NodeLocationAccessors NodeIntrospection::GetLocations(
|
||||||
|
clang::CXXBaseSpecifier const*) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
NodeLocationAccessors
|
NodeLocationAccessors
|
||||||
NodeIntrospection::GetLocations(clang::DynTypedNode const &) {
|
NodeIntrospection::GetLocations(clang::DynTypedNode const &) {
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -30,7 +30,10 @@ template<typename T, typename MapType>
|
||||||
std::map<std::string, T>
|
std::map<std::string, T>
|
||||||
FormatExpected(const MapType &Accessors) {
|
FormatExpected(const MapType &Accessors) {
|
||||||
std::map<std::string, T> Result;
|
std::map<std::string, T> Result;
|
||||||
llvm::transform(Accessors,
|
llvm::transform(llvm::make_filter_range(Accessors,
|
||||||
|
[](const auto &Accessor) {
|
||||||
|
return Accessor.first.isValid();
|
||||||
|
}),
|
||||||
std::inserter(Result, Result.end()),
|
std::inserter(Result, Result.end()),
|
||||||
[](const auto &Accessor) {
|
[](const auto &Accessor) {
|
||||||
return std::make_pair(
|
return std::make_pair(
|
||||||
|
@ -126,11 +129,9 @@ ns1::ns2::Foo<A, B> ns1::ns2::Bar<T, U>::Nested::method(int i, bool b) const
|
||||||
UnorderedElementsAre(
|
UnorderedElementsAre(
|
||||||
STRING_LOCATION_PAIR(MethodDecl, getBeginLoc()),
|
STRING_LOCATION_PAIR(MethodDecl, getBeginLoc()),
|
||||||
STRING_LOCATION_PAIR(MethodDecl, getBodyRBrace()),
|
STRING_LOCATION_PAIR(MethodDecl, getBodyRBrace()),
|
||||||
STRING_LOCATION_PAIR(MethodDecl, getEllipsisLoc()),
|
|
||||||
STRING_LOCATION_PAIR(MethodDecl, getInnerLocStart()),
|
STRING_LOCATION_PAIR(MethodDecl, getInnerLocStart()),
|
||||||
STRING_LOCATION_PAIR(MethodDecl, getLocation()),
|
STRING_LOCATION_PAIR(MethodDecl, getLocation()),
|
||||||
STRING_LOCATION_PAIR(MethodDecl, getOuterLocStart()),
|
STRING_LOCATION_PAIR(MethodDecl, getOuterLocStart()),
|
||||||
STRING_LOCATION_PAIR(MethodDecl, getPointOfInstantiation()),
|
|
||||||
STRING_LOCATION_PAIR(MethodDecl, getTypeSpecEndLoc()),
|
STRING_LOCATION_PAIR(MethodDecl, getTypeSpecEndLoc()),
|
||||||
STRING_LOCATION_PAIR(MethodDecl, getTypeSpecStartLoc()),
|
STRING_LOCATION_PAIR(MethodDecl, getTypeSpecStartLoc()),
|
||||||
STRING_LOCATION_PAIR(MethodDecl, getEndLoc())));
|
STRING_LOCATION_PAIR(MethodDecl, getEndLoc())));
|
||||||
|
@ -145,3 +146,741 @@ ns1::ns2::Foo<A, B> ns1::ns2::Bar<T, U>::Nested::method(int i, bool b) const
|
||||||
STRING_LOCATION_PAIR(MethodDecl, getReturnTypeSourceRange()),
|
STRING_LOCATION_PAIR(MethodDecl, getReturnTypeSourceRange()),
|
||||||
STRING_LOCATION_PAIR(MethodDecl, getSourceRange())));
|
STRING_LOCATION_PAIR(MethodDecl, getSourceRange())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Introspection, SourceLocations_NNS) {
|
||||||
|
auto AST =
|
||||||
|
buildASTFromCode(R"cpp(
|
||||||
|
namespace ns
|
||||||
|
{
|
||||||
|
struct A {
|
||||||
|
void foo();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
void ns::A::foo() {}
|
||||||
|
)cpp",
|
||||||
|
"foo.cpp", std::make_shared<PCHContainerOperations>());
|
||||||
|
auto &Ctx = AST->getASTContext();
|
||||||
|
auto &TU = *Ctx.getTranslationUnitDecl();
|
||||||
|
|
||||||
|
auto BoundNodes = ast_matchers::match(
|
||||||
|
decl(hasDescendant(nestedNameSpecifierLoc().bind("nns"))), TU, Ctx);
|
||||||
|
|
||||||
|
EXPECT_EQ(BoundNodes.size(), 1u);
|
||||||
|
|
||||||
|
const auto *NNS = BoundNodes[0].getNodeAs<NestedNameSpecifierLoc>("nns");
|
||||||
|
|
||||||
|
auto Result = NodeIntrospection::GetLocations(NNS);
|
||||||
|
|
||||||
|
if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ExpectedLocations =
|
||||||
|
FormatExpected<SourceLocation>(Result.LocationAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(
|
||||||
|
ExpectedLocations,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(NNS, getBeginLoc()),
|
||||||
|
STRING_LOCATION_PAIR(NNS, getEndLoc()),
|
||||||
|
STRING_LOCATION_PAIR(NNS, getLocalBeginLoc()),
|
||||||
|
STRING_LOCATION_PAIR(NNS, getLocalEndLoc())));
|
||||||
|
|
||||||
|
auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(
|
||||||
|
ExpectedRanges,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(NNS, getLocalSourceRange()),
|
||||||
|
STRING_LOCATION_PAIR(NNS, getSourceRange())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Introspection, SourceLocations_TA_Type) {
|
||||||
|
auto AST =
|
||||||
|
buildASTFromCode(R"cpp(
|
||||||
|
template<typename T>
|
||||||
|
struct A {
|
||||||
|
void foo();
|
||||||
|
};
|
||||||
|
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
A<int> a;
|
||||||
|
}
|
||||||
|
)cpp",
|
||||||
|
"foo.cpp", std::make_shared<PCHContainerOperations>());
|
||||||
|
auto &Ctx = AST->getASTContext();
|
||||||
|
auto &TU = *Ctx.getTranslationUnitDecl();
|
||||||
|
|
||||||
|
auto BoundNodes = ast_matchers::match(
|
||||||
|
decl(hasDescendant(templateArgumentLoc().bind("ta"))), TU, Ctx);
|
||||||
|
|
||||||
|
EXPECT_EQ(BoundNodes.size(), 1u);
|
||||||
|
|
||||||
|
const auto *TA = BoundNodes[0].getNodeAs<TemplateArgumentLoc>("ta");
|
||||||
|
|
||||||
|
auto Result = NodeIntrospection::GetLocations(TA);
|
||||||
|
|
||||||
|
if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ExpectedLocations =
|
||||||
|
FormatExpected<SourceLocation>(Result.LocationAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedLocations,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getLocation())));
|
||||||
|
|
||||||
|
auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedRanges,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getSourceRange())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Introspection, SourceLocations_TA_Decl) {
|
||||||
|
auto AST =
|
||||||
|
buildASTFromCode(R"cpp(
|
||||||
|
template<void(*Ty)()>
|
||||||
|
void test2() {}
|
||||||
|
void doNothing() {}
|
||||||
|
void test() {
|
||||||
|
test2<doNothing>();
|
||||||
|
}
|
||||||
|
)cpp",
|
||||||
|
"foo.cpp", std::make_shared<PCHContainerOperations>());
|
||||||
|
auto &Ctx = AST->getASTContext();
|
||||||
|
auto &TU = *Ctx.getTranslationUnitDecl();
|
||||||
|
|
||||||
|
auto BoundNodes = ast_matchers::match(
|
||||||
|
decl(hasDescendant(templateArgumentLoc().bind("ta"))), TU, Ctx);
|
||||||
|
|
||||||
|
EXPECT_EQ(BoundNodes.size(), 1u);
|
||||||
|
|
||||||
|
const auto *TA = BoundNodes[0].getNodeAs<TemplateArgumentLoc>("ta");
|
||||||
|
|
||||||
|
auto Result = NodeIntrospection::GetLocations(TA);
|
||||||
|
|
||||||
|
if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ExpectedLocations =
|
||||||
|
FormatExpected<SourceLocation>(Result.LocationAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedLocations,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getLocation())));
|
||||||
|
|
||||||
|
auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedRanges,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getSourceRange())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Introspection, SourceLocations_TA_Nullptr) {
|
||||||
|
auto AST =
|
||||||
|
buildASTFromCode(R"cpp(
|
||||||
|
template<void(*Ty)()>
|
||||||
|
void test2() {}
|
||||||
|
void doNothing() {}
|
||||||
|
void test() {
|
||||||
|
test2<nullptr>();
|
||||||
|
}
|
||||||
|
)cpp",
|
||||||
|
"foo.cpp", std::make_shared<PCHContainerOperations>());
|
||||||
|
auto &Ctx = AST->getASTContext();
|
||||||
|
auto &TU = *Ctx.getTranslationUnitDecl();
|
||||||
|
|
||||||
|
auto BoundNodes = ast_matchers::match(
|
||||||
|
decl(hasDescendant(templateArgumentLoc().bind("ta"))), TU, Ctx);
|
||||||
|
|
||||||
|
EXPECT_EQ(BoundNodes.size(), 1u);
|
||||||
|
|
||||||
|
const auto *TA = BoundNodes[0].getNodeAs<TemplateArgumentLoc>("ta");
|
||||||
|
|
||||||
|
auto Result = NodeIntrospection::GetLocations(TA);
|
||||||
|
|
||||||
|
if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ExpectedLocations =
|
||||||
|
FormatExpected<SourceLocation>(Result.LocationAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedLocations,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getLocation())));
|
||||||
|
|
||||||
|
auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedRanges,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getSourceRange())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Introspection, SourceLocations_TA_Integral) {
|
||||||
|
auto AST =
|
||||||
|
buildASTFromCode(R"cpp(
|
||||||
|
template<int>
|
||||||
|
void test2() {}
|
||||||
|
void test() {
|
||||||
|
test2<42>();
|
||||||
|
}
|
||||||
|
)cpp",
|
||||||
|
"foo.cpp", std::make_shared<PCHContainerOperations>());
|
||||||
|
auto &Ctx = AST->getASTContext();
|
||||||
|
auto &TU = *Ctx.getTranslationUnitDecl();
|
||||||
|
|
||||||
|
auto BoundNodes = ast_matchers::match(
|
||||||
|
decl(hasDescendant(templateArgumentLoc().bind("ta"))), TU, Ctx);
|
||||||
|
|
||||||
|
EXPECT_EQ(BoundNodes.size(), 1u);
|
||||||
|
|
||||||
|
const auto *TA = BoundNodes[0].getNodeAs<TemplateArgumentLoc>("ta");
|
||||||
|
|
||||||
|
auto Result = NodeIntrospection::GetLocations(TA);
|
||||||
|
|
||||||
|
if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ExpectedLocations =
|
||||||
|
FormatExpected<SourceLocation>(Result.LocationAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedLocations,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getLocation())));
|
||||||
|
|
||||||
|
auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedRanges,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getSourceRange())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Introspection, SourceLocations_TA_Template) {
|
||||||
|
auto AST =
|
||||||
|
buildASTFromCode(R"cpp(
|
||||||
|
template<typename T> class A;
|
||||||
|
template <template <typename> class T> void foo();
|
||||||
|
void bar()
|
||||||
|
{
|
||||||
|
foo<A>();
|
||||||
|
}
|
||||||
|
)cpp",
|
||||||
|
"foo.cpp", std::make_shared<PCHContainerOperations>());
|
||||||
|
auto &Ctx = AST->getASTContext();
|
||||||
|
auto &TU = *Ctx.getTranslationUnitDecl();
|
||||||
|
|
||||||
|
auto BoundNodes = ast_matchers::match(
|
||||||
|
decl(hasDescendant(templateArgumentLoc().bind("ta"))), TU, Ctx);
|
||||||
|
|
||||||
|
EXPECT_EQ(BoundNodes.size(), 1u);
|
||||||
|
|
||||||
|
const auto *TA = BoundNodes[0].getNodeAs<TemplateArgumentLoc>("ta");
|
||||||
|
|
||||||
|
auto Result = NodeIntrospection::GetLocations(TA);
|
||||||
|
|
||||||
|
if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ExpectedLocations =
|
||||||
|
FormatExpected<SourceLocation>(Result.LocationAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(
|
||||||
|
ExpectedLocations,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getLocation()),
|
||||||
|
STRING_LOCATION_PAIR(TA, getTemplateNameLoc())));
|
||||||
|
|
||||||
|
auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedRanges,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getSourceRange())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Introspection, SourceLocations_TA_TemplateExpansion) {
|
||||||
|
auto AST = buildASTFromCodeWithArgs(
|
||||||
|
R"cpp(
|
||||||
|
template<template<typename> class ...> class B { };
|
||||||
|
template<template<typename> class ...T> class C {
|
||||||
|
B<T...> testTemplateExpansion;
|
||||||
|
};
|
||||||
|
)cpp",
|
||||||
|
{"-fno-delayed-template-parsing"}, "foo.cpp", "clang-tool",
|
||||||
|
std::make_shared<PCHContainerOperations>());
|
||||||
|
auto &Ctx = AST->getASTContext();
|
||||||
|
auto &TU = *Ctx.getTranslationUnitDecl();
|
||||||
|
|
||||||
|
auto BoundNodes = ast_matchers::match(
|
||||||
|
decl(hasDescendant(templateArgumentLoc().bind("ta"))), TU, Ctx);
|
||||||
|
|
||||||
|
EXPECT_EQ(BoundNodes.size(), 1u);
|
||||||
|
|
||||||
|
const auto *TA = BoundNodes[0].getNodeAs<TemplateArgumentLoc>("ta");
|
||||||
|
|
||||||
|
auto Result = NodeIntrospection::GetLocations(TA);
|
||||||
|
|
||||||
|
if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ExpectedLocations =
|
||||||
|
FormatExpected<SourceLocation>(Result.LocationAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(
|
||||||
|
ExpectedLocations,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getLocation()),
|
||||||
|
STRING_LOCATION_PAIR(TA, getTemplateNameLoc()),
|
||||||
|
STRING_LOCATION_PAIR(TA, getTemplateEllipsisLoc())));
|
||||||
|
|
||||||
|
auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedRanges,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getSourceRange())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Introspection, SourceLocations_TA_Expression) {
|
||||||
|
auto AST =
|
||||||
|
buildASTFromCode(R"cpp(
|
||||||
|
template<int, int = 0> class testExpr;
|
||||||
|
template<int I> class testExpr<I> { };
|
||||||
|
)cpp",
|
||||||
|
"foo.cpp", std::make_shared<PCHContainerOperations>());
|
||||||
|
auto &Ctx = AST->getASTContext();
|
||||||
|
auto &TU = *Ctx.getTranslationUnitDecl();
|
||||||
|
|
||||||
|
auto BoundNodes = ast_matchers::match(
|
||||||
|
decl(hasDescendant(templateArgumentLoc().bind("ta"))), TU, Ctx);
|
||||||
|
|
||||||
|
EXPECT_EQ(BoundNodes.size(), 1u);
|
||||||
|
|
||||||
|
const auto *TA = BoundNodes[0].getNodeAs<TemplateArgumentLoc>("ta");
|
||||||
|
|
||||||
|
auto Result = NodeIntrospection::GetLocations(TA);
|
||||||
|
|
||||||
|
if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ExpectedLocations =
|
||||||
|
FormatExpected<SourceLocation>(Result.LocationAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedLocations,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getLocation())));
|
||||||
|
|
||||||
|
auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedRanges,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getSourceRange())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Introspection, SourceLocations_TA_Pack) {
|
||||||
|
auto AST = buildASTFromCodeWithArgs(
|
||||||
|
R"cpp(
|
||||||
|
template<typename... T> class A {};
|
||||||
|
void foo()
|
||||||
|
{
|
||||||
|
A<int> ai;
|
||||||
|
}
|
||||||
|
)cpp",
|
||||||
|
{"-fno-delayed-template-parsing"}, "foo.cpp", "clang-tool",
|
||||||
|
std::make_shared<PCHContainerOperations>());
|
||||||
|
auto &Ctx = AST->getASTContext();
|
||||||
|
auto &TU = *Ctx.getTranslationUnitDecl();
|
||||||
|
|
||||||
|
auto BoundNodes = ast_matchers::match(
|
||||||
|
decl(hasDescendant(templateArgumentLoc().bind("ta"))), TU, Ctx);
|
||||||
|
|
||||||
|
EXPECT_EQ(BoundNodes.size(), 1u);
|
||||||
|
|
||||||
|
const auto *TA = BoundNodes[0].getNodeAs<TemplateArgumentLoc>("ta");
|
||||||
|
|
||||||
|
auto Result = NodeIntrospection::GetLocations(TA);
|
||||||
|
|
||||||
|
if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ExpectedLocations =
|
||||||
|
FormatExpected<SourceLocation>(Result.LocationAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedLocations,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getLocation())));
|
||||||
|
|
||||||
|
auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedRanges,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getSourceRange())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Introspection, SourceLocations_CXXCtorInitializer_base) {
|
||||||
|
auto AST =
|
||||||
|
buildASTFromCode(R"cpp(
|
||||||
|
struct A {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct B : A {
|
||||||
|
B() : A() {}
|
||||||
|
};
|
||||||
|
)cpp",
|
||||||
|
"foo.cpp", std::make_shared<PCHContainerOperations>());
|
||||||
|
auto &Ctx = AST->getASTContext();
|
||||||
|
auto &TU = *Ctx.getTranslationUnitDecl();
|
||||||
|
|
||||||
|
auto BoundNodes = ast_matchers::match(
|
||||||
|
decl(hasDescendant(cxxConstructorDecl(
|
||||||
|
hasAnyConstructorInitializer(cxxCtorInitializer().bind("init"))))),
|
||||||
|
TU, Ctx);
|
||||||
|
|
||||||
|
EXPECT_EQ(BoundNodes.size(), 1u);
|
||||||
|
|
||||||
|
const auto *CtorInit = BoundNodes[0].getNodeAs<CXXCtorInitializer>("init");
|
||||||
|
|
||||||
|
auto Result = NodeIntrospection::GetLocations(CtorInit);
|
||||||
|
|
||||||
|
if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ExpectedLocations =
|
||||||
|
FormatExpected<SourceLocation>(Result.LocationAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedLocations,
|
||||||
|
UnorderedElementsAre(
|
||||||
|
STRING_LOCATION_PAIR(CtorInit, getLParenLoc()),
|
||||||
|
STRING_LOCATION_PAIR(CtorInit, getRParenLoc()),
|
||||||
|
STRING_LOCATION_PAIR(CtorInit, getSourceLocation())));
|
||||||
|
|
||||||
|
auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
|
||||||
|
CtorInit, getSourceRange())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Introspection, SourceLocations_CXXCtorInitializer_member) {
|
||||||
|
auto AST =
|
||||||
|
buildASTFromCode(R"cpp(
|
||||||
|
struct A {
|
||||||
|
int m_i;
|
||||||
|
A() : m_i(42) {}
|
||||||
|
};
|
||||||
|
)cpp",
|
||||||
|
"foo.cpp", std::make_shared<PCHContainerOperations>());
|
||||||
|
auto &Ctx = AST->getASTContext();
|
||||||
|
auto &TU = *Ctx.getTranslationUnitDecl();
|
||||||
|
|
||||||
|
auto BoundNodes = ast_matchers::match(
|
||||||
|
decl(hasDescendant(cxxConstructorDecl(
|
||||||
|
hasAnyConstructorInitializer(cxxCtorInitializer().bind("init"))))),
|
||||||
|
TU, Ctx);
|
||||||
|
|
||||||
|
EXPECT_EQ(BoundNodes.size(), 1u);
|
||||||
|
|
||||||
|
const auto *CtorInit = BoundNodes[0].getNodeAs<CXXCtorInitializer>("init");
|
||||||
|
|
||||||
|
auto Result = NodeIntrospection::GetLocations(CtorInit);
|
||||||
|
|
||||||
|
if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ExpectedLocations =
|
||||||
|
FormatExpected<SourceLocation>(Result.LocationAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedLocations,
|
||||||
|
UnorderedElementsAre(
|
||||||
|
STRING_LOCATION_PAIR(CtorInit, getLParenLoc()),
|
||||||
|
STRING_LOCATION_PAIR(CtorInit, getMemberLocation()),
|
||||||
|
STRING_LOCATION_PAIR(CtorInit, getRParenLoc()),
|
||||||
|
STRING_LOCATION_PAIR(CtorInit, getSourceLocation())));
|
||||||
|
|
||||||
|
auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
|
||||||
|
CtorInit, getSourceRange())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Introspection, SourceLocations_CXXCtorInitializer_ctor) {
|
||||||
|
auto AST =
|
||||||
|
buildASTFromCode(R"cpp(
|
||||||
|
struct C {
|
||||||
|
C() : C(42) {}
|
||||||
|
C(int) {}
|
||||||
|
};
|
||||||
|
)cpp",
|
||||||
|
"foo.cpp", std::make_shared<PCHContainerOperations>());
|
||||||
|
auto &Ctx = AST->getASTContext();
|
||||||
|
auto &TU = *Ctx.getTranslationUnitDecl();
|
||||||
|
|
||||||
|
auto BoundNodes = ast_matchers::match(
|
||||||
|
decl(hasDescendant(cxxConstructorDecl(
|
||||||
|
hasAnyConstructorInitializer(cxxCtorInitializer().bind("init"))))),
|
||||||
|
TU, Ctx);
|
||||||
|
|
||||||
|
EXPECT_EQ(BoundNodes.size(), 1u);
|
||||||
|
|
||||||
|
const auto *CtorInit = BoundNodes[0].getNodeAs<CXXCtorInitializer>("init");
|
||||||
|
|
||||||
|
auto Result = NodeIntrospection::GetLocations(CtorInit);
|
||||||
|
|
||||||
|
if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ExpectedLocations =
|
||||||
|
FormatExpected<SourceLocation>(Result.LocationAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedLocations,
|
||||||
|
UnorderedElementsAre(
|
||||||
|
STRING_LOCATION_PAIR(CtorInit, getLParenLoc()),
|
||||||
|
STRING_LOCATION_PAIR(CtorInit, getRParenLoc()),
|
||||||
|
STRING_LOCATION_PAIR(CtorInit, getSourceLocation())));
|
||||||
|
|
||||||
|
auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
|
||||||
|
CtorInit, getSourceRange())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Introspection, SourceLocations_CXXCtorInitializer_pack) {
|
||||||
|
auto AST = buildASTFromCodeWithArgs(
|
||||||
|
R"cpp(
|
||||||
|
template<typename... T>
|
||||||
|
struct Templ {
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... T>
|
||||||
|
struct D : Templ<T...> {
|
||||||
|
D(T... t) : Templ<T>(t)... {}
|
||||||
|
};
|
||||||
|
)cpp",
|
||||||
|
{"-fno-delayed-template-parsing"}, "foo.cpp", "clang-tool",
|
||||||
|
std::make_shared<PCHContainerOperations>());
|
||||||
|
auto &Ctx = AST->getASTContext();
|
||||||
|
auto &TU = *Ctx.getTranslationUnitDecl();
|
||||||
|
|
||||||
|
auto BoundNodes = ast_matchers::match(
|
||||||
|
decl(hasDescendant(cxxConstructorDecl(
|
||||||
|
hasAnyConstructorInitializer(cxxCtorInitializer().bind("init"))))),
|
||||||
|
TU, Ctx);
|
||||||
|
|
||||||
|
EXPECT_EQ(BoundNodes.size(), 1u);
|
||||||
|
|
||||||
|
const auto *CtorInit = BoundNodes[0].getNodeAs<CXXCtorInitializer>("init");
|
||||||
|
|
||||||
|
auto Result = NodeIntrospection::GetLocations(CtorInit);
|
||||||
|
|
||||||
|
if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ExpectedLocations =
|
||||||
|
FormatExpected<SourceLocation>(Result.LocationAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedLocations,
|
||||||
|
UnorderedElementsAre(
|
||||||
|
STRING_LOCATION_PAIR(CtorInit, getEllipsisLoc()),
|
||||||
|
STRING_LOCATION_PAIR(CtorInit, getLParenLoc()),
|
||||||
|
STRING_LOCATION_PAIR(CtorInit, getMemberLocation()),
|
||||||
|
STRING_LOCATION_PAIR(CtorInit, getRParenLoc()),
|
||||||
|
STRING_LOCATION_PAIR(CtorInit, getSourceLocation())));
|
||||||
|
|
||||||
|
auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
|
||||||
|
CtorInit, getSourceRange())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Introspection, SourceLocations_CXXBaseSpecifier_plain) {
|
||||||
|
auto AST =
|
||||||
|
buildASTFromCode(R"cpp(
|
||||||
|
class A {};
|
||||||
|
class B : A {};
|
||||||
|
)cpp",
|
||||||
|
"foo.cpp", std::make_shared<PCHContainerOperations>());
|
||||||
|
auto &Ctx = AST->getASTContext();
|
||||||
|
auto &TU = *Ctx.getTranslationUnitDecl();
|
||||||
|
|
||||||
|
auto BoundNodes = ast_matchers::match(
|
||||||
|
decl(hasDescendant(cxxRecordDecl(hasDirectBase(
|
||||||
|
cxxBaseSpecifier(hasType(asString("class A"))).bind("base"))))),
|
||||||
|
TU, Ctx);
|
||||||
|
|
||||||
|
EXPECT_EQ(BoundNodes.size(), 1u);
|
||||||
|
|
||||||
|
const auto *Base = BoundNodes[0].getNodeAs<CXXBaseSpecifier>("base");
|
||||||
|
|
||||||
|
auto Result = NodeIntrospection::GetLocations(Base);
|
||||||
|
|
||||||
|
if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ExpectedLocations =
|
||||||
|
FormatExpected<SourceLocation>(Result.LocationAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedLocations,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(Base, getBaseTypeLoc()),
|
||||||
|
STRING_LOCATION_PAIR(Base, getBeginLoc()),
|
||||||
|
STRING_LOCATION_PAIR(Base, getEndLoc())));
|
||||||
|
|
||||||
|
auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
|
||||||
|
Base, getSourceRange())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Introspection, SourceLocations_CXXBaseSpecifier_accessspec) {
|
||||||
|
auto AST =
|
||||||
|
buildASTFromCode(R"cpp(
|
||||||
|
class A {};
|
||||||
|
class B : public A {};
|
||||||
|
)cpp",
|
||||||
|
"foo.cpp", std::make_shared<PCHContainerOperations>());
|
||||||
|
auto &Ctx = AST->getASTContext();
|
||||||
|
auto &TU = *Ctx.getTranslationUnitDecl();
|
||||||
|
|
||||||
|
auto BoundNodes = ast_matchers::match(
|
||||||
|
decl(hasDescendant(cxxRecordDecl(hasDirectBase(
|
||||||
|
cxxBaseSpecifier(hasType(asString("class A"))).bind("base"))))),
|
||||||
|
TU, Ctx);
|
||||||
|
|
||||||
|
EXPECT_EQ(BoundNodes.size(), 1u);
|
||||||
|
|
||||||
|
const auto *Base = BoundNodes[0].getNodeAs<CXXBaseSpecifier>("base");
|
||||||
|
|
||||||
|
auto Result = NodeIntrospection::GetLocations(Base);
|
||||||
|
|
||||||
|
if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ExpectedLocations =
|
||||||
|
FormatExpected<SourceLocation>(Result.LocationAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedLocations,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(Base, getBaseTypeLoc()),
|
||||||
|
STRING_LOCATION_PAIR(Base, getBeginLoc()),
|
||||||
|
STRING_LOCATION_PAIR(Base, getEndLoc())));
|
||||||
|
|
||||||
|
auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
|
||||||
|
Base, getSourceRange())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Introspection, SourceLocations_CXXBaseSpecifier_virtual) {
|
||||||
|
auto AST =
|
||||||
|
buildASTFromCode(R"cpp(
|
||||||
|
class A {};
|
||||||
|
class B {};
|
||||||
|
class C : virtual B, A {};
|
||||||
|
)cpp",
|
||||||
|
"foo.cpp", std::make_shared<PCHContainerOperations>());
|
||||||
|
auto &Ctx = AST->getASTContext();
|
||||||
|
auto &TU = *Ctx.getTranslationUnitDecl();
|
||||||
|
|
||||||
|
auto BoundNodes = ast_matchers::match(
|
||||||
|
decl(hasDescendant(cxxRecordDecl(hasDirectBase(
|
||||||
|
cxxBaseSpecifier(hasType(asString("class A"))).bind("base"))))),
|
||||||
|
TU, Ctx);
|
||||||
|
|
||||||
|
EXPECT_EQ(BoundNodes.size(), 1u);
|
||||||
|
|
||||||
|
const auto *Base = BoundNodes[0].getNodeAs<CXXBaseSpecifier>("base");
|
||||||
|
|
||||||
|
auto Result = NodeIntrospection::GetLocations(Base);
|
||||||
|
|
||||||
|
if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ExpectedLocations =
|
||||||
|
FormatExpected<SourceLocation>(Result.LocationAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedLocations,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(Base, getBaseTypeLoc()),
|
||||||
|
STRING_LOCATION_PAIR(Base, getBeginLoc()),
|
||||||
|
STRING_LOCATION_PAIR(Base, getEndLoc())));
|
||||||
|
|
||||||
|
auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
|
||||||
|
Base, getSourceRange())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Introspection, SourceLocations_CXXBaseSpecifier_template_base) {
|
||||||
|
auto AST =
|
||||||
|
buildASTFromCode(R"cpp(
|
||||||
|
template<typename T, typename U>
|
||||||
|
class A {};
|
||||||
|
class B : A<int, bool> {};
|
||||||
|
)cpp",
|
||||||
|
"foo.cpp", std::make_shared<PCHContainerOperations>());
|
||||||
|
auto &Ctx = AST->getASTContext();
|
||||||
|
auto &TU = *Ctx.getTranslationUnitDecl();
|
||||||
|
|
||||||
|
auto BoundNodes =
|
||||||
|
ast_matchers::match(decl(hasDescendant(cxxRecordDecl(
|
||||||
|
hasDirectBase(cxxBaseSpecifier().bind("base"))))),
|
||||||
|
TU, Ctx);
|
||||||
|
|
||||||
|
EXPECT_EQ(BoundNodes.size(), 1u);
|
||||||
|
|
||||||
|
const auto *Base = BoundNodes[0].getNodeAs<CXXBaseSpecifier>("base");
|
||||||
|
|
||||||
|
auto Result = NodeIntrospection::GetLocations(Base);
|
||||||
|
|
||||||
|
if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ExpectedLocations =
|
||||||
|
FormatExpected<SourceLocation>(Result.LocationAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedLocations,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(Base, getBaseTypeLoc()),
|
||||||
|
STRING_LOCATION_PAIR(Base, getBeginLoc()),
|
||||||
|
STRING_LOCATION_PAIR(Base, getEndLoc())));
|
||||||
|
|
||||||
|
auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
|
||||||
|
Base, getSourceRange())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Introspection, SourceLocations_CXXBaseSpecifier_pack) {
|
||||||
|
auto AST = buildASTFromCodeWithArgs(
|
||||||
|
R"cpp(
|
||||||
|
template<typename... T>
|
||||||
|
struct Templ : T... {
|
||||||
|
};
|
||||||
|
)cpp",
|
||||||
|
{"-fno-delayed-template-parsing"}, "foo.cpp", "clang-tool",
|
||||||
|
std::make_shared<PCHContainerOperations>());
|
||||||
|
auto &Ctx = AST->getASTContext();
|
||||||
|
auto &TU = *Ctx.getTranslationUnitDecl();
|
||||||
|
|
||||||
|
auto BoundNodes =
|
||||||
|
ast_matchers::match(decl(hasDescendant(cxxRecordDecl(
|
||||||
|
hasDirectBase(cxxBaseSpecifier().bind("base"))))),
|
||||||
|
TU, Ctx);
|
||||||
|
|
||||||
|
EXPECT_EQ(BoundNodes.size(), 1u);
|
||||||
|
|
||||||
|
const auto *Base = BoundNodes[0].getNodeAs<CXXBaseSpecifier>("base");
|
||||||
|
|
||||||
|
auto Result = NodeIntrospection::GetLocations(Base);
|
||||||
|
|
||||||
|
if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ExpectedLocations =
|
||||||
|
FormatExpected<SourceLocation>(Result.LocationAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedLocations,
|
||||||
|
UnorderedElementsAre(STRING_LOCATION_PAIR(Base, getBaseTypeLoc()),
|
||||||
|
STRING_LOCATION_PAIR(Base, getEllipsisLoc()),
|
||||||
|
STRING_LOCATION_PAIR(Base, getBeginLoc()),
|
||||||
|
STRING_LOCATION_PAIR(Base, getEndLoc())));
|
||||||
|
|
||||||
|
auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
|
||||||
|
|
||||||
|
EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
|
||||||
|
Base, getSourceRange())));
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue