forked from OSchip/llvm-project
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
This commit is contained in:
parent
07c740e213
commit
bee085762b
|
@ -1398,6 +1398,13 @@ declCountIs(2)
|
||||||
</pre></td></tr>
|
</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>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.
|
<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>
|
</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>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.
|
<tr><td colspan="4" class="doc" id="isDefinition0"><pre>Matches if a declaration has a body attached.
|
||||||
|
|
||||||
|
|
|
@ -2945,6 +2945,26 @@ AST_MATCHER_P(NestedNameSpecifier, specifiesNamespace,
|
||||||
return InnerMatcher.matches(*Node.getAsNamespace(), Finder, Builder);
|
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 ast_matchers
|
||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
|
||||||
|
|
|
@ -3546,6 +3546,37 @@ TEST(MatchFinder, CanMatchSingleNodesRecursively) {
|
||||||
"X", recordDecl(has(recordDecl(hasName("X::Z")).bind("Z"))), "Z")));
|
"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 {
|
class VerifyStartOfTranslationUnit : public MatchFinder::MatchCallback {
|
||||||
public:
|
public:
|
||||||
VerifyStartOfTranslationUnit() : Called(false) {}
|
VerifyStartOfTranslationUnit() : Called(false) {}
|
||||||
|
|
Loading…
Reference in New Issue