r174315 - Add an eachOf matcher.
Manuel Klimek
klimek at google.com
Mon Feb 4 01:42:38 PST 2013
Author: klimek
Date: Mon Feb 4 03:42:38 2013
New Revision: 174315
URL: http://llvm.org/viewvc/llvm-project?rev=174315&view=rev
Log:
Add an eachOf matcher.
eachOf gives closure on the forEach and forEachDescendant matchers.
Before, it was impossible to implement a findAll matcher, as matching
the node or any of its descendants was not expressible (since anyOf
only triggers the first match).
Modified:
cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=174315&r1=174314&r2=174315&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Mon Feb 4 03:42:38 2013
@@ -1095,6 +1095,32 @@ const internal::VariadicDynCastAllOfMatc
/// \brief Matches \c TypeLocs in the clang AST.
const internal::VariadicDynCastAllOfMatcher<TypeLoc, TypeLoc> typeLoc;
+/// \brief Matches if any of the given matchers matches.
+///
+/// Unlike \c anyOf, \c eachOf will generate a match result for each
+/// matching submatcher.
+///
+/// For example, in:
+/// \code
+/// class A { int a; int b; };
+/// \endcode
+/// The matcher:
+/// \code
+/// recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")),
+/// has(fieldDecl(hasName("b")).bind("v"))))
+/// \endcode
+/// will generate two results binding "v", the first of which binds
+/// the field declaration of \c a, the second the field declaration of
+/// \c b.
+///
+/// Usable as: Any Matcher
+template <typename M1, typename M2>
+internal::PolymorphicMatcherWithParam2<internal::EachOfMatcher, M1, M2>
+eachOf(const M1 &P1, const M2 &P2) {
+ return internal::PolymorphicMatcherWithParam2<internal::EachOfMatcher, M1,
+ M2>(P1, P2);
+}
+
/// \brief Various overloads for the anyOf matcher.
/// @{
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=174315&r1=174314&r2=174315&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h Mon Feb 4 03:42:38 2013
@@ -832,21 +832,56 @@ private:
/// used. They will always be instantiated with types convertible to
/// Matcher<T>.
template <typename T, typename MatcherT1, typename MatcherT2>
+class EachOfMatcher : public MatcherInterface<T> {
+public:
+ EachOfMatcher(const Matcher<T> &InnerMatcher1,
+ const Matcher<T> &InnerMatcher2)
+ : InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) {
+ }
+
+ virtual bool matches(const T &Node, ASTMatchFinder *Finder,
+ BoundNodesTreeBuilder *Builder) const {
+ BoundNodesTreeBuilder Builder1;
+ bool Matched1 = InnerMatcher1.matches(Node, Finder, &Builder1);
+ if (Matched1)
+ Builder->addMatch(Builder1.build());
+
+ BoundNodesTreeBuilder Builder2;
+ bool Matched2 = InnerMatcher2.matches(Node, Finder, &Builder2);
+ if (Matched2)
+ Builder->addMatch(Builder2.build());
+
+ return Matched1 || Matched2;
+ }
+
+private:
+ const Matcher<T> InnerMatcher1;
+ const Matcher<T> InnerMatcher2;
+};
+
+/// \brief Matches nodes of type T for which at least one of the two provided
+/// matchers matches.
+///
+/// Type arguments MatcherT1 and MatcherT2 are
+/// required by PolymorphicMatcherWithParam2 but not actually
+/// used. They will always be instantiated with types convertible to
+/// Matcher<T>.
+template <typename T, typename MatcherT1, typename MatcherT2>
class AnyOfMatcher : public MatcherInterface<T> {
public:
AnyOfMatcher(const Matcher<T> &InnerMatcher1, const Matcher<T> &InnerMatcher2)
- : InnerMatcher1(InnerMatcher1), InnertMatcher2(InnerMatcher2) {}
+ : InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) {}
virtual bool matches(const T &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
return InnerMatcher1.matches(Node, Finder, Builder) ||
- InnertMatcher2.matches(Node, Finder, Builder);
+ InnerMatcher2.matches(Node, Finder, Builder);
}
private:
const Matcher<T> InnerMatcher1;
- const Matcher<T> InnertMatcher2;
+ const Matcher<T> InnerMatcher2;
};
/// \brief Creates a Matcher<T> that matches if all inner matchers match.
Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp?rev=174315&r1=174314&r2=174315&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp Mon Feb 4 03:42:38 2013
@@ -2854,6 +2854,30 @@ TEST(ForEachDescendant, BindsCorrectNode
new VerifyIdIsBoundTo<FunctionDecl>("decl", 1)));
}
+TEST(EachOf, TriggersForEachMatch) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class A { int a; int b; };",
+ recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")),
+ has(fieldDecl(hasName("b")).bind("v")))),
+ new VerifyIdIsBoundTo<FieldDecl>("v", 2)));
+}
+
+TEST(EachOf, BehavesLikeAnyOfUnlessBothMatch) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class A { int a; int c; };",
+ recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")),
+ has(fieldDecl(hasName("b")).bind("v")))),
+ new VerifyIdIsBoundTo<FieldDecl>("v", 1)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "class A { int c; int b; };",
+ recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")),
+ has(fieldDecl(hasName("b")).bind("v")))),
+ new VerifyIdIsBoundTo<FieldDecl>("v", 1)));
+ EXPECT_TRUE(notMatches(
+ "class A { int c; int d; };",
+ recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")),
+ has(fieldDecl(hasName("b")).bind("v"))))));
+}
TEST(IsTemplateInstantiation, MatchesImplicitClassTemplateInstantiation) {
// Make sure that we can both match the class by name (::X) and by the type
More information about the cfe-commits
mailing list