| //===- 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::vector<std::pair<std::string, T>> |
| FormatExpected(const MapType &Accessors) { |
| std::vector<std::pair<std::string, T>> 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<LocationCall>(Prefix, "getSourceRange"))); |
| EXPECT_EQ(slm.size(), 1u); |
| |
| auto callTypeLoc = |
| llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "getTypeLoc"); |
| slm.insert(std::make_pair( |
| SourceLocation(), |
| llvm::makeIntrusiveRefCnt<LocationCall>(callTypeLoc, "getSourceRange"))); |
| EXPECT_EQ(slm.size(), 2u); |
| } |
| |
| TEST(Introspection, SourceLocations_CallContainer2) { |
| SourceRangeMap slm; |
| SharedLocationCall Prefix; |
| slm.insert( |
| std::make_pair(SourceRange(), llvm::makeIntrusiveRefCnt<LocationCall>( |
| Prefix, "getCXXOperatorNameRange"))); |
| EXPECT_EQ(slm.size(), 1u); |
| |
| slm.insert(std::make_pair( |
| SourceRange(), |
| llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "getSourceRange"))); |
| EXPECT_EQ(slm.size(), 2u); |
| } |
| |
| TEST(Introspection, SourceLocations_CallChainFormatting) { |
| SharedLocationCall Prefix; |
| auto chainedCall = llvm::makeIntrusiveRefCnt<LocationCall>( |
| llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "getTypeLoc"), |
| "getSourceRange"); |
| EXPECT_EQ(LocationCallFormatterCpp::format(*chainedCall), |
| "getTypeLoc().getSourceRange()"); |
| } |
| |
| TEST(Introspection, SourceLocations_Formatter) { |
| SharedLocationCall Prefix; |
| auto chainedCall = llvm::makeIntrusiveRefCnt<LocationCall>( |
| llvm::makeIntrusiveRefCnt<LocationCall>( |
| llvm::makeIntrusiveRefCnt<LocationCall>( |
| llvm::makeIntrusiveRefCnt<LocationCall>( |
| Prefix, "getTypeSourceInfo", LocationCall::ReturnsPointer), |
| "getTypeLoc"), |
| "getAs<clang::TypeSpecTypeLoc>", LocationCall::IsCast), |
| "getNameLoc"); |
| |
| EXPECT_EQ("getTypeSourceInfo()->getTypeLoc().getAs<clang::TypeSpecTypeLoc>()." |
| "getNameLoc()", |
| LocationCallFormatterCpp::format(*chainedCall)); |
| EXPECT_EQ("getTypeSourceInfo().getTypeLoc().getNameLoc()", |
| LocationCallFormatterSimple::format(*chainedCall)); |
| } |
| |
| TEST(Introspection, SourceLocations_Stmt) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| 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); |
| |
| 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) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| 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"), isDefinition()).bind("method"))), |
| TU, Ctx); |
| |
| EXPECT_EQ(BoundNodes.size(), 1u); |
| |
| const auto *MethodDecl = BoundNodes[0].getNodeAs<CXXMethodDecl>("method"); |
| |
| auto Result = NodeIntrospection::GetLocations(MethodDecl); |
| |
| auto ExpectedLocations = |
| FormatExpected<SourceLocation>(Result.LocationAccessors); |
| |
| llvm::sort(ExpectedLocations); |
| |
| // clang-format off |
| std::vector<std::pair<std::string, SourceLocation>> 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<clang::TemplateSpecializationTypeLoc>().getLAngleLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getRAngleLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getTemplateNameLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getTypeLoc().getBeginLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getTypeLoc().getEndLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getTypeLoc().getAs<clang::TypeSpecTypeLoc>().getNameLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getTypeLoc().getBeginLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getTypeLoc().getEndLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getLParenLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getLocalRangeBegin()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getLocalRangeEnd()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getRParenLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getLAngleLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getRAngleLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getTemplateNameLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getBeginLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getEndLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getBeginLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getEndLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getLocalBeginLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getLocalEndLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getPrefix().getBeginLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getPrefix().getEndLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getPrefix().getLocalBeginLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getPrefix().getLocalEndLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getBeginLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getEndLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getNextTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getLAngleLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getNextTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getRAngleLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getNextTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getTemplateNameLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getNextTypeLoc().getBeginLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().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<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getLAngleLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getRAngleLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getTemplateNameLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getBeginLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getEndLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getBeginLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getEndLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getLocalBeginLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getLocalEndLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getPrefix().getBeginLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getPrefix().getEndLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getPrefix().getLocalBeginLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().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<clang::TemplateSpecializationTypeLoc>().getLAngleLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getNextTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getRAngleLoc()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getNextTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().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<SourceRange>(Result.RangeAccessors); |
| |
| llvm::sort(ExpectedRanges, [](const auto &LHS, const auto &RHS) { |
| return LHS.first < RHS.first; |
| }); |
| |
| // clang-format off |
| EXPECT_EQ( |
| llvm::makeArrayRef(ExpectedRanges), |
| (ArrayRef<std::pair<std::string, SourceRange>>{ |
| 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<clang::FunctionTypeLoc>().getExceptionSpecRange()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getParensRange()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getLocalSourceRange()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getSourceRange()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getLocalSourceRange()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getPrefix().getLocalSourceRange()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getPrefix().getSourceRange()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getSourceRange()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getLocalSourceRange()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getNextTypeLoc().getLocalSourceRange()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getNextTypeLoc().getSourceRange()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getSourceRange()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getLocalSourceRange()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getLocalSourceRange()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getSourceRange()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getLocalSourceRange()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getPrefix().getLocalSourceRange()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getQualifierLoc().getPrefix().getSourceRange()), |
| STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().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()) |
| return; |
| 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); |
| |
| auto ExpectedLocations = |
| FormatExpected<SourceLocation>(Result.LocationAccessors); |
| |
| llvm::sort(ExpectedLocations); |
| |
| EXPECT_EQ( |
| llvm::makeArrayRef(ExpectedLocations), |
| (ArrayRef<std::pair<std::string, SourceLocation>>{ |
| 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<clang::TypeSpecTypeLoc>().getNameLoc()), |
| STRING_LOCATION_STDPAIR(NNS, getTypeLoc().getBeginLoc()), |
| STRING_LOCATION_STDPAIR(NNS, getTypeLoc().getEndLoc())})); |
| |
| auto ExpectedRanges = FormatExpected<SourceRange>(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()) |
| return; |
| 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); |
| |
| auto ExpectedLocations = |
| FormatExpected<SourceLocation>(Result.LocationAccessors); |
| |
| // clang-format off |
| EXPECT_THAT(ExpectedLocations, |
| UnorderedElementsAre( |
| STRING_LOCATION_PAIR(TA, getLocation()), |
| STRING_LOCATION_PAIR(TA, |
| getTypeSourceInfo()->getTypeLoc().getAs<clang::BuiltinTypeLoc>().getBuiltinLoc()), |
| STRING_LOCATION_PAIR(TA, |
| getTypeSourceInfo()->getTypeLoc().getAs<clang::BuiltinTypeLoc>().getNameLoc()), |
| STRING_LOCATION_PAIR( |
| TA, getTypeSourceInfo()->getTypeLoc().getBeginLoc()), |
| STRING_LOCATION_PAIR( |
| TA, getTypeSourceInfo()->getTypeLoc().getEndLoc()) |
| )); |
| // clang-format on |
| |
| auto ExpectedRanges = FormatExpected<SourceRange>(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()) |
| return; |
| 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); |
| |
| 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) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| 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); |
| |
| 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) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| 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); |
| |
| 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) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| 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); |
| |
| 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) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| 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); |
| |
| 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) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| 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); |
| |
| 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) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| 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); |
| |
| auto ExpectedLocations = |
| FormatExpected<SourceLocation>(Result.LocationAccessors); |
| |
| // clang-format off |
| EXPECT_THAT(ExpectedLocations, |
| UnorderedElementsAre( |
| STRING_LOCATION_PAIR(TA, getLocation()), |
| STRING_LOCATION_PAIR(TA, |
| getTypeSourceInfo()->getTypeLoc().getAs<clang::BuiltinTypeLoc>().getBuiltinLoc()), |
| STRING_LOCATION_PAIR(TA, |
| getTypeSourceInfo()->getTypeLoc().getAs<clang::BuiltinTypeLoc>().getNameLoc()), |
| STRING_LOCATION_PAIR( |
| TA, getTypeSourceInfo()->getTypeLoc().getBeginLoc()), |
| STRING_LOCATION_PAIR( |
| TA, getTypeSourceInfo()->getTypeLoc().getEndLoc()) |
| )); |
| // clang-format on |
| |
| auto ExpectedRanges = FormatExpected<SourceRange>(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_CXXCtorInitializer_base) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| 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); |
| |
| auto ExpectedLocations = |
| FormatExpected<SourceLocation>(Result.LocationAccessors); |
| |
| // clang-format off |
| EXPECT_THAT( |
| ExpectedLocations, |
| UnorderedElementsAre( |
| STRING_LOCATION_PAIR(CtorInit, getBaseClassLoc().getAs<clang::TypeSpecTypeLoc>().getNameLoc()), |
| STRING_LOCATION_PAIR(CtorInit, getBaseClassLoc().getBeginLoc()), |
| STRING_LOCATION_PAIR(CtorInit, getBaseClassLoc().getEndLoc()), |
| STRING_LOCATION_PAIR(CtorInit, getLParenLoc()), |
| STRING_LOCATION_PAIR(CtorInit, getRParenLoc()), |
| STRING_LOCATION_PAIR(CtorInit, getSourceLocation()), |
| STRING_LOCATION_PAIR(CtorInit, getTypeSourceInfo()->getTypeLoc().getAs<clang::TypeSpecTypeLoc>().getNameLoc()), |
| STRING_LOCATION_PAIR(CtorInit, getTypeSourceInfo()->getTypeLoc().getBeginLoc()), |
| STRING_LOCATION_PAIR(CtorInit, getTypeSourceInfo()->getTypeLoc().getEndLoc()) |
| )); |
| // clang-format on |
| |
| auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors); |
| |
| // clang-format off |
| EXPECT_THAT( |
| ExpectedRanges, |
| UnorderedElementsAre( |
| STRING_LOCATION_PAIR(CtorInit, getBaseClassLoc().getLocalSourceRange()), |
| STRING_LOCATION_PAIR(CtorInit, getBaseClassLoc().getSourceRange()), |
| STRING_LOCATION_PAIR(CtorInit, getTypeSourceInfo()->getTypeLoc().getLocalSourceRange()), |
| STRING_LOCATION_PAIR(CtorInit, getTypeSourceInfo()->getTypeLoc().getSourceRange()), |
| STRING_LOCATION_PAIR(CtorInit, getSourceRange()))); |
| // clang-format on |
| } |
| |
| TEST(Introspection, SourceLocations_CXXCtorInitializer_member) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| 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); |
| |
| 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) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| 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); |
| |
| auto ExpectedLocations = |
| FormatExpected<SourceLocation>(Result.LocationAccessors); |
| |
| // clang-format off |
| EXPECT_THAT( |
| ExpectedLocations, |
| UnorderedElementsAre( |
| STRING_LOCATION_PAIR(CtorInit, getLParenLoc()), |
| STRING_LOCATION_PAIR(CtorInit, getRParenLoc()), |
| STRING_LOCATION_PAIR(CtorInit, getSourceLocation()), |
| STRING_LOCATION_PAIR(CtorInit, |
| getTypeSourceInfo()->getTypeLoc().getBeginLoc()), |
| STRING_LOCATION_PAIR(CtorInit, |
| getTypeSourceInfo()->getTypeLoc().getEndLoc()), |
| STRING_LOCATION_PAIR(CtorInit, |
| getTypeSourceInfo()->getTypeLoc().getAs<clang::TypeSpecTypeLoc>().getNameLoc()) |
| )); |
| // clang-format on |
| |
| auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors); |
| |
| EXPECT_THAT( |
| ExpectedRanges, |
| UnorderedElementsAre( |
| STRING_LOCATION_PAIR(CtorInit, getSourceRange()), |
| STRING_LOCATION_PAIR( |
| CtorInit, |
| getTypeSourceInfo()->getTypeLoc().getLocalSourceRange()), |
| STRING_LOCATION_PAIR( |
| CtorInit, getTypeSourceInfo()->getTypeLoc().getSourceRange()))); |
| } |
| |
| TEST(Introspection, SourceLocations_CXXCtorInitializer_pack) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| 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); |
| |
| auto ExpectedLocations = |
| FormatExpected<SourceLocation>(Result.LocationAccessors); |
| |
| llvm::sort(ExpectedLocations); |
| |
| // clang-format off |
| EXPECT_EQ( |
| llvm::makeArrayRef(ExpectedLocations), |
| (ArrayRef<std::pair<std::string, SourceLocation>>{ |
| STRING_LOCATION_STDPAIR(CtorInit, getBaseClassLoc().getAs<clang::TemplateSpecializationTypeLoc>().getLAngleLoc()), |
| STRING_LOCATION_STDPAIR(CtorInit, getBaseClassLoc().getAs<clang::TemplateSpecializationTypeLoc>().getRAngleLoc()), |
| STRING_LOCATION_STDPAIR(CtorInit, getBaseClassLoc().getAs<clang::TemplateSpecializationTypeLoc>().getTemplateNameLoc()), |
| STRING_LOCATION_STDPAIR(CtorInit, getBaseClassLoc().getBeginLoc()), |
| STRING_LOCATION_STDPAIR(CtorInit, getBaseClassLoc().getEndLoc()), |
| STRING_LOCATION_STDPAIR(CtorInit, getEllipsisLoc()), |
| STRING_LOCATION_STDPAIR(CtorInit, getLParenLoc()), |
| STRING_LOCATION_STDPAIR(CtorInit, getMemberLocation()), |
| STRING_LOCATION_STDPAIR(CtorInit, getRParenLoc()), |
| STRING_LOCATION_STDPAIR(CtorInit, getSourceLocation()), |
| STRING_LOCATION_STDPAIR(CtorInit, getTypeSourceInfo()->getTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getLAngleLoc()), |
| STRING_LOCATION_STDPAIR(CtorInit, getTypeSourceInfo()->getTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getRAngleLoc()), |
| STRING_LOCATION_STDPAIR(CtorInit, getTypeSourceInfo()->getTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getTemplateNameLoc()), |
| STRING_LOCATION_STDPAIR(CtorInit, getTypeSourceInfo()->getTypeLoc().getBeginLoc()), |
| STRING_LOCATION_STDPAIR(CtorInit, getTypeSourceInfo()->getTypeLoc().getEndLoc()) |
| })); |
| // clang-format on |
| |
| auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors); |
| |
| EXPECT_THAT( |
| ExpectedRanges, |
| UnorderedElementsAre( |
| STRING_LOCATION_PAIR(CtorInit, |
| getBaseClassLoc().getLocalSourceRange()), |
| STRING_LOCATION_PAIR(CtorInit, getBaseClassLoc().getSourceRange()), |
| STRING_LOCATION_PAIR(CtorInit, getSourceRange()), |
| STRING_LOCATION_PAIR( |
| CtorInit, |
| getTypeSourceInfo()->getTypeLoc().getLocalSourceRange()), |
| STRING_LOCATION_PAIR( |
| CtorInit, getTypeSourceInfo()->getTypeLoc().getSourceRange()))); |
| } |
| |
| TEST(Introspection, SourceLocations_CXXBaseSpecifier_plain) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| 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); |
| |
| auto ExpectedLocations = |
| FormatExpected<SourceLocation>(Result.LocationAccessors); |
| |
| // clang-format off |
| EXPECT_THAT(ExpectedLocations, |
| UnorderedElementsAre( |
| STRING_LOCATION_PAIR(Base, getBaseTypeLoc()), |
| STRING_LOCATION_PAIR(Base, getBeginLoc()), |
| STRING_LOCATION_PAIR(Base, getEndLoc()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getAs<clang::TypeSpecTypeLoc>().getNameLoc()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getEndLoc()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getBeginLoc()) |
| )); |
| // clang-format on |
| |
| auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors); |
| |
| // clang-format off |
| EXPECT_THAT(ExpectedRanges, UnorderedElementsAre( |
| STRING_LOCATION_PAIR(Base, getSourceRange()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getSourceRange()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getLocalSourceRange()) |
| )); |
| // clang-format on |
| } |
| |
| TEST(Introspection, SourceLocations_CXXBaseSpecifier_accessspec) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| 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); |
| |
| auto ExpectedLocations = |
| FormatExpected<SourceLocation>(Result.LocationAccessors); |
| |
| // clang-format off |
| EXPECT_THAT(ExpectedLocations, |
| UnorderedElementsAre( |
| STRING_LOCATION_PAIR(Base, getBaseTypeLoc()), |
| STRING_LOCATION_PAIR(Base, getBeginLoc()), |
| STRING_LOCATION_PAIR(Base, getEndLoc()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getAs<clang::TypeSpecTypeLoc>().getNameLoc()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getEndLoc()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getBeginLoc()) |
| )); |
| // clang-format on |
| |
| auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors); |
| |
| // clang-format off |
| EXPECT_THAT(ExpectedRanges, UnorderedElementsAre( |
| STRING_LOCATION_PAIR(Base, getSourceRange()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getLocalSourceRange()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getSourceRange()) |
| )); |
| // clang-format on |
| } |
| |
| TEST(Introspection, SourceLocations_CXXBaseSpecifier_virtual) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| 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); |
| |
| auto ExpectedLocations = |
| FormatExpected<SourceLocation>(Result.LocationAccessors); |
| |
| // clang-format off |
| EXPECT_THAT(ExpectedLocations, |
| UnorderedElementsAre( |
| STRING_LOCATION_PAIR(Base, getBaseTypeLoc()), |
| STRING_LOCATION_PAIR(Base, getBeginLoc()), |
| STRING_LOCATION_PAIR(Base, getEndLoc()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getBeginLoc()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getAs<clang::TypeSpecTypeLoc>().getNameLoc()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getEndLoc()) |
| )); |
| // clang-format on |
| |
| auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors); |
| |
| // clang-format off |
| EXPECT_THAT(ExpectedRanges, UnorderedElementsAre( |
| STRING_LOCATION_PAIR(Base, getSourceRange()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getSourceRange()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getLocalSourceRange()) |
| )); |
| // clang-format on |
| } |
| |
| TEST(Introspection, SourceLocations_CXXBaseSpecifier_template_base) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| 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); |
| |
| auto ExpectedLocations = |
| FormatExpected<SourceLocation>(Result.LocationAccessors); |
| |
| // clang-format off |
| EXPECT_THAT(ExpectedLocations, |
| UnorderedElementsAre( |
| STRING_LOCATION_PAIR(Base, getBaseTypeLoc()), |
| STRING_LOCATION_PAIR(Base, getBeginLoc()), |
| STRING_LOCATION_PAIR(Base, getEndLoc()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getBeginLoc()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getTemplateNameLoc()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getLAngleLoc()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getEndLoc()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getRAngleLoc()) |
| )); |
| // clang-format on |
| |
| auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors); |
| |
| // clang-format off |
| EXPECT_THAT(ExpectedRanges, UnorderedElementsAre( |
| STRING_LOCATION_PAIR(Base, getSourceRange()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getSourceRange()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getLocalSourceRange()) |
| )); |
| // clang-format on |
| } |
| |
| TEST(Introspection, SourceLocations_CXXBaseSpecifier_pack) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| 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); |
| |
| auto ExpectedLocations = |
| FormatExpected<SourceLocation>(Result.LocationAccessors); |
| |
| // clang-format off |
| EXPECT_THAT(ExpectedLocations, |
| UnorderedElementsAre( |
| STRING_LOCATION_PAIR(Base, getBaseTypeLoc()), |
| STRING_LOCATION_PAIR(Base, getEllipsisLoc()), |
| STRING_LOCATION_PAIR(Base, getBeginLoc()), |
| STRING_LOCATION_PAIR(Base, getEndLoc()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getEndLoc()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getAs<clang::TypeSpecTypeLoc>().getNameLoc()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getBeginLoc()) |
| )); |
| // clang-format on |
| |
| auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors); |
| |
| // clang-format off |
| EXPECT_THAT(ExpectedRanges, UnorderedElementsAre( |
| STRING_LOCATION_PAIR(Base, getSourceRange()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getSourceRange()), |
| STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getLocalSourceRange()) |
| )); |
| // clang-format on |
| } |
| |
| TEST(Introspection, SourceLocations_FunctionProtoTypeLoc) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| auto AST = |
| buildASTFromCode(R"cpp( |
| int foo(); |
| )cpp", |
| "foo.cpp", std::make_shared<PCHContainerOperations>()); |
| auto &Ctx = AST->getASTContext(); |
| auto &TU = *Ctx.getTranslationUnitDecl(); |
| |
| auto BoundNodes = ast_matchers::match( |
| decl(hasDescendant(loc(functionProtoType()).bind("tl"))), TU, Ctx); |
| |
| EXPECT_EQ(BoundNodes.size(), 1u); |
| |
| const auto *TL = BoundNodes[0].getNodeAs<TypeLoc>("tl"); |
| auto Result = NodeIntrospection::GetLocations(*TL); |
| |
| auto ExpectedLocations = |
| FormatExpected<SourceLocation>(Result.LocationAccessors); |
| |
| llvm::sort(ExpectedLocations); |
| |
| // clang-format off |
| EXPECT_EQ( |
| llvm::makeArrayRef(ExpectedLocations), |
| (ArrayRef<std::pair<std::string, SourceLocation>>{ |
| STRING_LOCATION_STDPAIR(TL, getAs<clang::FunctionTypeLoc>().getLParenLoc()), |
| STRING_LOCATION_STDPAIR(TL, getAs<clang::FunctionTypeLoc>().getLocalRangeBegin()), |
| STRING_LOCATION_STDPAIR(TL, getAs<clang::FunctionTypeLoc>().getLocalRangeEnd()), |
| STRING_LOCATION_STDPAIR(TL, getAs<clang::FunctionTypeLoc>().getRParenLoc()), |
| STRING_LOCATION_STDPAIR(TL, getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::BuiltinTypeLoc>().getBuiltinLoc()), |
| STRING_LOCATION_STDPAIR(TL, getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::BuiltinTypeLoc>().getNameLoc()), |
| STRING_LOCATION_STDPAIR(TL, getAs<clang::FunctionTypeLoc>().getReturnLoc().getBeginLoc()), |
| STRING_LOCATION_STDPAIR(TL, getAs<clang::FunctionTypeLoc>().getReturnLoc().getEndLoc()), |
| STRING_LOCATION_STDPAIR(TL, getBeginLoc()), |
| STRING_LOCATION_STDPAIR(TL, getEndLoc()), |
| STRING_LOCATION_STDPAIR(TL, getNextTypeLoc().getAs<clang::BuiltinTypeLoc>().getBuiltinLoc()), |
| STRING_LOCATION_STDPAIR(TL, getNextTypeLoc().getAs<clang::BuiltinTypeLoc>().getNameLoc()), |
| STRING_LOCATION_STDPAIR(TL, getNextTypeLoc().getBeginLoc()), |
| STRING_LOCATION_STDPAIR(TL, getNextTypeLoc().getEndLoc()) |
| })); |
| // clang-format on |
| |
| auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors); |
| |
| // clang-format off |
| EXPECT_THAT( |
| ExpectedRanges, |
| UnorderedElementsAre( |
| STRING_LOCATION_PAIR(TL, getAs<clang::FunctionTypeLoc>().getParensRange()), |
| STRING_LOCATION_PAIR(TL, getAs<clang::FunctionTypeLoc>().getReturnLoc().getLocalSourceRange()), |
| STRING_LOCATION_PAIR(TL, getAs<clang::FunctionTypeLoc>().getReturnLoc().getSourceRange()), |
| STRING_LOCATION_PAIR(TL, getLocalSourceRange()), |
| STRING_LOCATION_PAIR(TL, getNextTypeLoc().getLocalSourceRange()), |
| STRING_LOCATION_PAIR(TL, getNextTypeLoc().getSourceRange()), |
| STRING_LOCATION_PAIR(TL, getSourceRange()) |
| )); |
| // clang-format on |
| } |
| |
| TEST(Introspection, SourceLocations_PointerTypeLoc) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| auto AST = |
| buildASTFromCode(R"cpp( |
| int* i; |
| )cpp", |
| "foo.cpp", std::make_shared<PCHContainerOperations>()); |
| auto &Ctx = AST->getASTContext(); |
| auto &TU = *Ctx.getTranslationUnitDecl(); |
| |
| auto BoundNodes = ast_matchers::match( |
| decl(hasDescendant( |
| varDecl(hasName("i"), hasDescendant(loc(pointerType()).bind("tl"))))), |
| TU, Ctx); |
| |
| EXPECT_EQ(BoundNodes.size(), 1u); |
| |
| const auto *TL = BoundNodes[0].getNodeAs<TypeLoc>("tl"); |
| auto Result = NodeIntrospection::GetLocations(*TL); |
| |
| auto ExpectedLocations = |
| FormatExpected<SourceLocation>(Result.LocationAccessors); |
| |
| llvm::sort(ExpectedLocations); |
| |
| // clang-format off |
| EXPECT_EQ( |
| llvm::makeArrayRef(ExpectedLocations), |
| (ArrayRef<std::pair<std::string, SourceLocation>>{ |
| STRING_LOCATION_STDPAIR(TL, getAs<clang::PointerTypeLoc>().getPointeeLoc().getAs<clang::BuiltinTypeLoc>().getBuiltinLoc()), |
| STRING_LOCATION_STDPAIR(TL, getAs<clang::PointerTypeLoc>().getPointeeLoc().getAs<clang::BuiltinTypeLoc>().getNameLoc()), |
| STRING_LOCATION_STDPAIR(TL, getAs<clang::PointerTypeLoc>().getPointeeLoc().getBeginLoc()), |
| STRING_LOCATION_STDPAIR(TL, getAs<clang::PointerTypeLoc>().getPointeeLoc().getEndLoc()), |
| STRING_LOCATION_STDPAIR(TL, getAs<clang::PointerTypeLoc>().getSigilLoc()), |
| STRING_LOCATION_STDPAIR(TL, getAs<clang::PointerTypeLoc>().getStarLoc()), |
| STRING_LOCATION_STDPAIR(TL, getBeginLoc()), |
| STRING_LOCATION_STDPAIR(TL, getEndLoc()), |
| STRING_LOCATION_STDPAIR(TL, getNextTypeLoc().getAs<clang::BuiltinTypeLoc>().getBuiltinLoc()), |
| STRING_LOCATION_STDPAIR(TL, getNextTypeLoc().getAs<clang::BuiltinTypeLoc>().getNameLoc()), |
| STRING_LOCATION_STDPAIR(TL, getNextTypeLoc().getBeginLoc()), |
| STRING_LOCATION_STDPAIR(TL, getNextTypeLoc().getEndLoc()) |
| })); |
| // clang-format on |
| |
| auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors); |
| |
| // clang-format off |
| EXPECT_THAT( |
| ExpectedRanges, |
| UnorderedElementsAre( |
| STRING_LOCATION_PAIR(TL, getAs<clang::PointerTypeLoc>().getPointeeLoc().getLocalSourceRange()), |
| STRING_LOCATION_PAIR(TL, getAs<clang::PointerTypeLoc>().getPointeeLoc().getSourceRange()), |
| STRING_LOCATION_PAIR(TL, getLocalSourceRange()), |
| STRING_LOCATION_PAIR(TL, getNextTypeLoc().getLocalSourceRange()), |
| STRING_LOCATION_PAIR(TL, getNextTypeLoc().getSourceRange()), |
| STRING_LOCATION_PAIR(TL, getSourceRange()) |
| )); |
| // clang-format on |
| } |
| |
| #ifndef _WIN32 |
| // This test doesn't work on windows due to use of the typeof extension. |
| TEST(Introspection, SourceLocations_TypeOfTypeLoc) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| auto AST = |
| buildASTFromCode(R"cpp( |
| typeof (static_cast<void *>(0)) i; |
| )cpp", |
| "foo.cpp", std::make_shared<PCHContainerOperations>()); |
| auto &Ctx = AST->getASTContext(); |
| auto &TU = *Ctx.getTranslationUnitDecl(); |
| |
| auto BoundNodes = ast_matchers::match( |
| decl(hasDescendant( |
| varDecl(hasName("i"), hasDescendant(loc(type()).bind("tl"))))), |
| TU, Ctx); |
| |
| EXPECT_EQ(BoundNodes.size(), 1u); |
| |
| const auto *TL = BoundNodes[0].getNodeAs<TypeLoc>("tl"); |
| auto Result = NodeIntrospection::GetLocations(*TL); |
| |
| auto ExpectedLocations = |
| FormatExpected<SourceLocation>(Result.LocationAccessors); |
| |
| EXPECT_THAT(ExpectedLocations, |
| UnorderedElementsAre( |
| STRING_LOCATION_PAIR(TL, getBeginLoc()), |
| STRING_LOCATION_PAIR(TL, getEndLoc()), |
| STRING_LOCATION_PAIR( |
| TL, getAs<clang::TypeOfExprTypeLoc>().getTypeofLoc()), |
| STRING_LOCATION_PAIR( |
| TL, getAs<clang::TypeOfExprTypeLoc>().getLParenLoc()), |
| STRING_LOCATION_PAIR( |
| TL, getAs<clang::TypeOfExprTypeLoc>().getRParenLoc()))); |
| |
| auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors); |
| |
| EXPECT_THAT(ExpectedRanges, |
| UnorderedElementsAre( |
| STRING_LOCATION_PAIR(TL, getLocalSourceRange()), |
| STRING_LOCATION_PAIR(TL, getSourceRange()), |
| STRING_LOCATION_PAIR( |
| TL, getAs<clang::TypeOfExprTypeLoc>().getParensRange()))); |
| } |
| #endif |
| |
| TEST(Introspection, SourceLocations_DeclarationNameInfo_Dtor) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| auto AST = |
| buildASTFromCode(R"cpp( |
| class Foo |
| { |
| ~Foo() {} |
| }; |
| )cpp", |
| "foo.cpp", std::make_shared<PCHContainerOperations>()); |
| auto &Ctx = AST->getASTContext(); |
| auto &TU = *Ctx.getTranslationUnitDecl(); |
| |
| auto BoundNodes = ast_matchers::match( |
| decl(hasDescendant(cxxDestructorDecl(hasName("~Foo")).bind("dtor"))), TU, |
| Ctx); |
| |
| EXPECT_EQ(BoundNodes.size(), 1u); |
| |
| const auto *Dtor = BoundNodes[0].getNodeAs<CXXDestructorDecl>("dtor"); |
| auto NI = Dtor->getNameInfo(); |
| auto Result = NodeIntrospection::GetLocations(NI); |
| |
| auto ExpectedLocations = |
| FormatExpected<SourceLocation>(Result.LocationAccessors); |
| |
| llvm::sort(ExpectedLocations); |
| |
| // clang-format off |
| EXPECT_EQ( |
| llvm::makeArrayRef(ExpectedLocations), |
| (ArrayRef<std::pair<std::string, SourceLocation>>{ |
| STRING_LOCATION_STDPAIR((&NI), getBeginLoc()), |
| STRING_LOCATION_STDPAIR((&NI), getEndLoc()), |
| STRING_LOCATION_STDPAIR((&NI), getLoc()), |
| STRING_LOCATION_STDPAIR((&NI), |
| getNamedTypeInfo()->getTypeLoc().getAs<clang::TypeSpecTypeLoc>().getNameLoc()), |
| STRING_LOCATION_STDPAIR( |
| (&NI), getNamedTypeInfo()->getTypeLoc().getBeginLoc()), |
| STRING_LOCATION_STDPAIR( |
| (&NI), getNamedTypeInfo()->getTypeLoc().getEndLoc())})); |
| // clang-format on |
| |
| auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors); |
| |
| EXPECT_THAT( |
| ExpectedRanges, |
| UnorderedElementsAre( |
| STRING_LOCATION_PAIR( |
| (&NI), getNamedTypeInfo()->getTypeLoc().getLocalSourceRange()), |
| STRING_LOCATION_PAIR( |
| (&NI), getNamedTypeInfo()->getTypeLoc().getSourceRange()), |
| STRING_LOCATION_PAIR((&NI), getSourceRange()))); |
| } |
| |
| TEST(Introspection, SourceLocations_DeclarationNameInfo_CRef) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| |
| auto AST = buildASTFromCodeWithArgs( |
| R"cpp( |
| template<typename T> |
| struct MyContainer |
| { |
| template <typename U> |
| void pushBack(); |
| }; |
| |
| template<typename T> |
| void foo() |
| { |
| MyContainer<T> mc; |
| mc.template pushBack<int>(); |
| } |
| )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(cxxDependentScopeMemberExpr(hasMemberName("pushBack")).bind("member"))), TU, |
| Ctx); |
| |
| EXPECT_EQ(BoundNodes.size(), 1u); |
| |
| const auto *Member = BoundNodes[0].getNodeAs<CXXDependentScopeMemberExpr>("member"); |
| auto Result = NodeIntrospection::GetLocations(Member); |
| |
| auto ExpectedLocations = |
| FormatExpected<SourceLocation>(Result.LocationAccessors); |
| |
| llvm::sort(ExpectedLocations); |
| |
| EXPECT_EQ( |
| llvm::makeArrayRef(ExpectedLocations), |
| (ArrayRef<std::pair<std::string, SourceLocation>>{ |
| STRING_LOCATION_STDPAIR(Member, getBeginLoc()), |
| STRING_LOCATION_STDPAIR(Member, getEndLoc()), |
| STRING_LOCATION_STDPAIR(Member, getExprLoc()), |
| STRING_LOCATION_STDPAIR(Member, getLAngleLoc()), |
| STRING_LOCATION_STDPAIR(Member, getMemberLoc()), |
| STRING_LOCATION_STDPAIR(Member, getMemberNameInfo().getBeginLoc()), |
| STRING_LOCATION_STDPAIR(Member, getMemberNameInfo().getEndLoc()), |
| STRING_LOCATION_STDPAIR(Member, getMemberNameInfo().getLoc()), |
| STRING_LOCATION_STDPAIR(Member, getOperatorLoc()), |
| STRING_LOCATION_STDPAIR(Member, getRAngleLoc()), |
| STRING_LOCATION_STDPAIR(Member, getTemplateKeywordLoc()) |
| })); |
| |
| auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors); |
| |
| EXPECT_THAT( |
| ExpectedRanges, |
| UnorderedElementsAre( |
| STRING_LOCATION_PAIR(Member, getMemberNameInfo().getSourceRange()), |
| STRING_LOCATION_PAIR(Member, getSourceRange()) |
| )); |
| } |
| |
| TEST(Introspection, SourceLocations_DeclarationNameInfo_ConvOp) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| auto AST = |
| buildASTFromCode(R"cpp( |
| class Foo |
| { |
| bool operator==(const Foo&) const { return false; } |
| }; |
| )cpp", |
| "foo.cpp", std::make_shared<PCHContainerOperations>()); |
| auto &Ctx = AST->getASTContext(); |
| auto &TU = *Ctx.getTranslationUnitDecl(); |
| |
| auto BoundNodes = ast_matchers::match( |
| decl(hasDescendant(cxxMethodDecl().bind("opeq"))), TU, Ctx); |
| |
| EXPECT_EQ(BoundNodes.size(), 1u); |
| |
| const auto *Opeq = BoundNodes[0].getNodeAs<CXXMethodDecl>("opeq"); |
| auto NI = Opeq->getNameInfo(); |
| auto Result = NodeIntrospection::GetLocations(NI); |
| |
| auto ExpectedLocations = |
| FormatExpected<SourceLocation>(Result.LocationAccessors); |
| |
| llvm::sort(ExpectedLocations); |
| |
| EXPECT_EQ(llvm::makeArrayRef(ExpectedLocations), |
| (ArrayRef<std::pair<std::string, SourceLocation>>{ |
| STRING_LOCATION_STDPAIR((&NI), getBeginLoc()), |
| STRING_LOCATION_STDPAIR((&NI), getEndLoc()), |
| STRING_LOCATION_STDPAIR((&NI), getLoc())})); |
| |
| auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors); |
| |
| EXPECT_THAT(ExpectedRanges, |
| UnorderedElementsAre( |
| STRING_LOCATION_PAIR((&NI), getSourceRange()), |
| STRING_LOCATION_PAIR((&NI), getCXXOperatorNameRange()))); |
| } |
| |
| TEST(Introspection, SourceLocations_DeclarationNameInfo_LitOp) { |
| if (!NodeIntrospection::hasIntrospectionSupport()) |
| return; |
| auto AST = |
| buildASTFromCode(R"cpp( |
| long double operator"" _identity ( long double val ) |
| { |
| return val; |
| } |
| )cpp", |
| "foo.cpp", std::make_shared<PCHContainerOperations>()); |
| auto &Ctx = AST->getASTContext(); |
| auto &TU = *Ctx.getTranslationUnitDecl(); |
| |
| auto BoundNodes = ast_matchers::match( |
| decl(hasDescendant(functionDecl().bind("litop"))), TU, Ctx); |
| |
| EXPECT_EQ(BoundNodes.size(), 1u); |
| |
| const auto *LitOp = BoundNodes[0].getNodeAs<FunctionDecl>("litop"); |
| auto NI = LitOp->getNameInfo(); |
| auto Result = NodeIntrospection::GetLocations(NI); |
| |
| auto ExpectedLocations = |
| FormatExpected<SourceLocation>(Result.LocationAccessors); |
| |
| llvm::sort(ExpectedLocations); |
| |
| EXPECT_EQ(llvm::makeArrayRef(ExpectedLocations), |
| (ArrayRef<std::pair<std::string, SourceLocation>>{ |
| STRING_LOCATION_STDPAIR((&NI), getBeginLoc()), |
| STRING_LOCATION_STDPAIR((&NI), getCXXLiteralOperatorNameLoc()), |
| STRING_LOCATION_STDPAIR((&NI), getEndLoc()), |
| STRING_LOCATION_STDPAIR((&NI), getLoc())})); |
| |
| auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors); |
| |
| EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR( |
| (&NI), getSourceRange()))); |
| } |