From: Samuel Benzaquen Date: Tue, 27 Aug 2013 15:11:16 +0000 (+0000) Subject: Rewrite eachOf/allOf/anyOf to use a variadic operator. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d36e46350b50907425bba0db1b3ddfb46cc1637f;p=clang Rewrite eachOf/allOf/anyOf to use a variadic operator. Summary: Rewrite eachOf/allOf/anyOf to use a variadic operator, instead of hand-written calls to Polymorphic matchers. This simplifies their definition and future changes to add them to the dynamic registry. Reviewers: klimek CC: cfe-commits, revane Differential Revision: http://llvm-reviews.chandlerc.com/D1427 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@189357 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html index 544e06dc7b..6f8f6a07c7 100644 --- a/docs/LibASTMatchersReference.html +++ b/docs/LibASTMatchersReference.html @@ -1273,14 +1273,14 @@ which allow users to create more powerful match expressions.

Return typeNameParameters -Matcher<*>allOfMatcher<*> P1, Matcher<*> P2 +Matcher<*>allOfMatcher<*>, ..., Matcher<*>
Matches if all given matchers match.
 
 Usable as: Any Matcher
 
-Matcher<*>anyOfMatcher<*> P1, Matcher<*> P2 +Matcher<*>anyOfMatcher<*>, ..., Matcher<*>
Matches if any of the given matchers matches.
 
 Usable as: Any Matcher
@@ -1999,7 +1999,7 @@ match expressions.

Return typeNameParameters -Matcher<*>eachOfMatcher<*> P1, Matcher<*> P2 +Matcher<*>eachOfMatcher<*>, ..., Matcher<*>
Matches if any of the given matchers matches.
 
 Unlike anyOf, eachOf will generate a match result for each
@@ -2018,21 +2018,6 @@ Usable as: Any Matcher
 
-Matcher<*>findAllMatcher<T> Matcher -
Matches if the node or any descendant matches.
-
-Generates results for each match.
-
-For example, in:
-  class A { class B {}; class C {}; };
-The matcher:
-  recordDecl(hasName("::A"), findAll(recordDecl(isDefinition()).bind("m")))
-will generate results for A, B and C.
-
-Usable as: Any Matcher
-
- - Matcher<*>forEachMatcher<*>
Matches AST nodes that have child AST nodes that match the
 provided matcher.
@@ -3316,6 +3301,21 @@ Usable as: Matcher<findAllMatcher<T>  Matcher
+
Matches if the node or any descendant matches.
+
+Generates results for each match.
+
+For example, in:
+  class A { class B {}; class C {}; };
+The matcher:
+  recordDecl(hasName("::A"), findAll(recordDecl(isDefinition()).bind("m")))
+will generate results for A, B and C.
+
+Usable as: Any Matcher
+
+ + Matcher<TypeLoc>locMatcher<QualType> InnerMatcher
Matches TypeLocs for which the given inner
 QualType-matcher matches.
diff --git a/docs/tools/dump_ast_matchers.py b/docs/tools/dump_ast_matchers.py
index e72426eafb..6a8687715f 100644
--- a/docs/tools/dump_ast_matchers.py
+++ b/docs/tools/dump_ast_matchers.py
@@ -239,6 +239,15 @@ def act_on_decl(declaration, comment, allowed_types):
       add_matcher('*', name, 'Matcher<*>', comment)
       return
 
+    # Parse Variadic operator matchers.
+    m = re.match(
+        r"""^.*VariadicOperatorMatcherFunc\s*([a-zA-Z]*)\s*=\s*{.*};$""",
+        declaration, flags=re.X)
+    if m:
+      name = m.groups()[0]
+      add_matcher('*', name, 'Matcher<*>, ..., Matcher<*>', comment)
+      return
+
 
     # Parse free standing matcher functions, like:
     #   Matcher Name(Matcher InnerMatcher) {
@@ -309,7 +318,7 @@ for line in open(MATCHERS_FILE).read().splitlines():
     declaration += ' ' + line
     if ((not line.strip()) or 
         line.rstrip()[-1] == ';' or
-        line.rstrip()[-1] == '{'):
+        (line.rstrip()[-1] == '{' and line.rstrip()[-3:] != '= {')):
       if line.strip() and line.rstrip()[-1] == '{':
         body = True
       else:
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index 6cf47d6c0f..cad9c404b4 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -1297,93 +1297,23 @@ const internal::VariadicAllOfMatcher typeLoc;
 /// \c b.
 ///
 /// Usable as: Any Matcher
-template 
-internal::PolymorphicMatcherWithParam2
-eachOf(const M1 &P1, const M2 &P2) {
-  return internal::PolymorphicMatcherWithParam2(P1, P2);
-}
-
-/// \brief Various overloads for the anyOf matcher.
-/// @{
+const internal::VariadicOperatorMatcherFunc eachOf = {
+  internal::EachOfVariadicOperator
+};
 
 /// \brief Matches if any of the given matchers matches.
 ///
 /// Usable as: Any Matcher
-template
-internal::PolymorphicMatcherWithParam2
-anyOf(const M1 &P1, const M2 &P2) {
-  return internal::PolymorphicMatcherWithParam2(P1, P2);
-}
-template
-internal::PolymorphicMatcherWithParam2 >
-anyOf(const M1 &P1, const M2 &P2, const M3 &P3) {
-  return anyOf(P1, anyOf(P2, P3));
-}
-template
-internal::PolymorphicMatcherWithParam2 > >
-anyOf(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4) {
-  return anyOf(P1, anyOf(P2, anyOf(P3, P4)));
-}
-template
-internal::PolymorphicMatcherWithParam2 > > >
-anyOf(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4, const M5 &P5) {
-  return anyOf(P1, anyOf(P2, anyOf(P3, anyOf(P4, P5))));
-}
-
-/// @}
-
-/// \brief Various overloads for the allOf matcher.
-/// @{
+const internal::VariadicOperatorMatcherFunc anyOf = {
+  internal::AnyOfVariadicOperator
+};
 
 /// \brief Matches if all given matchers match.
 ///
 /// Usable as: Any Matcher
-template 
-internal::PolymorphicMatcherWithParam2
-allOf(const M1 &P1, const M2 &P2) {
-  return internal::PolymorphicMatcherWithParam2(
-      P1, P2);
-}
-template 
-internal::PolymorphicMatcherWithParam2<
-    internal::AllOfMatcher, M1,
-    internal::PolymorphicMatcherWithParam2 >
-allOf(const M1 &P1, const M2 &P2, const M3 &P3) {
-  return allOf(P1, allOf(P2, P3));
-}
-template 
-internal::PolymorphicMatcherWithParam2<
-    internal::AllOfMatcher, M1,
-    internal::PolymorphicMatcherWithParam2<
-        internal::AllOfMatcher, M2, internal::PolymorphicMatcherWithParam2<
-                                        internal::AllOfMatcher, M3, M4> > >
-allOf(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4) {
-  return allOf(P1, allOf(P2, P3, P4));
-}
-template 
-internal::PolymorphicMatcherWithParam2<
-    internal::AllOfMatcher, M1,
-    internal::PolymorphicMatcherWithParam2<
-        internal::AllOfMatcher, M2,
-        internal::PolymorphicMatcherWithParam2<
-            internal::AllOfMatcher, M3,
-            internal::PolymorphicMatcherWithParam2 > > >
-allOf(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4, const M5 &P5) {
-  return allOf(P1, allOf(P2, P3, P4, P5));
-}
-
-/// @}
+const internal::VariadicOperatorMatcherFunc allOf = {
+  internal::AllOfVariadicOperator
+};
 
 /// \brief Matches sizeof (C99), alignof (C++11) and vec_step (OpenCL)
 ///
@@ -1678,11 +1608,7 @@ forEachDescendant = {};
 ///
 /// Usable as: Any Matcher
 template 
-internal::PolymorphicMatcherWithParam2<
-    internal::EachOfMatcher, internal::Matcher,
-    internal::ArgumentAdaptingMatcherFunc<
-        internal::ForEachDescendantMatcher>::Adaptor >
-findAll(const internal::Matcher &Matcher) {
+internal::Matcher findAll(const internal::Matcher &Matcher) {
   return eachOf(Matcher, forEachDescendant(Matcher));
 }
 
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
index b3eea63915..bb1793b727 100644
--- a/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1080,115 +1080,161 @@ private:
   const Matcher InnerMatcher;
 };
 
-/// \brief Matches nodes of type T for which both provided matchers match.
-///
-/// Type arguments MatcherT1 and MatcherT2 are required by
-/// PolymorphicMatcherWithParam2 but not actually used. They will
-/// always be instantiated with types convertible to Matcher.
-template 
-class AllOfMatcher : public MatcherInterface {
+/// \brief VariadicOperatorMatcher related types.
+/// @{
+
+/// \brief Function signature for any variadic operator. It takes the inner
+///   matchers as an array of DynTypedMatcher.
+typedef bool (*VariadicOperatorFunction)(
+    const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder,
+    BoundNodesTreeBuilder *Builder,
+    ArrayRef InnerMatchers);
+
+/// \brief \c MatcherInterface implementation for an variadic operator.
+template 
+class VariadicOperatorMatcherInterface : public MatcherInterface {
 public:
-  AllOfMatcher(const Matcher &InnerMatcher1, const Matcher &InnerMatcher2)
-      : InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) {}
+  VariadicOperatorMatcherInterface(VariadicOperatorFunction Func,
+                                   ArrayRef *> InputMatchers)
+      : Func(Func) {
+    for (size_t i = 0, e = InputMatchers.size(); i != e; ++i) {
+      InnerMatchers.push_back(new Matcher(*InputMatchers[i]));
+    }
+  }
 
-  virtual bool matches(const T &Node,
-                       ASTMatchFinder *Finder,
+  ~VariadicOperatorMatcherInterface() {
+    llvm::DeleteContainerPointers(InnerMatchers);
+  }
+
+  virtual bool matches(const T &Node, ASTMatchFinder *Finder,
                        BoundNodesTreeBuilder *Builder) const {
-    // allOf leads to one matcher for each alternative in the first
-    // matcher combined with each alternative in the second matcher.
-    // Thus, we can reuse the same Builder.
-    return InnerMatcher1.matches(Node, Finder, Builder) &&
-           InnerMatcher2.matches(Node, Finder, Builder);
+    return Func(ast_type_traits::DynTypedNode::create(Node), Finder, Builder,
+                InnerMatchers);
   }
 
 private:
-  const Matcher InnerMatcher1;
-  const Matcher InnerMatcher2;
+  const VariadicOperatorFunction Func;
+  std::vector InnerMatchers;
 };
 
-/// \brief Matches nodes of type T for which at least one of the two provided
-/// matchers matches.
+/// \brief "No argument" placeholder to use as template paratemers.
+struct VariadicOperatorNoArg {};
+
+/// \brief Polymorphic matcher object that uses a \c VariadicOperatorFunction
+///   operator.
 ///
-/// Type arguments MatcherT1 and MatcherT2 are
-/// required by PolymorphicMatcherWithParam2 but not actually
-/// used. They will always be instantiated with types convertible to
-/// Matcher.
-template 
-class EachOfMatcher : public MatcherInterface {
+/// Input matchers can have any type (including other polymorphic matcher
+/// types), and the actual Matcher is generated on demand with an implicit
+/// coversion operator.
+template 
+class VariadicOperatorMatcher {
 public:
-  EachOfMatcher(const Matcher &InnerMatcher1,
-                const Matcher &InnerMatcher2)
-      : InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) {
+  VariadicOperatorMatcher(VariadicOperatorFunction Func, const P1 &Param1,
+                          const P2 &Param2,
+                          const P3 &Param3 = VariadicOperatorNoArg(),
+                          const P4 &Param4 = VariadicOperatorNoArg(),
+                          const P5 &Param5 = VariadicOperatorNoArg())
+      : Func(Func), Param1(Param1), Param2(Param2), Param3(Param3),
+        Param4(Param4), Param5(Param5) {}
+
+  template  operator Matcher() const {
+    Matcher *Array[5];
+    size_t Size = 0;
+
+    addMatcher(Param1, Array, Size);
+    addMatcher(Param2, Array, Size);
+    addMatcher(Param3, Array, Size);
+    addMatcher(Param4, Array, Size);
+    addMatcher(Param5, Array, Size);
+    Matcher Result(new VariadicOperatorMatcherInterface(
+        Func, ArrayRef *>(Array, Size)));
+    for (size_t i = 0, e = Size; i != e; ++i) delete Array[i];
+    return Result;
   }
 
-  virtual bool matches(const T &Node, ASTMatchFinder *Finder,
-                       BoundNodesTreeBuilder *Builder) const {
-    BoundNodesTreeBuilder Result;
-    BoundNodesTreeBuilder Builder1(*Builder);
-    bool Matched1 = InnerMatcher1.matches(Node, Finder, &Builder1);
-    if (Matched1)
-      Result.addMatch(Builder1);
-
-    BoundNodesTreeBuilder Builder2(*Builder);
-    bool Matched2 = InnerMatcher2.matches(Node, Finder, &Builder2);
-    if (Matched2)
-      Result.addMatch(Builder2);
-
-    *Builder = Result;
-    return Matched1 || Matched2;
+private:
+  template 
+  static void addMatcher(const Matcher &M, Matcher **Array,
+                         size_t &Size) {
+    Array[Size++] = new Matcher(M);
   }
 
-private:
-  const Matcher InnerMatcher1;
-  const Matcher InnerMatcher2;
+  /// \brief Overload to ignore \c VariadicOperatorNoArg arguments.
+  template 
+  static void addMatcher(VariadicOperatorNoArg, Matcher **Array,
+                         size_t &Size) {}
+
+  const VariadicOperatorFunction Func;
+  const P1 Param1;
+  const P2 Param2;
+  const P3 Param3;
+  const P4 Param4;
+  const P5 Param5;
 };
 
-/// \brief Matches nodes of type T for which at least one of the two provided
-/// matchers matches.
+/// \brief Overloaded function object to generate VariadicOperatorMatcher
+///   objects from arbitrary matchers.
 ///
-/// Type arguments MatcherT1 and MatcherT2 are
-/// required by PolymorphicMatcherWithParam2 but not actually
-/// used. They will always be instantiated with types convertible to
-/// Matcher.
-template 
-class AnyOfMatcher : public MatcherInterface {
-public:
-  AnyOfMatcher(const Matcher &InnerMatcher1, const Matcher &InnerMatcher2)
-      : InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) {}
+/// It supports 2-5 argument overloaded operator(). More can be added if needed.
+struct VariadicOperatorMatcherFunc {
+  VariadicOperatorFunction Func;
 
-  virtual bool matches(const T &Node,
-                       ASTMatchFinder *Finder,
-                       BoundNodesTreeBuilder *Builder) const {
-    BoundNodesTreeBuilder Result = *Builder;
-    if (InnerMatcher1.matches(Node, Finder, &Result)) {
-      *Builder = Result;
-      return true;
-    }
-    Result = *Builder;
-    if (InnerMatcher2.matches(Node, Finder, &Result)) {
-      *Builder = Result;
-      return true;
-    }
-    return false;
+  template 
+  VariadicOperatorMatcher operator()(const M1 &P1, const M2 &P2) const {
+    return VariadicOperatorMatcher(Func, P1, P2);
+  }
+  template 
+  VariadicOperatorMatcher operator()(const M1 &P1, const M2 &P2,
+                                                 const M3 &P3) const {
+    return VariadicOperatorMatcher(Func, P1, P2, P3);
+  }
+  template 
+  VariadicOperatorMatcher
+  operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4) const {
+    return VariadicOperatorMatcher(Func, P1, P2, P3, P4);
+  }
+  template 
+  VariadicOperatorMatcher
+  operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4,
+             const M5 &P5) const {
+    return VariadicOperatorMatcher(Func, P1, P2, P3, P4,
+                                                       P5);
   }
-
-private:
-  const Matcher InnerMatcher1;
-  const Matcher InnerMatcher2;
 };
 
+/// @}
+
+/// \brief Matches nodes for which all provided matchers match.
+bool
+AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
+                      ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
+                      ArrayRef InnerMatchers);
+
+/// \brief Matches nodes for which at least one of the provided matchers
+/// matches, but doesn't stop at the first match.
+bool
+EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
+                       ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
+                       ArrayRef InnerMatchers);
+
+/// \brief Matches nodes for which at least one of the provided matchers
+/// matches.
+bool
+AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
+                      ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
+                      ArrayRef InnerMatchers);
+
 /// \brief Creates a Matcher that matches if all inner matchers match.
 template
 BindableMatcher makeAllOfComposite(
     ArrayRef *> InnerMatchers) {
   if (InnerMatchers.empty())
     return BindableMatcher(new TrueMatcher);
-  MatcherInterface *InnerMatcher = new TrueMatcher;
-  for (int i = InnerMatchers.size() - 1; i >= 0; --i) {
-    InnerMatcher = new AllOfMatcher, Matcher >(
-      *InnerMatchers[i], makeMatcher(InnerMatcher));
-  }
-  return BindableMatcher(InnerMatcher);
+  return BindableMatcher(new VariadicOperatorMatcherInterface(
+      AllOfVariadicOperator, InnerMatchers));
 }
 
 /// \brief Creates a Matcher that matches if
diff --git a/lib/ASTMatchers/ASTMatchersInternal.cpp b/lib/ASTMatchers/ASTMatchersInternal.cpp
index 757d20675b..e7465167da 100644
--- a/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -36,6 +36,51 @@ DynTypedMatcher::~DynTypedMatcher() {}
 
 DynTypedMatcher *DynTypedMatcher::tryBind(StringRef ID) const { return NULL; }
 
+bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
+                           ASTMatchFinder *Finder,
+                           BoundNodesTreeBuilder *Builder,
+                           ArrayRef InnerMatchers) {
+  // allOf leads to one matcher for each alternative in the first
+  // matcher combined with each alternative in the second matcher.
+  // Thus, we can reuse the same Builder.
+  for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
+    if (!InnerMatchers[i]->matches(DynNode, Finder, Builder))
+      return false;
+  }
+  return true;
+}
+
+bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
+                            ASTMatchFinder *Finder,
+                            BoundNodesTreeBuilder *Builder,
+                            ArrayRef InnerMatchers) {
+  BoundNodesTreeBuilder Result;
+  bool Matched = false;
+  for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
+    BoundNodesTreeBuilder BuilderInner(*Builder);
+    if (InnerMatchers[i]->matches(DynNode, Finder, &BuilderInner)) {
+      Matched = true;
+      Result.addMatch(BuilderInner);
+    }
+  }
+  *Builder = Result;
+  return Matched;
+}
+
+bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
+                           ASTMatchFinder *Finder,
+                           BoundNodesTreeBuilder *Builder,
+                           ArrayRef InnerMatchers) {
+  for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) {
+    BoundNodesTreeBuilder Result = *Builder;
+    if (InnerMatchers[i]->matches(DynNode, Finder, &Result)) {
+      *Builder = Result;
+      return true;
+    }
+  }
+  return false;
+}
+
 } // end namespace internal
 } // end namespace ast_matchers
 } // end namespace clang