From bee085762bce7f552afa0ebc43085102f96e41a4 Mon Sep 17 00:00:00 2001 From: Manuel Klimek Date: Thu, 7 Feb 2013 12:42:10 +0000 Subject: [PATCH] Implements equalsNode for Decl and Stmt. This is a powerful tool when doing iterative refined matches, where another match is started inside the match callback of the first one; this allows for example to find out whether the node was in the condition or body of its parent if-statement. llvm-svn: 174605 --- clang/docs/LibASTMatchersReference.html | 15 ++++++++++++ clang/include/clang/ASTMatchers/ASTMatchers.h | 20 ++++++++++++++++ clang/unittests/ASTMatchers/ASTMatchersTest.cpp | 31 +++++++++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index 3027083..930b922 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -1398,6 +1398,13 @@ declCountIs(2) +Matcher<Decl>equalsNodeDecl* Other +
Matches if a node equals another node.
+
+Decl has pointer identity in the AST.
+
+ + Matcher<FloatingLiteral>equalsValueT Value
Matches literals that are equal to the given value.
 
@@ -1581,6 +1588,14 @@ matches "a(int)", "b(long)", but not "c(double)".
 
+Matcher<Stmt>equalsNodeStmt* Other +
Matches if a node equals another node.
+
+Stmt has pointer identity in the AST.
+
+
+ + Matcher<TagDecl>isDefinition
Matches if a declaration has a body attached.
 
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 15c9565..d41aa1b 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -2945,6 +2945,26 @@ AST_MATCHER_P(NestedNameSpecifier, specifiesNamespace,
   return InnerMatcher.matches(*Node.getAsNamespace(), Finder, Builder);
 }
 
+/// \brief Overloads for the \c equalsNode matcher.
+/// FIXME: Implement for other node types.
+/// @{
+
+/// \brief Matches if a node equals another node.
+///
+/// \c Decl has pointer identity in the AST.
+AST_MATCHER_P_OVERLOAD(Decl, equalsNode, Decl*, Other, 0) {
+  return &Node == Other;
+}
+/// \brief Matches if a node equals another node.
+///
+/// \c Stmt has pointer identity in the AST.
+///
+AST_MATCHER_P_OVERLOAD(Stmt, equalsNode, Stmt*, Other, 1) {
+  return &Node == Other;
+}
+
+/// @}
+
 } // end namespace ast_matchers
 } // end namespace clang
 
diff --git a/clang/unittests/ASTMatchers/ASTMatchersTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp
index 60a79e8..618ac6e 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -3546,6 +3546,37 @@ TEST(MatchFinder, CanMatchSingleNodesRecursively) {
           "X", recordDecl(has(recordDecl(hasName("X::Z")).bind("Z"))), "Z")));
 }
 
+template 
+class VerifyAncestorHasChildIsEqual : public BoundNodesCallback {
+public:
+  virtual bool run(const BoundNodes *Nodes) { return false; }
+
+  virtual bool run(const BoundNodes *Nodes, ASTContext *Context) {
+    const T *Node = Nodes->getNodeAs("");
+    return verify(*Nodes, *Context, Node);
+  }
+
+  bool verify(const BoundNodes &Nodes, ASTContext &Context, const Stmt *Node) {
+    return selectFirst(
+        "", match(stmt(hasParent(stmt(has(stmt(equalsNode(Node)))).bind(""))),
+                  *Node, Context)) != NULL;
+  }
+  bool verify(const BoundNodes &Nodes, ASTContext &Context, const Decl *Node) {
+    return selectFirst(
+        "", match(decl(hasParent(decl(has(decl(equalsNode(Node)))).bind(""))),
+                  *Node, Context)) != NULL;
+  }
+};
+
+TEST(IsEqualTo, MatchesNodesByIdentity) {
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      "class X { class Y {}; };", recordDecl(hasName("::X::Y")).bind(""),
+      new VerifyAncestorHasChildIsEqual()));
+  EXPECT_TRUE(
+      matchAndVerifyResultTrue("void f() { if(true) {} }", ifStmt().bind(""),
+                               new VerifyAncestorHasChildIsEqual()));
+}
+
 class VerifyStartOfTranslationUnit : public MatchFinder::MatchCallback {
 public:
   VerifyStartOfTranslationUnit() : Called(false) {}
-- 
2.7.4