On Mon, Feb 4, 2013 at 10:42 AM, Manuel Klimek <[email protected]> wrote:
> 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); > +} > + > Should we add more overloads (similar to anyOf and allOf)? > /// \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; > Could you directly use \p Builder for one of these? (I think we do that at some other place(s) and thus it would be slightly more consistent. > + 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))); > +} > Probably not important at all, but it might be nice to show that you also get two results if you bind the outer recordDecl().. > + > +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 > > > _______________________________________________ > cfe-commits mailing list > [email protected] > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
