[cfe-commits] [PATCH] Implement descendant matchers for NestedNamespecifiers

Daniel Jasper djasper at google.com
Mon Oct 29 08:57:51 PDT 2012


Hi klimek,

This implements has(), hasDescendant(), forEach() and forEachDescendant() for NestedNameSpecifier and NestedNameSpecifierLoc matchers.

http://llvm-reviews.chandlerc.com/D86

Files:
  include/clang/ASTMatchers/ASTMatchersInternal.h
  lib/ASTMatchers/ASTMatchFinder.cpp
  unittests/ASTMatchers/ASTMatchersTest.cpp

Index: include/clang/ASTMatchers/ASTMatchersInternal.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchersInternal.h
+++ include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -495,25 +495,31 @@
                       BoundNodesTreeBuilder *Builder,
                       TraversalKind Traverse,
                       BindKind Bind) {
-    TOOLING_COMPILE_ASSERT((llvm::is_base_of<Decl, T>::value ||
-                            llvm::is_base_of<Stmt, T>::value ||
-                            llvm::is_base_of<TypeLoc, T>::value ||
-                            llvm::is_base_of<QualType, T>::value),
-                           unsupported_type_for_recursive_matching);
-    return matchesChildOf(ast_type_traits::DynTypedNode::create(Node),
+    TOOLING_COMPILE_ASSERT(
+        (llvm::is_base_of<Decl, T>::value ||
+         llvm::is_base_of<Stmt, T>::value ||
+         llvm::is_base_of<NestedNameSpecifier, T>::value ||
+         llvm::is_base_of<NestedNameSpecifierLoc, T>::value ||
+         llvm::is_base_of<TypeLoc, T>::value ||
+         llvm::is_base_of<QualType, T>::value),
+        unsupported_type_for_recursive_matching);
+   return matchesChildOf(ast_type_traits::DynTypedNode::create(Node),
                           Matcher, Builder, Traverse, Bind);
   }
 
   template <typename T>
   bool matchesDescendantOf(const T &Node,
                            const DynTypedMatcher &Matcher,
                            BoundNodesTreeBuilder *Builder,
                            BindKind Bind) {
-    TOOLING_COMPILE_ASSERT((llvm::is_base_of<Decl, T>::value ||
-                            llvm::is_base_of<Stmt, T>::value ||
-                            llvm::is_base_of<TypeLoc, T>::value ||
-                            llvm::is_base_of<QualType, T>::value),
-                           unsupported_type_for_recursive_matching);
+    TOOLING_COMPILE_ASSERT(
+        (llvm::is_base_of<Decl, T>::value ||
+         llvm::is_base_of<Stmt, T>::value ||
+         llvm::is_base_of<NestedNameSpecifier, T>::value ||
+         llvm::is_base_of<NestedNameSpecifierLoc, T>::value ||
+         llvm::is_base_of<TypeLoc, T>::value ||
+         llvm::is_base_of<QualType, T>::value),
+        unsupported_type_for_recursive_matching);
     return matchesDescendantOf(ast_type_traits::DynTypedNode::create(Node),
                                Matcher, Builder, Bind);
   }
Index: lib/ASTMatchers/ASTMatchFinder.cpp
===================================================================
--- lib/ASTMatchers/ASTMatchFinder.cpp
+++ lib/ASTMatchers/ASTMatchFinder.cpp
@@ -147,6 +147,12 @@
       traverse(*D);
     else if (const Stmt *S = DynNode.get<Stmt>())
       traverse(*S);
+    else if (const NestedNameSpecifier *NNS =
+             DynNode.get<NestedNameSpecifier>())
+      traverse(*NNS);
+    else if (const NestedNameSpecifierLoc *NNSLoc =
+             DynNode.get<NestedNameSpecifierLoc>())
+      traverse(*NNSLoc);
     else if (const QualType *Q = DynNode.get<QualType>())
       traverse(*Q);
     else if (const TypeLoc *T = DynNode.get<TypeLoc>())
@@ -197,6 +203,16 @@
     // The TypeLoc is matched inside traverse.
     return traverse(TypeLocNode);
   }
+  bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) {
+    ScopedIncrement ScopedDepth(&CurrentDepth);
+    return (NNS == NULL) || traverse(*NNS);
+  }
+  bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
+    ScopedIncrement ScopedDepth(&CurrentDepth);
+    if (!match(*NNS.getNestedNameSpecifier()))
+      return false;
+    return !NNS || traverse(NNS);
+  }
 
   bool shouldVisitTemplateInstantiations() const { return true; }
   bool shouldVisitImplicitCode() const { return true; }
@@ -231,6 +247,13 @@
   bool baseTraverse(TypeLoc TypeLocNode) {
     return VisitorBase::TraverseTypeLoc(TypeLocNode);
   }
+  bool baseTraverse(const NestedNameSpecifier &NNS) {
+    return VisitorBase::TraverseNestedNameSpecifier(
+        const_cast<NestedNameSpecifier*>(&NNS));
+  }
+  bool baseTraverse(NestedNameSpecifierLoc NNS) {
+    return VisitorBase::TraverseNestedNameSpecifierLoc(NNS);
+  }
 
   // Sets 'Matched' to true if 'Matcher' matches 'Node' and:
   //   0 < CurrentDepth <= MaxDepth.
Index: unittests/ASTMatchers/ASTMatchersTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -3236,6 +3236,87 @@
           specifiesTypeLoc(loc(qualType(asString("struct A"))))))));
 }
 
+TEST(NNS, Descendants) {
+  std::string Fragment =
+      "namespace a { struct A { struct B { struct C {}; }; }; };"
+      "void f() { a::A::B::C c; }";
+  EXPECT_TRUE(matches(
+      Fragment,
+      decl(hasDescendant(nestedNameSpecifier(specifiesType(
+          asString("struct a::A")))))));
+  EXPECT_TRUE(matches(
+      Fragment,
+      nestedNameSpecifier(specifiesType(asString("struct a::A::B")),
+                          hasDescendant(nestedNameSpecifier(
+                              specifiesNamespace(hasName("a")))))));
+  EXPECT_TRUE(notMatches(
+      Fragment,
+      nestedNameSpecifier(specifiesType(asString("struct a::A::B")),
+                          has(nestedNameSpecifier(
+                              specifiesNamespace(hasName("a")))))));
+  EXPECT_TRUE(matches(
+      Fragment,
+      nestedNameSpecifier(specifiesType(asString("struct a::A")),
+                          has(nestedNameSpecifier(
+                              specifiesNamespace(hasName("a")))))));
+  EXPECT_TRUE(matches(
+      Fragment,
+      nestedNameSpecifier(specifiesType(asString("struct a::A")),
+                          has(nestedNameSpecifier(
+                              specifiesNamespace(hasName("a")))))));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      Fragment,
+      functionDecl(hasName("f"),
+                   forEachDescendant(nestedNameSpecifier().bind("x"))),
+      // Nested names: a, a::A and a::A::B.
+      new VerifyIdIsBoundTo<NestedNameSpecifier>("x", 3)));
+
+  // Not really useful, but to complete the interface.
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      Fragment,
+      nestedNameSpecifier(specifiesType(asString("struct a::A::B")),
+                          forEach(nestedNameSpecifier().bind("x"))),
+      new VerifyIdIsBoundTo<NestedNameSpecifier>("x", 1)));
+}
+
+TEST(NNSLoc, Descendants) {
+  std::string Fragment =
+      "namespace a { struct A { struct B { struct C {}; }; }; };"
+      "void f() { a::A::B::C c; }";
+  EXPECT_TRUE(matches(
+      Fragment,
+      decl(hasDescendant(loc(nestedNameSpecifier(specifiesType(
+          asString("struct a::A"))))))));
+  EXPECT_TRUE(matches(
+      Fragment,
+      nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A::B"))),
+                             hasDescendant(loc(nestedNameSpecifier(
+                                 specifiesNamespace(hasName("a"))))))));
+  EXPECT_TRUE(notMatches(
+      Fragment,
+      nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A::B"))),
+                             has(loc(nestedNameSpecifier(
+                                 specifiesNamespace(hasName("a"))))))));
+  EXPECT_TRUE(matches(
+      Fragment,
+      nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A"))),
+                             has(loc(nestedNameSpecifier(
+                                 specifiesNamespace(hasName("a"))))))));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      Fragment,
+      functionDecl(hasName("f"),
+                   forEachDescendant(nestedNameSpecifierLoc().bind("x"))),
+      // Nested names: a, a::A and a::A::B.
+      new VerifyIdIsBoundTo<NestedNameSpecifierLoc>("x", 3)));
+
+  // Not really useful, but to complete the interface.
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      Fragment,
+      nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A::B"))),
+                             forEach(nestedNameSpecifierLoc().bind("x"))),
+      new VerifyIdIsBoundTo<NestedNameSpecifierLoc>("x", 1)));
+}
+
 template <typename T>
 class VerifyRecursiveMatch : public BoundNodesCallback {
 public:
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D86.1.patch
Type: text/x-patch
Size: 8181 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20121029/0acaaee3/attachment.bin>


More information about the cfe-commits mailing list