[cfe-commits] r169508 - in /cfe/trunk: lib/ASTMatchers/ASTMatchFinder.cpp unittests/ASTMatchers/ASTMatchersTest.cpp

Manuel Klimek klimek at google.com
Thu Dec 6 06:42:48 PST 2012


Author: klimek
Date: Thu Dec  6 08:42:48 2012
New Revision: 169508

URL: http://llvm.org/viewvc/llvm-project?rev=169508&view=rev
Log:
Implements multiple parents in the parent map.

Previously we would match the last visited parent, which in the
case of template instantiations was the last instantiated template.

Modified:
    cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp
    cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp

Modified: cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp?rev=169508&r1=169507&r2=169508&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp Thu Dec  6 08:42:48 2012
@@ -39,8 +39,11 @@
 /// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes.
 class ParentMapASTVisitor : public RecursiveASTVisitor<ParentMapASTVisitor> {
 public:
-  /// \brief Maps from a node to its parent.
-  typedef llvm::DenseMap<const void*, ast_type_traits::DynTypedNode> ParentMap;
+  /// \brief Contains parents of a node.
+  typedef llvm::SmallVector<ast_type_traits::DynTypedNode, 1> ParentVector;
+
+  /// \brief Maps from a node to its parents.
+  typedef llvm::DenseMap<const void *, ParentVector> ParentMap;
 
   /// \brief Builds and returns the translation unit's parent map.
   ///
@@ -67,7 +70,15 @@
     if (Node == NULL)
       return true;
     if (ParentStack.size() > 0)
-      (*Parents)[Node] = ParentStack.back();
+      // FIXME: Currently we add the same parent multiple times, for example
+      // when we visit all subexpressions of template instantiations; this is
+      // suboptimal, bug benign: the only way to visit those is with
+      // hasAncestor / hasParent, and those do not create new matches.
+      // The plan is to enable DynTypedNode to be storable in a map or hash
+      // map. The main problem there is to implement hash functions /
+      // comparison operators for all types that DynTypedNode supports that
+      // do not have pointer identity.
+      (*Parents)[Node].push_back(ParentStack.back());
     ParentStack.push_back(ast_type_traits::DynTypedNode::create(*Node));
     bool Result = (this->*traverse)(Node);
     ParentStack.pop_back();
@@ -453,26 +464,7 @@
       Parents.reset(ParentMapASTVisitor::buildMap(
         *ActiveASTContext->getTranslationUnitDecl()));
     }
-    ast_type_traits::DynTypedNode Ancestor = Node;
-    while (Ancestor.get<TranslationUnitDecl>() !=
-           ActiveASTContext->getTranslationUnitDecl()) {
-      assert(Ancestor.getMemoizationData() &&
-             "Invariant broken: only nodes that support memoization may be "
-             "used in the parent map.");
-      ParentMapASTVisitor::ParentMap::const_iterator I =
-        Parents->find(Ancestor.getMemoizationData());
-      if (I == Parents->end()) {
-        assert(false &&
-               "Found node that is not in the parent map.");
-        return false;
-      }
-      Ancestor = I->second;
-      if (Matcher.matches(Ancestor, this, Builder))
-        return true;
-      if (MatchMode == ASTMatchFinder::AMM_ParentOnly)
-        return false;
-    }
-    return false;
+    return matchesAncestorOfRecursively(Node, Matcher, Builder, MatchMode);
   }
 
   // Implements ASTMatchFinder::getASTContext.
@@ -485,6 +477,39 @@
   bool shouldUseDataRecursionFor(clang::Stmt *S) const { return false; }
 
 private:
+  bool matchesAncestorOfRecursively(
+      const ast_type_traits::DynTypedNode &Node, const DynTypedMatcher &Matcher,
+      BoundNodesTreeBuilder *Builder, AncestorMatchMode MatchMode) {
+    if (Node.get<TranslationUnitDecl>() ==
+        ActiveASTContext->getTranslationUnitDecl())
+      return false;
+    assert(Node.getMemoizationData() &&
+           "Invariant broken: only nodes that support memoization may be "
+           "used in the parent map.");
+    ParentMapASTVisitor::ParentMap::const_iterator I =
+        Parents->find(Node.getMemoizationData());
+    if (I == Parents->end()) {
+      assert(false && "Found node that is not in the parent map.");
+      return false;
+    }
+    for (ParentMapASTVisitor::ParentVector::const_iterator AncestorI =
+             I->second.begin(), AncestorE = I->second.end();
+         AncestorI != AncestorE; ++AncestorI) {
+      if (Matcher.matches(*AncestorI, this, Builder))
+        return true;
+    }
+    if (MatchMode == ASTMatchFinder::AMM_ParentOnly)
+      return false;
+    for (ParentMapASTVisitor::ParentVector::const_iterator AncestorI =
+             I->second.begin(), AncestorE = I->second.end();
+         AncestorI != AncestorE; ++AncestorI) {
+      if (matchesAncestorOfRecursively(*AncestorI, Matcher, Builder, MatchMode))
+        return true;
+    }
+    return false;
+  }
+
+
   // Implements a BoundNodesTree::Visitor that calls a MatchCallback with
   // the aggregated bound nodes for each match.
   class MatchVisitor : public BoundNodesTree::Visitor {

Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp?rev=169508&r1=169507&r2=169508&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp Thu Dec  6 08:42:48 2012
@@ -3044,6 +3044,42 @@
       compoundStmt(hasParent(ifStmt()))));
 }
 
+TEST(HasAncestor, MatchesAllAncestors) {
+  EXPECT_TRUE(matches(
+      "template <typename T> struct C { static void f() { 42; } };"
+      "void t() { C<int>::f(); }",
+      integerLiteral(
+          equals(42),
+          allOf(hasAncestor(recordDecl(isTemplateInstantiation())),
+                hasAncestor(recordDecl(unless(isTemplateInstantiation())))))));
+}
+
+TEST(HasParent, MatchesAllParents) {
+  EXPECT_TRUE(matches(
+      "template <typename T> struct C { static void f() { 42; } };"
+      "void t() { C<int>::f(); }",
+      integerLiteral(
+          equals(42),
+          hasParent(compoundStmt(hasParent(functionDecl(
+              hasParent(recordDecl(isTemplateInstantiation())))))))));
+  EXPECT_TRUE(matches(
+      "template <typename T> struct C { static void f() { 42; } };"
+      "void t() { C<int>::f(); }",
+      integerLiteral(
+          equals(42),
+          hasParent(compoundStmt(hasParent(functionDecl(
+              hasParent(recordDecl(unless(isTemplateInstantiation()))))))))));
+  EXPECT_TRUE(matches(
+      "template <typename T> struct C { static void f() { 42; } };"
+      "void t() { C<int>::f(); }",
+      integerLiteral(equals(42),
+                     hasParent(compoundStmt(allOf(
+                         hasParent(functionDecl(
+                             hasParent(recordDecl(isTemplateInstantiation())))),
+                         hasParent(functionDecl(hasParent(recordDecl(
+                             unless(isTemplateInstantiation())))))))))));
+}
+
 TEST(TypeMatching, MatchesTypes) {
   EXPECT_TRUE(matches("struct S {};", qualType().bind("loc")));
 }





More information about the cfe-commits mailing list