Hi djasper,
First, this implements a match() method on MatchFinder; this allows us
to get rid of the findAll implementation, as findAll is really a special
case of forEachDescendant() on match.
Next, provides some convenience functions that make matching a lot nicer
when one already has an ASTContext:
- a match function that returns a vector of BoundNodes to iterate over
- findAll functions that return a vector of T* for a given
BindableMatcher<T>, which is the common use case for the more generic
findAll on MatchFinder that's deleted in this change.
http://llvm-reviews.chandlerc.com/D359
Files:
include/clang/ASTMatchers/ASTMatchFinder.h
lib/ASTMatchers/ASTMatchFinder.cpp
unittests/ASTMatchers/ASTMatchersTest.cpp
Index: include/clang/ASTMatchers/ASTMatchFinder.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchFinder.h
+++ include/clang/ASTMatchers/ASTMatchFinder.h
@@ -134,11 +134,17 @@
/// \brief Creates a clang ASTConsumer that finds all matches.
clang::ASTConsumer *newASTConsumer();
- /// \brief Finds all matches on the given \c Node.
+ /// \brief Triggers on all matches on the given \c Node.
+ ///
+ /// Note that there can be multiple matches on a single node, for
+ /// example when using decl(forEachDescendant(stmt())).
///
/// @{
- void findAll(const Decl &Node, ASTContext &Context);
- void findAll(const Stmt &Node, ASTContext &Context);
+ template <typename T> void match(const T &Node, ASTContext &Context) {
+ match(clang::ast_type_traits::DynTypedNode::create(Node), Context);
+ }
+ void match(const clang::ast_type_traits::DynTypedNode &Node,
+ ASTContext &Context);
/// @}
/// \brief Registers a callback to notify the end of parsing.
@@ -158,6 +164,83 @@
ParsingDoneTestCallback *ParsingDone;
};
+/// \brief Returns the results of matching \c Matcher on \c Node.
+///
+/// @{
+template <typename MatcherT, typename NodeT>
+SmallVector<BoundNodes, 1>
+match(MatcherT Matcher, const NodeT &Node, ASTContext &Context);
+
+template <typename MatcherT>
+SmallVector<BoundNodes, 1>
+match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node,
+ ASTContext &Context);
+/// @}
+
+/// \brief Returns all nodes that match \c Matcher under \c Node.
+///
+/// @{
+template <typename T>
+SmallVector<const T *, 1> findAll(internal::BindableMatcher<T> Matcher,
+ const Stmt &Node, ASTContext &Context);
+template <typename T>
+SmallVector<const T *, 1> findAll(internal::BindableMatcher<T> Matcher,
+ const Decl &Node, ASTContext &Context);
+/// @}
+
+namespace internal {
+class CollectMatchesCallback : public MatchFinder::MatchCallback {
+public:
+ virtual void run(const MatchFinder::MatchResult &Result) {
+ Nodes.push_back(Result.Nodes);
+ }
+ SmallVector<BoundNodes, 1> Nodes;
+};
+}
+
+template <typename MatcherT>
+SmallVector<BoundNodes, 1>
+match(MatcherT Matcher, const ast_type_traits::DynTypedNode &Node,
+ ASTContext &Context) {
+ internal::CollectMatchesCallback Callback;
+ MatchFinder Finder;
+ Finder.addMatcher(Matcher, &Callback);
+ Finder.match(Node, Context);
+ return Callback.Nodes;
+}
+
+template <typename MatcherT, typename NodeT>
+SmallVector<BoundNodes, 1>
+match(MatcherT Matcher, const NodeT &Node, ASTContext &Context) {
+ return match(Matcher, ast_type_traits::DynTypedNode::create(Node), Context);
+}
+
+template <typename T>
+SmallVector<const T *, 1> findAll(internal::BindableMatcher<T> Matcher,
+ const Stmt &Node, ASTContext &Context) {
+ SmallVector<BoundNodes, 1> Nodes =
+ match(stmt(forEachDescendant(Matcher.bind(""))),
+ ast_type_traits::DynTypedNode::create(Node), Context);
+ SmallVector<const T *, 1> Result(Nodes.size());
+ for (int i = 0, e = Nodes.size(); i != e; ++i) {
+ Result[i] = Nodes[i].getNodeAs<T>("");
+ }
+ return Result;
+}
+
+template <typename T>
+SmallVector<const T *, 1> findAll(internal::BindableMatcher<T> Matcher,
+ const Decl &Node, ASTContext &Context) {
+ SmallVector<BoundNodes, 1> Nodes =
+ match(decl(forEachDescendant(Matcher.bind(""))),
+ ast_type_traits::DynTypedNode::create(Node), Context);
+ SmallVector<const T *, 1> Result(Nodes.size());
+ for (int i = 0, e = Nodes.size(); i != e; ++i) {
+ Result[i] = Nodes[i].getNodeAs<T>("");
+ }
+ return Result;
+}
+
} // end namespace ast_matchers
} // end namespace clang
Index: lib/ASTMatchers/ASTMatchFinder.cpp
===================================================================
--- lib/ASTMatchers/ASTMatchFinder.cpp
+++ lib/ASTMatchers/ASTMatchFinder.cpp
@@ -467,6 +467,26 @@
return matchesAncestorOfRecursively(Node, Matcher, Builder, MatchMode);
}
+ // Matches all registered matchers on the given node and calls the
+ // result callback for every node that matches.
+ void match(const ast_type_traits::DynTypedNode& Node) {
+ for (std::vector<std::pair<const internal::DynTypedMatcher*,
+ MatchCallback*> >::const_iterator
+ I = MatcherCallbackPairs->begin(), E = MatcherCallbackPairs->end();
+ I != E; ++I) {
+ BoundNodesTreeBuilder Builder;
+ if (I->first->matches(Node, this, &Builder)) {
+ BoundNodesTree BoundNodes = Builder.build();
+ MatchVisitor Visitor(ActiveASTContext, I->second);
+ BoundNodes.visitMatches(&Visitor);
+ }
+ }
+ }
+
+ template <typename T> void match(const T &Node) {
+ match(ast_type_traits::DynTypedNode::create(Node));
+ }
+
// Implements ASTMatchFinder::getASTContext.
virtual ASTContext &getASTContext() const { return *ActiveASTContext; }
@@ -544,24 +564,6 @@
return false;
}
- // Matches all registered matchers on the given node and calls the
- // result callback for every node that matches.
- template <typename T>
- void match(const T &node) {
- for (std::vector<std::pair<const internal::DynTypedMatcher*,
- MatchCallback*> >::const_iterator
- I = MatcherCallbackPairs->begin(), E = MatcherCallbackPairs->end();
- I != E; ++I) {
- BoundNodesTreeBuilder Builder;
- if (I->first->matches(ast_type_traits::DynTypedNode::create(node),
- this, &Builder)) {
- BoundNodesTree BoundNodes = Builder.build();
- MatchVisitor Visitor(ActiveASTContext, I->second);
- BoundNodes.visitMatches(&Visitor);
- }
- }
- }
-
std::vector<std::pair<const internal::DynTypedMatcher*,
MatchCallback*> > *const MatcherCallbackPairs;
ASTContext *ActiveASTContext;
@@ -777,16 +779,11 @@
return new internal::MatchASTConsumer(&MatcherCallbackPairs, ParsingDone);
}
-void MatchFinder::findAll(const Decl &Node, ASTContext &Context) {
- internal::MatchASTVisitor Visitor(&MatcherCallbackPairs);
- Visitor.set_active_ast_context(&Context);
- Visitor.TraverseDecl(const_cast<Decl*>(&Node));
-}
-
-void MatchFinder::findAll(const Stmt &Node, ASTContext &Context) {
+void MatchFinder::match(const clang::ast_type_traits::DynTypedNode &Node,
+ ASTContext &Context) {
internal::MatchASTVisitor Visitor(&MatcherCallbackPairs);
Visitor.set_active_ast_context(&Context);
- Visitor.TraverseStmt(const_cast<Stmt*>(&Node));
+ Visitor.match(Node);
}
void MatchFinder::registerTestCallbackAfterParsing(
Index: unittests/ASTMatchers/ASTMatchersTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -3439,46 +3439,72 @@
new VerifyIdIsBoundTo<NestedNameSpecifierLoc>("x", 3)));
}
-template <typename T>
-class VerifyRecursiveMatch : public BoundNodesCallback {
+template <typename T> class VerifyRecursiveMatch : public BoundNodesCallback {
public:
- explicit VerifyRecursiveMatch(StringRef Id,
- const internal::Matcher<T> &InnerMatcher)
- : Id(Id), InnerMatcher(InnerMatcher) {}
-
- virtual bool run(const BoundNodes *Nodes) {
- return false;
+ explicit VerifyRecursiveMatch(
+ StringRef Id, const internal::BindableMatcher<T> &InnerMatcher)
+ : Id(Id), InnerMatcher(InnerMatcher) {
}
+ virtual bool run(const BoundNodes *Nodes) { return false; }
+
virtual bool run(const BoundNodes *Nodes, ASTContext *Context) {
const T *Node = Nodes->getNodeAs<T>(Id);
- bool Found = false;
- MatchFinder Finder;
- Finder.addMatcher(InnerMatcher, new VerifyMatch(0, &Found));
- Finder.findAll(*Node, *Context);
- return Found;
+ SmallVector<const T *, 1> Result =
+ findAll<T>(InnerMatcher, *Node, *Context);
+ return !Result.empty();
}
private:
std::string Id;
- internal::Matcher<T> InnerMatcher;
+ internal::BindableMatcher<T> InnerMatcher;
};
TEST(MatchFinder, CanMatchDeclarationsRecursively) {
- EXPECT_TRUE(matchAndVerifyResultTrue("class X { class Y {}; };",
- recordDecl(hasName("::X")).bind("X"),
- new VerifyRecursiveMatch<clang::Decl>("X", recordDecl(hasName("X::Y")))));
- EXPECT_TRUE(matchAndVerifyResultFalse("class X { class Y {}; };",
- recordDecl(hasName("::X")).bind("X"),
- new VerifyRecursiveMatch<clang::Decl>("X", recordDecl(hasName("X::Z")))));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class X { class Y {}; };", recordDecl(hasName("::X")).bind("X"),
+ new VerifyRecursiveMatch<clang::Decl>("X", recordDecl(hasName("X::Y")))));
+ EXPECT_TRUE(matchAndVerifyResultFalse(
+ "class X { class Y {}; };", recordDecl(hasName("::X")).bind("X"),
+ new VerifyRecursiveMatch<clang::Decl>("X", recordDecl(hasName("X::Z")))));
}
TEST(MatchFinder, CanMatchStatementsRecursively) {
- EXPECT_TRUE(matchAndVerifyResultTrue("void f() { if (1) { for (;;) { } } }",
- ifStmt().bind("if"),
- new VerifyRecursiveMatch<clang::Stmt>("if", forStmt())));
- EXPECT_TRUE(matchAndVerifyResultFalse("void f() { if (1) { for (;;) { } } }",
- ifStmt().bind("if"),
- new VerifyRecursiveMatch<clang::Stmt>("if", declStmt())));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "void f() { if (1) { for (;;) { } } }", ifStmt().bind("if"),
+ new VerifyRecursiveMatch<clang::Stmt>("if", forStmt())));
+ EXPECT_TRUE(matchAndVerifyResultFalse(
+ "void f() { if (1) { for (;;) { } } }", ifStmt().bind("if"),
+ new VerifyRecursiveMatch<clang::Stmt>("if", declStmt())));
+}
+
+template <typename T> class VerifyMatchOnNode : public BoundNodesCallback {
+public:
+ explicit VerifyMatchOnNode(StringRef Id,
+ const internal::Matcher<T> &InnerMatcher)
+ : Id(Id), InnerMatcher(InnerMatcher) {
+ }
+
+ 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();
+ }
+private:
+ std::string Id;
+ internal::Matcher<T> InnerMatcher;
+};
+
+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")))))));
+ EXPECT_TRUE(matchAndVerifyResultFalse(
+ "class X { class Y {}; };", recordDecl(hasName("::X")).bind("X"),
+ new VerifyMatchOnNode<clang::Decl>(
+ "X", recordDecl(has(recordDecl(hasName("X::Z")))))));
}
class VerifyStartOfTranslationUnit : public MatchFinder::MatchCallback {
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits