steveire updated this revision to Diff 336804. steveire added a comment. Update
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D99231/new/ https://reviews.llvm.org/D99231 Files: clang/include/clang/AST/DeclCXX.h clang/include/clang/Tooling/NodeIntrospection.h clang/lib/Tooling/CMakeLists.txt clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py clang/unittests/Introspection/IntrospectionTest.cpp
Index: clang/unittests/Introspection/IntrospectionTest.cpp =================================================================== --- clang/unittests/Introspection/IntrospectionTest.cpp +++ clang/unittests/Introspection/IntrospectionTest.cpp @@ -30,7 +30,10 @@ std::map<std::string, T> FormatExpected(const MapType &Accessors) { 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()), [](const auto &Accessor) { return std::make_pair( @@ -126,11 +129,9 @@ UnorderedElementsAre( STRING_LOCATION_PAIR(MethodDecl, getBeginLoc()), STRING_LOCATION_PAIR(MethodDecl, getBodyRBrace()), - STRING_LOCATION_PAIR(MethodDecl, getEllipsisLoc()), STRING_LOCATION_PAIR(MethodDecl, getInnerLocStart()), STRING_LOCATION_PAIR(MethodDecl, getLocation()), STRING_LOCATION_PAIR(MethodDecl, getOuterLocStart()), - STRING_LOCATION_PAIR(MethodDecl, getPointOfInstantiation()), STRING_LOCATION_PAIR(MethodDecl, getTypeSpecEndLoc()), STRING_LOCATION_PAIR(MethodDecl, getTypeSpecStartLoc()), STRING_LOCATION_PAIR(MethodDecl, getEndLoc()))); @@ -145,3 +146,741 @@ STRING_LOCATION_PAIR(MethodDecl, getReturnTypeSourceRange()), 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()))); +} Index: clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py =================================================================== --- clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py +++ clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py @@ -180,6 +180,15 @@ NodeLocationAccessors NodeIntrospection::GetLocations(clang::Decl const *) { 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::DynTypedNode const &) { return {}; Index: clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp =================================================================== --- clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp +++ clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp @@ -26,7 +26,11 @@ isDefinition(), isSameOrDerivedFrom( // 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")), optionally(isDerivedFrom(cxxRecordDecl().bind("derivedFrom")))) .bind("className"), @@ -116,22 +120,30 @@ InnerMatcher...); }; - auto BoundNodesVec = - match(findAll(publicAccessor(ofClass(equalsNode(ASTClass)), - returns(asString(TypeString))) - .bind("classMethod")), - *ASTClass, *Result.Context); + auto BoundNodesVec = match( + findAll( + publicAccessor( + ofClass(cxxRecordDecl( + 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; for (const auto &BN : BoundNodesVec) { + const auto *StmtOrDeclBase = + BN.getNodeAs<clang::CXXRecordDecl>("stmtOrDeclBase"); if (const auto *Node = BN.getNodeAs<clang::NamedDecl>("classMethod")) { // Only record the getBeginLoc etc on Stmt etc, because it will call // more-derived implementations pseudo-virtually. - if ((ASTClass->getName() != "Stmt" && ASTClass->getName() != "Decl") && + if (StmtOrDeclBase && (Node->getName() == "getBeginLoc" || Node->getName() == "getEndLoc" || - Node->getName() == "getSourceRange")) { + Node->getName() == "getSourceRange")) continue; - } + // Only record the getExprLoc on Expr, because it will call // more-derived implementations pseudo-virtually. if (ASTClass->getName() != "Expr" && Node->getName() == "getExprLoc") { Index: clang/lib/Tooling/CMakeLists.txt =================================================================== --- clang/lib/Tooling/CMakeLists.txt +++ clang/lib/Tooling/CMakeLists.txt @@ -41,6 +41,18 @@ NodeLocationAccessors NodeIntrospection::GetLocations(clang::Decl const *) { 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 NodeIntrospection::GetLocations(clang::DynTypedNode const &) { return {}; Index: clang/include/clang/Tooling/NodeIntrospection.h =================================================================== --- clang/include/clang/Tooling/NodeIntrospection.h +++ clang/include/clang/Tooling/NodeIntrospection.h @@ -23,6 +23,10 @@ class Stmt; class Decl; +class CXXCtorInitializer; +class NestedNameSpecifierLoc; +class TemplateArgumentLoc; +class CXXBaseSpecifier; namespace tooling { @@ -80,6 +84,10 @@ namespace NodeIntrospection { NodeLocationAccessors GetLocations(clang::Stmt 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); } // namespace NodeIntrospection } // namespace tooling Index: clang/include/clang/AST/DeclCXX.h =================================================================== --- clang/include/clang/AST/DeclCXX.h +++ clang/include/clang/AST/DeclCXX.h @@ -2267,7 +2267,8 @@ // For a pack expansion, returns the location of the ellipsis. SourceLocation getEllipsisLoc() const { - assert(isPackExpansion() && "Initializer is not a pack expansion"); + if (!isPackExpansion()) + return {}; return MemberOrEllipsisLocation; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits