//===- unittest/Introspection/IntrospectionTest.cpp ----------*- C++ -*---===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Tests for AST location API introspection. // //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/NodeIntrospection.h" #include "clang/Tooling/Tooling.h" #include "gmock/gmock-matchers.h" #include "gmock/gmock.h" #include "gtest/gtest.h" using namespace clang; using namespace clang::ast_matchers; using namespace clang::tooling; using ::testing::Pair; using ::testing::UnorderedElementsAre; template std::vector> FormatExpected(const MapType &Accessors) { std::vector> Result; llvm::transform(llvm::make_filter_range(Accessors, [](const auto &Accessor) { return Accessor.first.isValid(); }), std::back_inserter(Result), [](const auto &Accessor) { return std::make_pair( LocationCallFormatterCpp::format(*Accessor.second), Accessor.first); }); return Result; } #define STRING_LOCATION_PAIR(INSTANCE, LOC) Pair(#LOC, INSTANCE->LOC) #define STRING_LOCATION_STDPAIR(INSTANCE, LOC) \ std::make_pair(std::string(#LOC), INSTANCE->LOC) /** A test formatter for a hypothetical language which needs neither casts nor '->'. */ class LocationCallFormatterSimple { public: static void print(const LocationCall &Call, llvm::raw_ostream &OS) { if (Call.isCast()) { if (const LocationCall *On = Call.on()) print(*On, OS); return; } if (const LocationCall *On = Call.on()) { print(*On, OS); OS << '.'; } OS << Call.name() << "()"; } static std::string format(const LocationCall &Call) { std::string Result; llvm::raw_string_ostream OS(Result); print(Call, OS); OS.flush(); return Result; } }; TEST(Introspection, SourceLocations_CallContainer) { SourceLocationMap slm; SharedLocationCall Prefix; slm.insert(std::make_pair( SourceLocation(), llvm::makeIntrusiveRefCnt(Prefix, "getSourceRange"))); EXPECT_EQ(slm.size(), 1u); auto callTypeLoc = llvm::makeIntrusiveRefCnt(Prefix, "getTypeLoc"); slm.insert(std::make_pair( SourceLocation(), llvm::makeIntrusiveRefCnt(callTypeLoc, "getSourceRange"))); EXPECT_EQ(slm.size(), 2u); } TEST(Introspection, SourceLocations_CallContainer2) { SourceRangeMap slm; SharedLocationCall Prefix; slm.insert( std::make_pair(SourceRange(), llvm::makeIntrusiveRefCnt( Prefix, "getCXXOperatorNameRange"))); EXPECT_EQ(slm.size(), 1u); slm.insert(std::make_pair( SourceRange(), llvm::makeIntrusiveRefCnt(Prefix, "getSourceRange"))); EXPECT_EQ(slm.size(), 2u); } TEST(Introspection, SourceLocations_CallChainFormatting) { SharedLocationCall Prefix; auto chainedCall = llvm::makeIntrusiveRefCnt( llvm::makeIntrusiveRefCnt(Prefix, "getTypeLoc"), "getSourceRange"); EXPECT_EQ(LocationCallFormatterCpp::format(*chainedCall), "getTypeLoc().getSourceRange()"); } TEST(Introspection, SourceLocations_Formatter) { SharedLocationCall Prefix; auto chainedCall = llvm::makeIntrusiveRefCnt( llvm::makeIntrusiveRefCnt( llvm::makeIntrusiveRefCnt( llvm::makeIntrusiveRefCnt( Prefix, "getTypeSourceInfo", LocationCall::ReturnsPointer), "getTypeLoc"), "getAs", LocationCall::IsCast), "getNameLoc"); EXPECT_EQ("getTypeSourceInfo()->getTypeLoc().getAs()." "getNameLoc()", LocationCallFormatterCpp::format(*chainedCall)); EXPECT_EQ("getTypeSourceInfo().getTypeLoc().getNameLoc()", LocationCallFormatterSimple::format(*chainedCall)); } TEST(Introspection, SourceLocations_Stmt) { if (!NodeIntrospection::hasIntrospectionSupport()) GTEST_SKIP(); auto AST = buildASTFromCode("void foo() {} void bar() { foo(); }", "foo.cpp", std::make_shared()); auto &Ctx = AST->getASTContext(); auto &TU = *Ctx.getTranslationUnitDecl(); auto BoundNodes = ast_matchers::match( decl(hasDescendant( callExpr(callee(functionDecl(hasName("foo")))).bind("fooCall"))), TU, Ctx); EXPECT_EQ(BoundNodes.size(), 1u); auto *FooCall = BoundNodes[0].getNodeAs("fooCall"); auto Result = NodeIntrospection::GetLocations(FooCall); auto ExpectedLocations = FormatExpected(Result.LocationAccessors); EXPECT_THAT( ExpectedLocations, UnorderedElementsAre(STRING_LOCATION_PAIR(FooCall, getBeginLoc()), STRING_LOCATION_PAIR(FooCall, getEndLoc()), STRING_LOCATION_PAIR(FooCall, getExprLoc()), STRING_LOCATION_PAIR(FooCall, getRParenLoc()))); auto ExpectedRanges = FormatExpected(Result.RangeAccessors); EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR( FooCall, getSourceRange()))); } TEST(Introspection, SourceLocations_Decl) { if (!NodeIntrospection::hasIntrospectionSupport()) GTEST_SKIP(); auto AST = buildASTFromCode(R"cpp( namespace ns1 { namespace ns2 { template struct Foo {}; template struct Bar { struct Nested { template Foo method(int i, bool b) const noexcept(true); }; }; } // namespace ns2 } // namespace ns1 template template ns1::ns2::Foo ns1::ns2::Bar::Nested::method(int i, bool b) const noexcept(true) {} )cpp", "foo.cpp", std::make_shared()); auto &Ctx = AST->getASTContext(); auto &TU = *Ctx.getTranslationUnitDecl(); auto BoundNodes = ast_matchers::match( decl(hasDescendant( cxxMethodDecl(hasName("method"), isDefinition()).bind("method"))), TU, Ctx); EXPECT_EQ(BoundNodes.size(), 1u); const auto *MethodDecl = BoundNodes[0].getNodeAs("method"); auto Result = NodeIntrospection::GetLocations(MethodDecl); auto ExpectedLocations = FormatExpected(Result.LocationAccessors); llvm::sort(ExpectedLocations); // clang-format off std::vector> ActualLocations{ STRING_LOCATION_STDPAIR(MethodDecl, getBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getBodyRBrace()), STRING_LOCATION_STDPAIR(MethodDecl, getEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getInnerLocStart()), STRING_LOCATION_STDPAIR(MethodDecl, getLocation()), STRING_LOCATION_STDPAIR(MethodDecl, getNameInfo().getBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getNameInfo().getEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getNameInfo().getLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getOuterLocStart()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getLocalBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getLocalEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getLocalBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getLocalEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getPrefix().getBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getPrefix().getEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getPrefix().getLocalBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getPrefix().getLocalEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getPrefix().getPrefix().getBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getPrefix().getPrefix().getEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getPrefix().getPrefix().getLocalBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getPrefix().getPrefix().getLocalEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getTypeLoc().getAs().getLAngleLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getTypeLoc().getAs().getRAngleLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getTypeLoc().getAs().getTemplateNameLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getTypeLoc().getBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getTypeLoc().getEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getTypeLoc().getAs().getNameLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getTypeLoc().getBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getTypeLoc().getEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getLParenLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getLocalRangeBegin()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getLocalRangeEnd()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getRParenLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getAs().getNamedTypeLoc().getAs().getLAngleLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getAs().getNamedTypeLoc().getAs().getRAngleLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getAs().getNamedTypeLoc().getAs().getTemplateNameLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getAs().getNamedTypeLoc().getBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getAs().getNamedTypeLoc().getEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getAs().getQualifierLoc().getBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getAs().getQualifierLoc().getEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getAs().getQualifierLoc().getLocalBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getAs().getQualifierLoc().getLocalEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getAs().getQualifierLoc().getPrefix().getBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getAs().getQualifierLoc().getPrefix().getEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getAs().getQualifierLoc().getPrefix().getLocalBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getAs().getQualifierLoc().getPrefix().getLocalEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getNextTypeLoc().getAs().getLAngleLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getNextTypeLoc().getAs().getRAngleLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getNextTypeLoc().getAs().getTemplateNameLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getNextTypeLoc().getBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getNextTypeLoc().getEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs().getNamedTypeLoc().getAs().getLAngleLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs().getNamedTypeLoc().getAs().getRAngleLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs().getNamedTypeLoc().getAs().getTemplateNameLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs().getNamedTypeLoc().getBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs().getNamedTypeLoc().getEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs().getQualifierLoc().getBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs().getQualifierLoc().getEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs().getQualifierLoc().getLocalBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs().getQualifierLoc().getLocalEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs().getQualifierLoc().getPrefix().getBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs().getQualifierLoc().getPrefix().getEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs().getQualifierLoc().getPrefix().getLocalBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs().getQualifierLoc().getPrefix().getLocalEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getNextTypeLoc().getAs().getLAngleLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getNextTypeLoc().getAs().getRAngleLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getNextTypeLoc().getAs().getTemplateNameLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getNextTypeLoc().getBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getNextTypeLoc().getEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSpecEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSpecStartLoc()) }; // clang-format on EXPECT_EQ(ExpectedLocations, ActualLocations); auto ExpectedRanges = FormatExpected(Result.RangeAccessors); llvm::sort(ExpectedRanges, llvm::less_first()); // clang-format off EXPECT_EQ( llvm::makeArrayRef(ExpectedRanges), (ArrayRef>{ STRING_LOCATION_STDPAIR(MethodDecl, getExceptionSpecSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getNameInfo().getSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getParametersSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getLocalSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getLocalSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getPrefix().getLocalSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getPrefix().getPrefix().getLocalSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getPrefix().getPrefix().getSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getPrefix().getSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getTypeLoc().getLocalSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getTypeLoc().getSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getTypeLoc().getLocalSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getTypeLoc().getSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getReturnTypeSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getExceptionSpecRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getParensRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getAs().getNamedTypeLoc().getLocalSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getAs().getNamedTypeLoc().getSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getAs().getQualifierLoc().getLocalSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getAs().getQualifierLoc().getPrefix().getLocalSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getAs().getQualifierLoc().getPrefix().getSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getAs().getQualifierLoc().getSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getLocalSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getNextTypeLoc().getLocalSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getNextTypeLoc().getSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs().getReturnLoc().getSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getLocalSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs().getNamedTypeLoc().getLocalSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs().getNamedTypeLoc().getSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs().getQualifierLoc().getLocalSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs().getQualifierLoc().getPrefix().getLocalSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs().getQualifierLoc().getPrefix().getSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs().getQualifierLoc().getSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getLocalSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getNextTypeLoc().getLocalSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getNextTypeLoc().getSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getSourceRange()) })); // clang-format on } TEST(Introspection, SourceLocations_NNS) { if (!NodeIntrospection::hasIntrospectionSupport()) GTEST_SKIP(); auto AST = buildASTFromCode(R"cpp( namespace ns { struct A { void foo(); }; } void ns::A::foo() {} )cpp", "foo.cpp", std::make_shared()); 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("nns"); auto Result = NodeIntrospection::GetLocations(*NNS); auto ExpectedLocations = FormatExpected(Result.LocationAccessors); llvm::sort(ExpectedLocations); EXPECT_EQ( llvm::makeArrayRef(ExpectedLocations), (ArrayRef>{ STRING_LOCATION_STDPAIR(NNS, getBeginLoc()), STRING_LOCATION_STDPAIR(NNS, getEndLoc()), STRING_LOCATION_STDPAIR(NNS, getLocalBeginLoc()), STRING_LOCATION_STDPAIR(NNS, getLocalEndLoc()), STRING_LOCATION_STDPAIR(NNS, getPrefix().getBeginLoc()), STRING_LOCATION_STDPAIR(NNS, getPrefix().getEndLoc()), STRING_LOCATION_STDPAIR(NNS, getPrefix().getLocalBeginLoc()), STRING_LOCATION_STDPAIR(NNS, getPrefix().getLocalEndLoc()), STRING_LOCATION_STDPAIR( NNS, getTypeLoc().getAs().getNameLoc()), STRING_LOCATION_STDPAIR(NNS, getTypeLoc().getBeginLoc()), STRING_LOCATION_STDPAIR(NNS, getTypeLoc().getEndLoc())})); auto ExpectedRanges = FormatExpected(Result.RangeAccessors); EXPECT_THAT( ExpectedRanges, UnorderedElementsAre( STRING_LOCATION_PAIR(NNS, getPrefix().getLocalSourceRange()), STRING_LOCATION_PAIR(NNS, getPrefix().getSourceRange()), STRING_LOCATION_PAIR(NNS, getLocalSourceRange()), STRING_LOCATION_PAIR(NNS, getSourceRange()), STRING_LOCATION_PAIR(NNS, getTypeLoc().getSourceRange()), STRING_LOCATION_PAIR(NNS, getTypeLoc().getLocalSourceRange()))); } TEST(Introspection, SourceLocations_TA_Type) { if (!NodeIntrospection::hasIntrospectionSupport()) GTEST_SKIP(); auto AST = buildASTFromCode(R"cpp( template struct A { void foo(); }; void foo() { A a; } )cpp", "foo.cpp", std::make_shared()); 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("ta"); auto Result = NodeIntrospection::GetLocations(*TA); auto ExpectedLocations = FormatExpected(Result.LocationAccessors); // clang-format off EXPECT_THAT(ExpectedLocations, UnorderedElementsAre( STRING_LOCATION_PAIR(TA, getLocation()), STRING_LOCATION_PAIR(TA, getTypeSourceInfo()->getTypeLoc().getAs().getBuiltinLoc()), STRING_LOCATION_PAIR(TA, getTypeSourceInfo()->getTypeLoc().getAs().getNameLoc()), STRING_LOCATION_PAIR( TA, getTypeSourceInfo()->getTypeLoc().getBeginLoc()), STRING_LOCATION_PAIR( TA, getTypeSourceInfo()->getTypeLoc().getEndLoc()) )); // clang-format on auto ExpectedRanges = FormatExpected(Result.RangeAccessors); EXPECT_THAT( ExpectedRanges, UnorderedElementsAre( STRING_LOCATION_PAIR(TA, getSourceRange()), STRING_LOCATION_PAIR( TA, getTypeSourceInfo()->getTypeLoc().getSourceRange()), STRING_LOCATION_PAIR( TA, getTypeSourceInfo()->getTypeLoc().getLocalSourceRange()))); } TEST(Introspection, SourceLocations_TA_Decl) { if (!NodeIntrospection::hasIntrospectionSupport()) GTEST_SKIP(); auto AST = buildASTFromCode(R"cpp( template void test2() {} void doNothing() {} void test() { test2(); } )cpp", "foo.cpp", std::make_shared()); 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("ta"); auto Result = NodeIntrospection::GetLocations(*TA); auto ExpectedLocations = FormatExpected(Result.LocationAccessors); EXPECT_THAT(ExpectedLocations, UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getLocation()))); auto ExpectedRanges = FormatExpected(Result.RangeAccessors); EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getSourceRange()))); } TEST(Introspection, SourceLocations_TA_Nullptr) { if (!NodeIntrospection::hasIntrospectionSupport()) GTEST_SKIP(); auto AST = buildASTFromCode(R"cpp( template void test2() {} void doNothing() {} void test() { test2(); } )cpp", "foo.cpp", std::make_shared()); 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("ta"); auto Result = NodeIntrospection::GetLocations(*TA); auto ExpectedLocations = FormatExpected(Result.LocationAccessors); EXPECT_THAT(ExpectedLocations, UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getLocation()))); auto ExpectedRanges = FormatExpected(Result.RangeAccessors); EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getSourceRange()))); } TEST(Introspection, SourceLocations_TA_Integral) { if (!NodeIntrospection::hasIntrospectionSupport()) GTEST_SKIP(); auto AST = buildASTFromCode(R"cpp( template void test2() {} void test() { test2<42>(); } )cpp", "foo.cpp", std::make_shared()); 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("ta"); auto Result = NodeIntrospection::GetLocations(*TA); auto ExpectedLocations = FormatExpected(Result.LocationAccessors); EXPECT_THAT(ExpectedLocations, UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getLocation()))); auto ExpectedRanges = FormatExpected(Result.RangeAccessors); EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getSourceRange()))); } TEST(Introspection, SourceLocations_TA_Template) { if (!NodeIntrospection::hasIntrospectionSupport()) GTEST_SKIP(); auto AST = buildASTFromCode(R"cpp( template class A; template