summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
authorManuel Klimek <klimek@google.com>2013-02-06 10:33:21 +0000
committerManuel Klimek <klimek@google.com>2013-02-06 10:33:21 +0000
commit2cff49e026879ad2f0c24de4a2c3168fb83c663e (patch)
treea82c5849fdb59188eb07e9610127056ede4b015e /clang
parentc697ad29ff7ffd13826bffa620650b725795034e (diff)
downloadbcm5719-llvm-2cff49e026879ad2f0c24de4a2c3168fb83c663e.tar.gz
bcm5719-llvm-2cff49e026879ad2f0c24de4a2c3168fb83c663e.zip
Adds a convenience function selectFirst to simplify matching.
A very common use case is to search for the first occurrence of a certain node that is a descendant of another node. In that case, selectFirst significantly simplifies the code at the client side. llvm-svn: 174499
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/ASTMatchers/ASTMatchFinder.h23
-rw-r--r--clang/unittests/ASTMatchers/ASTMatchersTest.cpp28
2 files changed, 39 insertions, 12 deletions
diff --git a/clang/include/clang/ASTMatchers/ASTMatchFinder.h b/clang/include/clang/ASTMatchers/ASTMatchFinder.h
index 44e1731646d..870a39b3911 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchFinder.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchFinder.h
@@ -172,6 +172,7 @@ private:
/// Multiple results occur when using matchers like \c forEachDescendant,
/// which generate a result for each sub-match.
///
+/// \see selectFirst
/// @{
template <typename MatcherT, typename NodeT>
SmallVector<BoundNodes, 1>
@@ -183,6 +184,28 @@ match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node,
ASTContext &Context);
/// @}
+/// \brief Returns the first result of type \c NodeT bound to \p BoundTo.
+///
+/// Returns \c NULL if there is no match, or if the matching node cannot be
+/// casted to \c NodeT.
+///
+/// This is useful in combanation with \c match():
+/// \code
+/// Decl *D = selectFirst<Decl>("id", match(Matcher.bind("id"),
+/// Node, Context));
+/// \endcode
+template <typename NodeT>
+NodeT *
+selectFirst(StringRef BoundTo, const SmallVectorImpl<BoundNodes> &Results) {
+ for (SmallVectorImpl<BoundNodes>::const_iterator I = Results.begin(),
+ E = Results.end();
+ I != E; ++I) {
+ if (NodeT *Node = I->getNodeAs<NodeT>(BoundTo))
+ return Node;
+ }
+ return NULL;
+}
+
namespace internal {
class CollectMatchesCallback : public MatchFinder::MatchCallback {
public:
diff --git a/clang/unittests/ASTMatchers/ASTMatchersTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp
index 8668b4970e7..60a79e86de3 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -3493,53 +3493,57 @@ TEST(NNSLoc, NestedNameSpecifierLocsAsDescendants) {
template <typename T> class VerifyMatchOnNode : public BoundNodesCallback {
public:
- VerifyMatchOnNode(StringRef Id, const internal::Matcher<T> &InnerMatcher)
- : Id(Id), InnerMatcher(InnerMatcher) {
+ VerifyMatchOnNode(StringRef Id, const internal::Matcher<T> &InnerMatcher,
+ StringRef InnerId)
+ : Id(Id), InnerMatcher(InnerMatcher), InnerId(InnerId) {
}
virtual bool run(const BoundNodes *Nodes) { return false; }
virtual bool run(const BoundNodes *Nodes, ASTContext *Context) {
const T *Node = Nodes->getNodeAs<T>(Id);
- SmallVector<BoundNodes, 1> Result = match(InnerMatcher, *Node, *Context);
- return !Result.empty();
+ return selectFirst<const T>(InnerId,
+ match(InnerMatcher, *Node, *Context)) != NULL;
}
private:
std::string Id;
internal::Matcher<T> InnerMatcher;
+ std::string InnerId;
};
TEST(MatchFinder, CanMatchDeclarationsRecursively) {
EXPECT_TRUE(matchAndVerifyResultTrue(
"class X { class Y {}; };", recordDecl(hasName("::X")).bind("X"),
new VerifyMatchOnNode<clang::Decl>(
- "X", decl(hasDescendant(recordDecl(hasName("X::Y")))))));
+ "X", decl(hasDescendant(recordDecl(hasName("X::Y")).bind("Y"))),
+ "Y")));
EXPECT_TRUE(matchAndVerifyResultFalse(
"class X { class Y {}; };", recordDecl(hasName("::X")).bind("X"),
new VerifyMatchOnNode<clang::Decl>(
- "X", decl(hasDescendant(recordDecl(hasName("X::Z")))))));
+ "X", decl(hasDescendant(recordDecl(hasName("X::Z")).bind("Z"))),
+ "Z")));
}
TEST(MatchFinder, CanMatchStatementsRecursively) {
EXPECT_TRUE(matchAndVerifyResultTrue(
"void f() { if (1) { for (;;) { } } }", ifStmt().bind("if"),
- new VerifyMatchOnNode<clang::Stmt>("if",
- stmt(hasDescendant(forStmt())))));
+ new VerifyMatchOnNode<clang::Stmt>(
+ "if", stmt(hasDescendant(forStmt().bind("for"))), "for")));
EXPECT_TRUE(matchAndVerifyResultFalse(
"void f() { if (1) { for (;;) { } } }", ifStmt().bind("if"),
- new VerifyMatchOnNode<clang::Stmt>("if",
- stmt(hasDescendant(declStmt())))));
+ new VerifyMatchOnNode<clang::Stmt>(
+ "if", stmt(hasDescendant(declStmt().bind("decl"))), "decl")));
}
TEST(MatchFinder, CanMatchSingleNodesRecursively) {
EXPECT_TRUE(matchAndVerifyResultTrue(
"class X { class Y {}; };", recordDecl(hasName("::X")).bind("X"),
new VerifyMatchOnNode<clang::Decl>(
- "X", recordDecl(has(recordDecl(hasName("X::Y")))))));
+ "X", recordDecl(has(recordDecl(hasName("X::Y")).bind("Y"))), "Y")));
EXPECT_TRUE(matchAndVerifyResultFalse(
"class X { class Y {}; };", recordDecl(hasName("::X")).bind("X"),
new VerifyMatchOnNode<clang::Decl>(
- "X", recordDecl(has(recordDecl(hasName("X::Z")))))));
+ "X", recordDecl(has(recordDecl(hasName("X::Z")).bind("Z"))), "Z")));
}
class VerifyStartOfTranslationUnit : public MatchFinder::MatchCallback {
OpenPOWER on IntegriCloud