[clang] f347f0e - [AST] Add introspection support for more base nodes

Stephen Kelly via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 14 13:36:04 PDT 2021


Author: Stephen Kelly
Date: 2021-04-14T21:31:23+01:00
New Revision: f347f0e0b869be4f9b97f26663cf8e4eac2c4868

URL: https://github.com/llvm/llvm-project/commit/f347f0e0b869be4f9b97f26663cf8e4eac2c4868
DIFF: https://github.com/llvm/llvm-project/commit/f347f0e0b869be4f9b97f26663cf8e4eac2c4868.diff

LOG: [AST] Add introspection support for more base nodes

Fix the logic of detecting pseudo-virtual getBeginLoc etc on Stmt and
Decl subclasses.

Adjust the test infrastructure to filter out invalid source locations.
This makes the tests more clear about which nodes have which locations.

Differential Revision: https://reviews.llvm.org/D99231

Added: 
    

Modified: 
    clang/include/clang/Tooling/NodeIntrospection.h
    clang/lib/Tooling/CMakeLists.txt
    clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp
    clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py
    clang/unittests/Introspection/IntrospectionTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Tooling/NodeIntrospection.h b/clang/include/clang/Tooling/NodeIntrospection.h
index 3b40e68df24e7..28007c4468295 100644
--- a/clang/include/clang/Tooling/NodeIntrospection.h
+++ b/clang/include/clang/Tooling/NodeIntrospection.h
@@ -23,6 +23,10 @@ namespace clang {
 
 class Stmt;
 class Decl;
+class CXXCtorInitializer;
+class NestedNameSpecifierLoc;
+class TemplateArgumentLoc;
+class CXXBaseSpecifier;
 
 namespace tooling {
 
@@ -80,6 +84,10 @@ struct NodeLocationAccessors {
 namespace NodeIntrospection {
 NodeLocationAccessors GetLocations(clang::Stmt const *Object);
 NodeLocationAccessors GetLocations(clang::Decl const *Object);
+NodeLocationAccessors GetLocations(clang::CXXCtorInitializer const *Object);
+NodeLocationAccessors GetLocations(clang::NestedNameSpecifierLoc const *);
+NodeLocationAccessors GetLocations(clang::TemplateArgumentLoc const *);
+NodeLocationAccessors GetLocations(clang::CXXBaseSpecifier const *);
 NodeLocationAccessors GetLocations(clang::DynTypedNode const &Node);
 } // namespace NodeIntrospection
 } // namespace tooling

diff  --git a/clang/lib/Tooling/CMakeLists.txt b/clang/lib/Tooling/CMakeLists.txt
index ce7936a53671c..3598a44f13054 100644
--- a/clang/lib/Tooling/CMakeLists.txt
+++ b/clang/lib/Tooling/CMakeLists.txt
@@ -41,6 +41,22 @@ NodeLocationAccessors NodeIntrospection::GetLocations(clang::Stmt const *) {
 NodeLocationAccessors NodeIntrospection::GetLocations(clang::Decl const *) {
   return {};
 }
+NodeLocationAccessors NodeIntrospection::GetLocations(
+    clang::CXXCtorInitializer const *) {
+  return {};
+}
+NodeLocationAccessors NodeIntrospection::GetLocations(
+    clang::NestedNameSpecifierLoc const*) {
+  return {};
+}
+NodeLocationAccessors NodeIntrospection::GetLocations(
+    clang::TemplateArgumentLoc const*) {
+  return {};
+}
+NodeLocationAccessors NodeIntrospection::GetLocations(
+    clang::CXXBaseSpecifier const*) {
+  return {};
+}
 NodeLocationAccessors
 NodeIntrospection::GetLocations(clang::DynTypedNode const &) {
   return {};

diff  --git a/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp b/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp
index d611261dd1a74..5121740cd7c3f 100644
--- a/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp
+++ b/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp
@@ -26,7 +26,11 @@ ASTSrcLocProcessor::ASTSrcLocProcessor(StringRef JsonPath)
           isDefinition(),
           isSameOrDerivedFrom(
               // TODO: Extend this with other clades
-              namedDecl(hasAnyName("clang::Stmt", "clang::Decl"))
+              namedDecl(hasAnyName("clang::Stmt", "clang::Decl",
+                                   "clang::CXXCtorInitializer",
+                                   "clang::NestedNameSpecifierLoc",
+                                   "clang::TemplateArgumentLoc",
+                                   "clang::CXXBaseSpecifier"))
                   .bind("nodeClade")),
           optionally(isDerivedFrom(cxxRecordDecl().bind("derivedFrom"))))
           .bind("className"),
@@ -116,22 +120,30 @@ CaptureMethods(std::string TypeString, const clang::CXXRecordDecl *ASTClass,
                          InnerMatcher...);
   };
 
-  auto BoundNodesVec =
-      match(findAll(publicAccessor(ofClass(equalsNode(ASTClass)),
-                                   returns(asString(TypeString)))
-                        .bind("classMethod")),
-            *ASTClass, *Result.Context);
+  auto BoundNodesVec = match(
+      findAll(
+          publicAccessor(
+              ofClass(cxxRecordDecl(
+                  equalsNode(ASTClass),
+                  optionally(isDerivedFrom(
+                      cxxRecordDecl(hasAnyName("clang::Stmt", "clang::Decl"))
+                          .bind("stmtOrDeclBase"))))),
+              returns(asString(TypeString)))
+              .bind("classMethod")),
+      *ASTClass, *Result.Context);
 
   std::vector<std::string> Methods;
   for (const auto &BN : BoundNodesVec) {
+    const auto *StmtOrDeclBase =
+        BN.getNodeAs<clang::CXXRecordDecl>("stmtOrDeclBase");
     if (const auto *Node = BN.getNodeAs<clang::NamedDecl>("classMethod")) {
       // Only record the getBeginLoc etc on Stmt etc, because it will call
       // more-derived implementations pseudo-virtually.
-      if ((ASTClass->getName() != "Stmt" && ASTClass->getName() != "Decl") &&
+      if (StmtOrDeclBase &&
           (Node->getName() == "getBeginLoc" || Node->getName() == "getEndLoc" ||
-           Node->getName() == "getSourceRange")) {
+           Node->getName() == "getSourceRange"))
         continue;
-      }
+
       // Only record the getExprLoc on Expr, because it will call
       // more-derived implementations pseudo-virtually.
       if (ASTClass->getName() != "Expr" && Node->getName() == "getExprLoc") {

diff  --git a/clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py b/clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py
index 15a373e524804..e89ed1c00176f 100755
--- a/clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py
+++ b/clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py
@@ -180,6 +180,22 @@ def main():
 NodeLocationAccessors NodeIntrospection::GetLocations(clang::Decl const *) {
   return {};
 }
+NodeLocationAccessors NodeIntrospection::GetLocations(
+    clang::CXXCtorInitializer const *) {
+  return {};
+}
+NodeLocationAccessors NodeIntrospection::GetLocations(
+    clang::NestedNameSpecifierLoc const*) {
+  return {};
+}
+NodeLocationAccessors NodeIntrospection::GetLocations(
+    clang::TemplateArgumentLoc const*) {
+  return {};
+}
+NodeLocationAccessors NodeIntrospection::GetLocations(
+    clang::CXXBaseSpecifier const*) {
+  return {};
+}
 NodeLocationAccessors
 NodeIntrospection::GetLocations(clang::DynTypedNode const &) {
   return {};

diff  --git a/clang/unittests/Introspection/IntrospectionTest.cpp b/clang/unittests/Introspection/IntrospectionTest.cpp
index 5e32d7d593c74..2bfdcd0a26979 100644
--- a/clang/unittests/Introspection/IntrospectionTest.cpp
+++ b/clang/unittests/Introspection/IntrospectionTest.cpp
@@ -30,7 +30,10 @@ template<typename T, typename MapType>
 std::map<std::string, T>
 FormatExpected(const MapType &Accessors) {
   std::map<std::string, T> Result;
-  llvm::transform(Accessors,
+  llvm::transform(llvm::make_filter_range(Accessors,
+                                          [](const auto &Accessor) {
+                                            return Accessor.first.isValid();
+                                          }),
                   std::inserter(Result, Result.end()),
                   [](const auto &Accessor) {
                     return std::make_pair(
@@ -126,11 +129,9 @@ ns1::ns2::Foo<A, B> ns1::ns2::Bar<T, U>::Nested::method(int i, bool b) const
               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())));
@@ -145,3 +146,741 @@ ns1::ns2::Foo<A, B> ns1::ns2::Bar<T, U>::Nested::method(int i, bool b) const
           STRING_LOCATION_PAIR(MethodDecl, getReturnTypeSourceRange()),
           STRING_LOCATION_PAIR(MethodDecl, getSourceRange())));
 }
+
+TEST(Introspection, SourceLocations_NNS) {
+  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);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  auto ExpectedLocations =
+      FormatExpected<SourceLocation>(Result.LocationAccessors);
+
+  EXPECT_THAT(
+      ExpectedLocations,
+      UnorderedElementsAre(STRING_LOCATION_PAIR(NNS, getBeginLoc()),
+                           STRING_LOCATION_PAIR(NNS, getEndLoc()),
+                           STRING_LOCATION_PAIR(NNS, getLocalBeginLoc()),
+                           STRING_LOCATION_PAIR(NNS, getLocalEndLoc())));
+
+  auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
+
+  EXPECT_THAT(
+      ExpectedRanges,
+      UnorderedElementsAre(STRING_LOCATION_PAIR(NNS, getLocalSourceRange()),
+                           STRING_LOCATION_PAIR(NNS, getSourceRange())));
+}
+
+TEST(Introspection, SourceLocations_TA_Type) {
+  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);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  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_Decl) {
+  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);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  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) {
+  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);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  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) {
+  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);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  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) {
+  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);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  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) {
+  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);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  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) {
+  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);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  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) {
+  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);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  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_CXXCtorInitializer_base) {
+  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);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  auto ExpectedLocations =
+      FormatExpected<SourceLocation>(Result.LocationAccessors);
+
+  EXPECT_THAT(ExpectedLocations,
+              UnorderedElementsAre(
+                  STRING_LOCATION_PAIR(CtorInit, getLParenLoc()),
+                  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_member) {
+  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);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  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) {
+  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);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  auto ExpectedLocations =
+      FormatExpected<SourceLocation>(Result.LocationAccessors);
+
+  EXPECT_THAT(ExpectedLocations,
+              UnorderedElementsAre(
+                  STRING_LOCATION_PAIR(CtorInit, getLParenLoc()),
+                  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_pack) {
+  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);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  auto ExpectedLocations =
+      FormatExpected<SourceLocation>(Result.LocationAccessors);
+
+  EXPECT_THAT(ExpectedLocations,
+              UnorderedElementsAre(
+                  STRING_LOCATION_PAIR(CtorInit, getEllipsisLoc()),
+                  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_CXXBaseSpecifier_plain) {
+  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);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  auto ExpectedLocations =
+      FormatExpected<SourceLocation>(Result.LocationAccessors);
+
+  EXPECT_THAT(ExpectedLocations,
+              UnorderedElementsAre(STRING_LOCATION_PAIR(Base, getBaseTypeLoc()),
+                                   STRING_LOCATION_PAIR(Base, getBeginLoc()),
+                                   STRING_LOCATION_PAIR(Base, getEndLoc())));
+
+  auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
+
+  EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
+                                  Base, getSourceRange())));
+}
+
+TEST(Introspection, SourceLocations_CXXBaseSpecifier_accessspec) {
+  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);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  auto ExpectedLocations =
+      FormatExpected<SourceLocation>(Result.LocationAccessors);
+
+  EXPECT_THAT(ExpectedLocations,
+              UnorderedElementsAre(STRING_LOCATION_PAIR(Base, getBaseTypeLoc()),
+                                   STRING_LOCATION_PAIR(Base, getBeginLoc()),
+                                   STRING_LOCATION_PAIR(Base, getEndLoc())));
+
+  auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
+
+  EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
+                                  Base, getSourceRange())));
+}
+
+TEST(Introspection, SourceLocations_CXXBaseSpecifier_virtual) {
+  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);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  auto ExpectedLocations =
+      FormatExpected<SourceLocation>(Result.LocationAccessors);
+
+  EXPECT_THAT(ExpectedLocations,
+              UnorderedElementsAre(STRING_LOCATION_PAIR(Base, getBaseTypeLoc()),
+                                   STRING_LOCATION_PAIR(Base, getBeginLoc()),
+                                   STRING_LOCATION_PAIR(Base, getEndLoc())));
+
+  auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
+
+  EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
+                                  Base, getSourceRange())));
+}
+
+TEST(Introspection, SourceLocations_CXXBaseSpecifier_template_base) {
+  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);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  auto ExpectedLocations =
+      FormatExpected<SourceLocation>(Result.LocationAccessors);
+
+  EXPECT_THAT(ExpectedLocations,
+              UnorderedElementsAre(STRING_LOCATION_PAIR(Base, getBaseTypeLoc()),
+                                   STRING_LOCATION_PAIR(Base, getBeginLoc()),
+                                   STRING_LOCATION_PAIR(Base, getEndLoc())));
+
+  auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
+
+  EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
+                                  Base, getSourceRange())));
+}
+
+TEST(Introspection, SourceLocations_CXXBaseSpecifier_pack) {
+  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);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  auto ExpectedLocations =
+      FormatExpected<SourceLocation>(Result.LocationAccessors);
+
+  EXPECT_THAT(ExpectedLocations,
+              UnorderedElementsAre(STRING_LOCATION_PAIR(Base, getBaseTypeLoc()),
+                                   STRING_LOCATION_PAIR(Base, getEllipsisLoc()),
+                                   STRING_LOCATION_PAIR(Base, getBeginLoc()),
+                                   STRING_LOCATION_PAIR(Base, getEndLoc())));
+
+  auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
+
+  EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
+                                  Base, getSourceRange())));
+}


        


More information about the cfe-commits mailing list