1 //===- unittest/Introspection/IntrospectionTest.cpp ----------*- C++ -*---===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Tests for AST location API introspection. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "clang/AST/ASTContext.h" 14 #include "clang/ASTMatchers/ASTMatchFinder.h" 15 #include "clang/ASTMatchers/ASTMatchers.h" 16 #include "clang/Tooling/NodeIntrospection.h" 17 #include "clang/Tooling/Tooling.h" 18 #include "gmock/gmock-matchers.h" 19 #include "gmock/gmock.h" 20 #include "gtest/gtest.h" 21 22 using namespace clang; 23 using namespace clang::ast_matchers; 24 using namespace clang::tooling; 25 26 using ::testing::Pair; 27 using ::testing::UnorderedElementsAre; 28 29 template<typename T, typename MapType> 30 std::map<std::string, T> 31 FormatExpected(const MapType &Accessors) { 32 std::map<std::string, T> Result; 33 llvm::transform(Accessors, 34 std::inserter(Result, Result.end()), 35 [](const auto &Accessor) { 36 return std::make_pair( 37 LocationCallFormatterCpp::format(Accessor.second.get()), 38 Accessor.first); 39 }); 40 return Result; 41 } 42 43 #define STRING_LOCATION_PAIR(INSTANCE, LOC) Pair(#LOC, INSTANCE->LOC) 44 45 TEST(Introspection, SourceLocations_Stmt) { 46 auto AST = buildASTFromCode("void foo() {} void bar() { foo(); }", "foo.cpp", 47 std::make_shared<PCHContainerOperations>()); 48 auto &Ctx = AST->getASTContext(); 49 auto &TU = *Ctx.getTranslationUnitDecl(); 50 51 auto BoundNodes = ast_matchers::match( 52 decl(hasDescendant( 53 callExpr(callee(functionDecl(hasName("foo")))).bind("fooCall"))), 54 TU, Ctx); 55 56 EXPECT_EQ(BoundNodes.size(), 1u); 57 58 auto *FooCall = BoundNodes[0].getNodeAs<CallExpr>("fooCall"); 59 60 auto Result = NodeIntrospection::GetLocations(FooCall); 61 62 if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) 63 { 64 return; 65 } 66 67 auto ExpectedLocations = 68 FormatExpected<SourceLocation>(Result.LocationAccessors); 69 70 EXPECT_THAT( 71 ExpectedLocations, 72 UnorderedElementsAre(STRING_LOCATION_PAIR(FooCall, getBeginLoc()), 73 STRING_LOCATION_PAIR(FooCall, getEndLoc()), 74 STRING_LOCATION_PAIR(FooCall, getExprLoc()), 75 STRING_LOCATION_PAIR(FooCall, getRParenLoc()))); 76 77 auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors); 78 79 EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR( 80 FooCall, getSourceRange()))); 81 } 82 83 TEST(Introspection, SourceLocations_Decl) { 84 auto AST = 85 buildASTFromCode(R"cpp( 86 namespace ns1 { 87 namespace ns2 { 88 template <typename T, typename U> struct Foo {}; 89 template <typename T, typename U> struct Bar { 90 struct Nested { 91 template <typename A, typename B> 92 Foo<A, B> method(int i, bool b) const noexcept(true); 93 }; 94 }; 95 } // namespace ns2 96 } // namespace ns1 97 98 template <typename T, typename U> 99 template <typename A, typename B> 100 ns1::ns2::Foo<A, B> ns1::ns2::Bar<T, U>::Nested::method(int i, bool b) const 101 noexcept(true) {} 102 )cpp", 103 "foo.cpp", std::make_shared<PCHContainerOperations>()); 104 auto &Ctx = AST->getASTContext(); 105 auto &TU = *Ctx.getTranslationUnitDecl(); 106 107 auto BoundNodes = ast_matchers::match( 108 decl(hasDescendant( 109 cxxMethodDecl(hasName("method")).bind("method"))), 110 TU, Ctx); 111 112 EXPECT_EQ(BoundNodes.size(), 1u); 113 114 const auto *MethodDecl = BoundNodes[0].getNodeAs<CXXMethodDecl>("method"); 115 116 auto Result = NodeIntrospection::GetLocations(MethodDecl); 117 118 if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) { 119 return; 120 } 121 122 auto ExpectedLocations = 123 FormatExpected<SourceLocation>(Result.LocationAccessors); 124 125 EXPECT_THAT(ExpectedLocations, 126 UnorderedElementsAre( 127 STRING_LOCATION_PAIR(MethodDecl, getBeginLoc()), 128 STRING_LOCATION_PAIR(MethodDecl, getBodyRBrace()), 129 STRING_LOCATION_PAIR(MethodDecl, getEllipsisLoc()), 130 STRING_LOCATION_PAIR(MethodDecl, getInnerLocStart()), 131 STRING_LOCATION_PAIR(MethodDecl, getLocation()), 132 STRING_LOCATION_PAIR(MethodDecl, getOuterLocStart()), 133 STRING_LOCATION_PAIR(MethodDecl, getPointOfInstantiation()), 134 STRING_LOCATION_PAIR(MethodDecl, getTypeSpecEndLoc()), 135 STRING_LOCATION_PAIR(MethodDecl, getTypeSpecStartLoc()), 136 STRING_LOCATION_PAIR(MethodDecl, getEndLoc()))); 137 138 auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors); 139 140 EXPECT_THAT( 141 ExpectedRanges, 142 UnorderedElementsAre( 143 STRING_LOCATION_PAIR(MethodDecl, getExceptionSpecSourceRange()), 144 STRING_LOCATION_PAIR(MethodDecl, getParametersSourceRange()), 145 STRING_LOCATION_PAIR(MethodDecl, getReturnTypeSourceRange()), 146 STRING_LOCATION_PAIR(MethodDecl, getSourceRange()))); 147 } 148