<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Feb 4, 2013 at 10:42 AM, Manuel Klimek <span dir="ltr"><<a href="mailto:klimek@google.com" target="_blank" class="cremed">klimek@google.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: klimek<br>
Date: Mon Feb  4 03:42:38 2013<br>
New Revision: 174315<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=174315&view=rev" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project?rev=174315&view=rev</a><br>
Log:<br>
Add an eachOf matcher.<br>
<br>
eachOf gives closure on the forEach and forEachDescendant matchers.<br>
Before, it was impossible to implement a findAll matcher, as matching<br>
the node or any of its descendants was not expressible (since anyOf<br>
only triggers the first match).<br>
<br>
Modified:<br>
    cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h<br>
    cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h<br>
    cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp<br>
<br>
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=174315&r1=174314&r2=174315&view=diff" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=174315&r1=174314&r2=174315&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original)<br>
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Mon Feb  4 03:42:38 2013<br>
@@ -1095,6 +1095,32 @@ const internal::VariadicDynCastAllOfMatc<br>
 /// \brief Matches \c TypeLocs in the clang AST.<br>
 const internal::VariadicDynCastAllOfMatcher<TypeLoc, TypeLoc> typeLoc;<br>
<br>
+/// \brief Matches if any of the given matchers matches.<br>
+///<br>
+/// Unlike \c anyOf, \c eachOf will generate a match result for each<br>
+/// matching submatcher.<br>
+///<br>
+/// For example, in:<br>
+/// \code<br>
+///   class A { int a; int b; };<br>
+/// \endcode<br>
+/// The matcher:<br>
+/// \code<br>
+///   recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")),<br>
+///                     has(fieldDecl(hasName("b")).bind("v"))))<br>
+/// \endcode<br>
+/// will generate two results binding "v", the first of which binds<br>
+/// the field declaration of \c a, the second the field declaration of<br>
+/// \c b.<br>
+///<br>
+/// Usable as: Any Matcher<br>
+template <typename M1, typename M2><br>
+internal::PolymorphicMatcherWithParam2<internal::EachOfMatcher, M1, M2><br>
+eachOf(const M1 &P1, const M2 &P2) {<br>
+  return internal::PolymorphicMatcherWithParam2<internal::EachOfMatcher, M1,<br>
+                                                M2>(P1, P2);<br>
+}<br>
+<br></blockquote><div><br></div><div style>Should we add more overloads (similar to anyOf and allOf)?</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

 /// \brief Various overloads for the anyOf matcher.<br>
 /// @{<br>
<br>
<br>
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=174315&r1=174314&r2=174315&view=diff" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=174315&r1=174314&r2=174315&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h (original)<br>
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h Mon Feb  4 03:42:38 2013<br>
@@ -832,21 +832,56 @@ private:<br>
 /// used. They will always be instantiated with types convertible to<br>
 /// Matcher<T>.<br>
 template <typename T, typename MatcherT1, typename MatcherT2><br>
+class EachOfMatcher : public MatcherInterface<T> {<br>
+public:<br>
+  EachOfMatcher(const Matcher<T> &InnerMatcher1,<br>
+                const Matcher<T> &InnerMatcher2)<br>
+      : InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) {<br>
+  }<br>
+<br>
+  virtual bool matches(const T &Node, ASTMatchFinder *Finder,<br>
+                       BoundNodesTreeBuilder *Builder) const {<br>
+    BoundNodesTreeBuilder Builder1;<br></blockquote><div><br></div><div style>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.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+    bool Matched1 = InnerMatcher1.matches(Node, Finder, &Builder1);<br>
+    if (Matched1)<br>
+      Builder->addMatch(Builder1.build());<br>
+<br>
+    BoundNodesTreeBuilder Builder2;<br>
+    bool Matched2 = InnerMatcher2.matches(Node, Finder, &Builder2);<br>
+    if (Matched2)<br>
+      Builder->addMatch(Builder2.build());<br>
+<br>
+    return Matched1 || Matched2;<br>
+  }<br>
+<br>
+private:<br>
+  const Matcher<T> InnerMatcher1;<br>
+  const Matcher<T> InnerMatcher2;<br>
+};<br>
+<br>
+/// \brief Matches nodes of type T for which at least one of the two provided<br>
+/// matchers matches.<br>
+///<br>
+/// Type arguments MatcherT1 and MatcherT2 are<br>
+/// required by PolymorphicMatcherWithParam2 but not actually<br>
+/// used. They will always be instantiated with types convertible to<br>
+/// Matcher<T>.<br>
+template <typename T, typename MatcherT1, typename MatcherT2><br>
 class AnyOfMatcher : public MatcherInterface<T> {<br>
 public:<br>
   AnyOfMatcher(const Matcher<T> &InnerMatcher1, const Matcher<T> &InnerMatcher2)<br>
-      : InnerMatcher1(InnerMatcher1), InnertMatcher2(InnerMatcher2) {}<br>
+      : InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) {}<br>
<br>
   virtual bool matches(const T &Node,<br>
                        ASTMatchFinder *Finder,<br>
                        BoundNodesTreeBuilder *Builder) const {<br>
     return InnerMatcher1.matches(Node, Finder, Builder) ||<br>
-           InnertMatcher2.matches(Node, Finder, Builder);<br>
+           InnerMatcher2.matches(Node, Finder, Builder);<br>
   }<br>
<br>
 private:<br>
   const Matcher<T> InnerMatcher1;<br>
-  const Matcher<T> InnertMatcher2;<br>
+  const Matcher<T> InnerMatcher2;<br>
 };<br>
<br>
 /// \brief Creates a Matcher<T> that matches if all inner matchers match.<br>
<br>
Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp?rev=174315&r1=174314&r2=174315&view=diff" target="_blank" class="cremed">http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp?rev=174315&r1=174314&r2=174315&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp (original)<br>
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp Mon Feb  4 03:42:38 2013<br>
@@ -2854,6 +2854,30 @@ TEST(ForEachDescendant, BindsCorrectNode<br>
       new VerifyIdIsBoundTo<FunctionDecl>("decl", 1)));<br>
 }<br>
<br>
+TEST(EachOf, TriggersForEachMatch) {<br>
+  EXPECT_TRUE(matchAndVerifyResultTrue(<br>
+      "class A { int a; int b; };",<br>
+      recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")),<br>
+                        has(fieldDecl(hasName("b")).bind("v")))),<br>
+      new VerifyIdIsBoundTo<FieldDecl>("v", 2)));<br>
+}<br></blockquote><div><br></div><div style>Probably not important at all, but it might be nice to show that you also get two results if you bind the outer recordDecl()..</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

+<br>
+TEST(EachOf, BehavesLikeAnyOfUnlessBothMatch) {<br>
+  EXPECT_TRUE(matchAndVerifyResultTrue(<br>
+      "class A { int a; int c; };",<br>
+      recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")),<br>
+                        has(fieldDecl(hasName("b")).bind("v")))),<br>
+      new VerifyIdIsBoundTo<FieldDecl>("v", 1)));<br>
+  EXPECT_TRUE(matchAndVerifyResultTrue(<br>
+      "class A { int c; int b; };",<br>
+      recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")),<br>
+                        has(fieldDecl(hasName("b")).bind("v")))),<br>
+      new VerifyIdIsBoundTo<FieldDecl>("v", 1)));<br>
+  EXPECT_TRUE(notMatches(<br>
+      "class A { int c; int d; };",<br>
+      recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")),<br>
+                        has(fieldDecl(hasName("b")).bind("v"))))));<br>
+}<br>
<br>
 TEST(IsTemplateInstantiation, MatchesImplicitClassTemplateInstantiation) {<br>
   // Make sure that we can both match the class by name (::X) and by the type<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu" class="cremed">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank" class="cremed">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div></div>