r174315 - Add an eachOf matcher.

Daniel Jasper djasper at google.com
Mon Feb 4 11:19:25 PST 2013


On Mon, Feb 4, 2013 at 10:42 AM, Manuel Klimek <klimek at google.com> 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
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130204/e8763163/attachment.html>


More information about the cfe-commits mailing list