diff options
author | Manuel Klimek <klimek@google.com> | 2013-02-07 12:42:10 +0000 |
---|---|---|
committer | Manuel Klimek <klimek@google.com> | 2013-02-07 12:42:10 +0000 |
commit | fa37c5ca61af275a329386407e58cf70f4d9f596 (patch) | |
tree | 37cf8b63d6d4e92a2f388501379121c471dc2613 | |
parent | 21f18c4fda167dc5f72feddbd6a7ac1b63200a0d (diff) |
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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@174605 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | docs/LibASTMatchersReference.html | 15 | ||||
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchers.h | 20 | ||||
-rw-r--r-- | unittests/ASTMatchers/ASTMatchersTest.cpp | 31 |
3 files changed, 66 insertions, 0 deletions
diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html index 30270835ad..930b922cdd 100644 --- a/docs/LibASTMatchersReference.html +++ b/docs/LibASTMatchersReference.html @@ -1398,6 +1398,13 @@ declCountIs(2) </pre></td></tr> +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('equalsNode0')"><a name="equalsNode0Anchor">equalsNode</a></td><td>Decl* Other</td></tr> +<tr><td colspan="4" class="doc" id="equalsNode0"><pre>Matches if a node equals another node. + +Decl has pointer identity in the AST. +</pre></td></tr> + + <tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>></td><td class="name" onclick="toggle('equals1')"><a name="equals1Anchor">equals</a></td><td>ValueT Value</td></tr> <tr><td colspan="4" class="doc" id="equals1"><pre>Matches literals that are equal to the given value. @@ -1581,6 +1588,14 @@ matches "a(int)", "b(long)", but not "c(double)". </pre></td></tr> +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('equalsNode1')"><a name="equalsNode1Anchor">equalsNode</a></td><td>Stmt* Other</td></tr> +<tr><td colspan="4" class="doc" id="equalsNode1"><pre>Matches if a node equals another node. + +Stmt has pointer identity in the AST. + +</pre></td></tr> + + <tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TagDecl.html">TagDecl</a>></td><td class="name" onclick="toggle('isDefinition0')"><a name="isDefinition0Anchor">isDefinition</a></td><td></td></tr> <tr><td colspan="4" class="doc" id="isDefinition0"><pre>Matches if a declaration has a body attached. diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index 15c9565d39..d41aa1b6e8 100644 --- a/include/clang/ASTMatchers/ASTMatchers.h +++ b/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/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp index 60a79e86de..618ac6ec51 100644 --- a/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/unittests/ASTMatchers/ASTMatchersTest.cpp @@ -3546,6 +3546,37 @@ TEST(MatchFinder, CanMatchSingleNodesRecursively) { "X", recordDecl(has(recordDecl(hasName("X::Z")).bind("Z"))), "Z"))); } +template <typename T> +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<T>(""); + return verify(*Nodes, *Context, Node); + } + + bool verify(const BoundNodes &Nodes, ASTContext &Context, const Stmt *Node) { + return selectFirst<const T>( + "", match(stmt(hasParent(stmt(has(stmt(equalsNode(Node)))).bind(""))), + *Node, Context)) != NULL; + } + bool verify(const BoundNodes &Nodes, ASTContext &Context, const Decl *Node) { + return selectFirst<const T>( + "", 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<Decl>())); + EXPECT_TRUE( + matchAndVerifyResultTrue("void f() { if(true) {} }", ifStmt().bind(""), + new VerifyAncestorHasChildIsEqual<Stmt>())); +} + class VerifyStartOfTranslationUnit : public MatchFinder::MatchCallback { public: VerifyStartOfTranslationUnit() : Called(false) {} |