<div dir="ltr">On Mon, Feb 4, 2013 at 8:19 PM, Daniel Jasper <span dir="ltr"><<a href="mailto:djasper@google.com" target="_blank">djasper@google.com</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote">
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote"><div><div class="h5">On Mon, Feb 4, 2013 at 10:42 AM, Manuel Klimek <span dir="ltr"><<a href="mailto:klimek@google.com" target="_blank">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">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">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></div><div>Should we add more overloads (similar to anyOf and allOf)?</div></div></div></div></blockquote><div><br></div><div style>I don't think that's needed. It shouldn't be too common to use this.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div class="im"><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">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><div>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></div></blockquote><div><br></div><div style>I think it would be strange to not have symmetry in how the results are handled here - for example, if we use the Builder for the first match, then the second match still would have all bindings from the first match, which IMO doesn't make sense... (note that those cannot happen the same way for anyOf, as only one can match - there are still strange cases with anyOf, but I'd rather fix those than make this one strange).</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><div class="h5">
<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">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></div><div>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 class="im"><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" target="_blank">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div></div><br></div></div>
</blockquote></div><br></div></div>