[AST] Add introspection support for Decls
authorStephen Kelly <steveire@gmail.com>
Wed, 17 Mar 2021 22:56:39 +0000 (22:56 +0000)
committerStephen Kelly <steveire@gmail.com>
Mon, 22 Mar 2021 23:16:02 +0000 (23:16 +0000)
The test code has lots of interesting locations which are not yet
introspected, but those will come later:

 http://ce.steveire.com/z/3T90hR

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

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

index abaa58b..3b40e68 100644 (file)
@@ -22,6 +22,7 @@
 namespace clang {
 
 class Stmt;
+class Decl;
 
 namespace tooling {
 
@@ -78,6 +79,7 @@ struct NodeLocationAccessors {
 
 namespace NodeIntrospection {
 NodeLocationAccessors GetLocations(clang::Stmt const *Object);
+NodeLocationAccessors GetLocations(clang::Decl const *Object);
 NodeLocationAccessors GetLocations(clang::DynTypedNode const &Node);
 } // namespace NodeIntrospection
 } // namespace tooling
index e820f63..0a6fb99 100644 (file)
@@ -40,6 +40,9 @@ namespace tooling {
 NodeLocationAccessors NodeIntrospection::GetLocations(clang::Stmt const *) {
   return {};
 }
+NodeLocationAccessors NodeIntrospection::GetLocations(clang::Decl const *) {
+  return {};
+}
 NodeLocationAccessors
 NodeIntrospection::GetLocations(clang::DynTypedNode const &) {
   return {};
index e7400e9..d611261 100644 (file)
@@ -26,7 +26,8 @@ ASTSrcLocProcessor::ASTSrcLocProcessor(StringRef JsonPath)
           isDefinition(),
           isSameOrDerivedFrom(
               // TODO: Extend this with other clades
-              namedDecl(hasName("clang::Stmt")).bind("nodeClade")),
+              namedDecl(hasAnyName("clang::Stmt", "clang::Decl"))
+                  .bind("nodeClade")),
           optionally(isDerivedFrom(cxxRecordDecl().bind("derivedFrom"))))
           .bind("className"),
       this);
index b4d31d3..15a373e 100755 (executable)
@@ -177,6 +177,9 @@ namespace tooling {
 NodeLocationAccessors NodeIntrospection::GetLocations(clang::Stmt const *) {
   return {};
 }
+NodeLocationAccessors NodeIntrospection::GetLocations(clang::Decl const *) {
+  return {};
+}
 NodeLocationAccessors
 NodeIntrospection::GetLocations(clang::DynTypedNode const &) {
   return {};
index a1280d9..5e32d7d 100644 (file)
@@ -42,7 +42,7 @@ FormatExpected(const MapType &Accessors) {
 
 #define STRING_LOCATION_PAIR(INSTANCE, LOC) Pair(#LOC, INSTANCE->LOC)
 
-TEST(Introspection, SourceLocations) {
+TEST(Introspection, SourceLocations_Stmt) {
   auto AST = buildASTFromCode("void foo() {} void bar() { foo(); }", "foo.cpp",
                               std::make_shared<PCHContainerOperations>());
   auto &Ctx = AST->getASTContext();
@@ -79,3 +79,69 @@ TEST(Introspection, SourceLocations) {
   EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
                                   FooCall, getSourceRange())));
 }
+
+TEST(Introspection, SourceLocations_Decl) {
+  auto AST =
+      buildASTFromCode(R"cpp(
+namespace ns1 {
+namespace ns2 {
+template <typename T, typename U> struct Foo {};
+template <typename T, typename U> struct Bar {
+  struct Nested {
+    template <typename A, typename B>
+    Foo<A, B> method(int i, bool b) const noexcept(true);
+  };
+};
+} // namespace ns2
+} // namespace ns1
+
+template <typename T, typename U>
+template <typename A, typename B>
+ns1::ns2::Foo<A, B> ns1::ns2::Bar<T, U>::Nested::method(int i, bool b) const
+    noexcept(true) {}
+)cpp",
+                       "foo.cpp", std::make_shared<PCHContainerOperations>());
+  auto &Ctx = AST->getASTContext();
+  auto &TU = *Ctx.getTranslationUnitDecl();
+
+  auto BoundNodes = ast_matchers::match(
+      decl(hasDescendant(
+          cxxMethodDecl(hasName("method")).bind("method"))),
+      TU, Ctx);
+
+  EXPECT_EQ(BoundNodes.size(), 1u);
+
+  const auto *MethodDecl = BoundNodes[0].getNodeAs<CXXMethodDecl>("method");
+
+  auto Result = NodeIntrospection::GetLocations(MethodDecl);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  auto ExpectedLocations =
+      FormatExpected<SourceLocation>(Result.LocationAccessors);
+
+  EXPECT_THAT(ExpectedLocations,
+              UnorderedElementsAre(
+                  STRING_LOCATION_PAIR(MethodDecl, getBeginLoc()),
+                  STRING_LOCATION_PAIR(MethodDecl, getBodyRBrace()),
+                  STRING_LOCATION_PAIR(MethodDecl, getEllipsisLoc()),
+                  STRING_LOCATION_PAIR(MethodDecl, getInnerLocStart()),
+                  STRING_LOCATION_PAIR(MethodDecl, getLocation()),
+                  STRING_LOCATION_PAIR(MethodDecl, getOuterLocStart()),
+                  STRING_LOCATION_PAIR(MethodDecl, getPointOfInstantiation()),
+                  STRING_LOCATION_PAIR(MethodDecl, getTypeSpecEndLoc()),
+                  STRING_LOCATION_PAIR(MethodDecl, getTypeSpecStartLoc()),
+                  STRING_LOCATION_PAIR(MethodDecl, getEndLoc())));
+
+  auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
+
+  EXPECT_THAT(
+      ExpectedRanges,
+      UnorderedElementsAre(
+          STRING_LOCATION_PAIR(MethodDecl, getExceptionSpecSourceRange()),
+          STRING_LOCATION_PAIR(MethodDecl, getParametersSourceRange()),
+          STRING_LOCATION_PAIR(MethodDecl, getReturnTypeSourceRange()),
+          STRING_LOCATION_PAIR(MethodDecl, getSourceRange())));
+}