//===- 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::map FormatExpected(const MapType &Accessors) { std::map Result; llvm::transform(Accessors, std::inserter(Result, Result.end()), [](const auto &Accessor) { return std::make_pair( LocationCallFormatterCpp::format(Accessor.second.get()), Accessor.first); }); return Result; } #define STRING_LOCATION_PAIR(INSTANCE, LOC) Pair(#LOC, INSTANCE->LOC) TEST(Introspection, SourceLocations_Stmt) { 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); if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) { return; } 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) { 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")).bind("method"))), TU, Ctx); EXPECT_EQ(BoundNodes.size(), 1u); const auto *MethodDecl = BoundNodes[0].getNodeAs("method"); auto Result = NodeIntrospection::GetLocations(MethodDecl); if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) { return; } auto ExpectedLocations = FormatExpected(Result.LocationAccessors); EXPECT_THAT(ExpectedLocations, 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()))); auto ExpectedRanges = FormatExpected(Result.RangeAccessors); EXPECT_THAT( ExpectedRanges, UnorderedElementsAre( STRING_LOCATION_PAIR(MethodDecl, getExceptionSpecSourceRange()), STRING_LOCATION_PAIR(MethodDecl, getParametersSourceRange()), STRING_LOCATION_PAIR(MethodDecl, getReturnTypeSourceRange()), STRING_LOCATION_PAIR(MethodDecl, getSourceRange()))); }