
The test code has lots of interesting locations which are not yet introspected, but those will come later: http://ce.steveire.com/z/3T90hR Differential Revision: https://reviews.llvm.org/D98775
148 lines
5.1 KiB
C++
148 lines
5.1 KiB
C++
//===- 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<typename T, typename MapType>
|
|
std::map<std::string, T>
|
|
FormatExpected(const MapType &Accessors) {
|
|
std::map<std::string, T> 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<PCHContainerOperations>());
|
|
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<CallExpr>("fooCall");
|
|
|
|
auto Result = NodeIntrospection::GetLocations(FooCall);
|
|
|
|
if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty())
|
|
{
|
|
return;
|
|
}
|
|
|
|
auto ExpectedLocations =
|
|
FormatExpected<SourceLocation>(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<SourceRange>(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 <typename T, typename U> struct Foo {};
|
|
template <typename T, typename U> struct Bar {
|
|
struct Nested {
|
|
template <typename A, typename B>
|
|
Foo<A, B> method(int i, bool b) const noexcept(true);
|
|
};
|
|
};
|
|
} // namespace ns2
|
|
} // namespace ns1
|
|
|
|
template <typename T, typename U>
|
|
template <typename A, typename B>
|
|
ns1::ns2::Foo<A, B> ns1::ns2::Bar<T, U>::Nested::method(int i, bool b) const
|
|
noexcept(true) {}
|
|
)cpp",
|
|
"foo.cpp", std::make_shared<PCHContainerOperations>());
|
|
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<CXXMethodDecl>("method");
|
|
|
|
auto Result = NodeIntrospection::GetLocations(MethodDecl);
|
|
|
|
if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
|
|
return;
|
|
}
|
|
|
|
auto ExpectedLocations =
|
|
FormatExpected<SourceLocation>(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<SourceRange>(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())));
|
|
}
|