r195466 - Add support for the 'unless' matcher in the dynamic layer.

Samuel Benzaquen sbenza at google.com
Fri Nov 22 06:41:48 PST 2013


Author: sbenza
Date: Fri Nov 22 08:41:48 2013
New Revision: 195466

URL: http://llvm.org/viewvc/llvm-project?rev=195466&view=rev
Log:
Add support for the 'unless' matcher in the dynamic layer.

Summary: Add support for the 'unless' matcher in the dynamic layer.

Reviewers: klimek

CC: cfe-commits, revane, klimek

Differential Revision: http://llvm-reviews.chandlerc.com/D2247

Modified:
    cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
    cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
    cfe/trunk/lib/ASTMatchers/ASTMatchersInternal.cpp
    cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h
    cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
    cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp

Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=195466&r1=195465&r2=195466&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Fri Nov 22 08:41:48 2013
@@ -1317,21 +1317,21 @@ const internal::VariadicAllOfMatcher<Typ
 /// \c b.
 ///
 /// Usable as: Any Matcher
-const internal::VariadicOperatorMatcherFunc eachOf = {
+const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> eachOf = {
   internal::EachOfVariadicOperator
 };
 
 /// \brief Matches if any of the given matchers matches.
 ///
 /// Usable as: Any Matcher
-const internal::VariadicOperatorMatcherFunc anyOf = {
+const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> anyOf = {
   internal::AnyOfVariadicOperator
 };
 
 /// \brief Matches if all given matchers match.
 ///
 /// Usable as: Any Matcher
-const internal::VariadicOperatorMatcherFunc allOf = {
+const internal::VariadicOperatorMatcherFunc<2, UINT_MAX> allOf = {
   internal::AllOfVariadicOperator
 };
 
@@ -1671,12 +1671,9 @@ const internal::ArgumentAdaptingMatcherF
 /// \endcode
 ///
 /// Usable as: Any Matcher
-template <typename M>
-internal::PolymorphicMatcherWithParam1<internal::NotMatcher, M>
-unless(const M &InnerMatcher) {
-  return internal::PolymorphicMatcherWithParam1<
-    internal::NotMatcher, M>(InnerMatcher);
-}
+const internal::VariadicOperatorMatcherFunc<1, 1> unless = {
+  internal::NotUnaryOperator
+};
 
 /// \brief Matches a node if the declaration associated with that node
 /// matches the given matcher.

Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=195466&r1=195465&r2=195466&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h Fri Nov 22 08:41:48 2013
@@ -1098,38 +1098,6 @@ private:
   const Matcher<ChildT> ChildMatcher;
 };
 
-/// \brief Matches nodes of type T if the given Matcher<T> does not match.
-///
-/// Type argument MatcherT is required by PolymorphicMatcherWithParam1
-/// but not actually used. It will always be instantiated with a type
-/// convertible to Matcher<T>.
-template <typename T, typename MatcherT>
-class NotMatcher : public MatcherInterface<T> {
-public:
-  explicit NotMatcher(const Matcher<T> &InnerMatcher)
-      : InnerMatcher(InnerMatcher) {}
-
-  virtual bool matches(const T &Node,
-                       ASTMatchFinder *Finder,
-                       BoundNodesTreeBuilder *Builder) const {
-    // The 'unless' matcher will always discard the result:
-    // If the inner matcher doesn't match, unless returns true,
-    // but the inner matcher cannot have bound anything.
-    // If the inner matcher matches, the result is false, and
-    // any possible binding will be discarded.
-    // We still need to hand in all the bound nodes up to this
-    // point so the inner matcher can depend on bound nodes,
-    // and we need to actively discard the bound nodes, otherwise
-    // the inner matcher will reset the bound nodes if it doesn't
-    // match, but this would be inversed by 'unless'.
-    BoundNodesTreeBuilder Discard(*Builder);
-    return !InnerMatcher.matches(Node, Finder, &Discard);
-  }
-
-private:
-  const Matcher<T> InnerMatcher;
-};
-
 /// \brief VariadicOperatorMatcher related types.
 /// @{
 
@@ -1167,14 +1135,14 @@ struct VariadicOperatorNoArg {};
 /// Input matchers can have any type (including other polymorphic matcher
 /// types), and the actual Matcher<T> is generated on demand with an implicit
 /// coversion operator.
-template <typename P1, typename P2,
+template <typename P1, typename P2 = VariadicOperatorNoArg,
           typename P3 = VariadicOperatorNoArg,
           typename P4 = VariadicOperatorNoArg,
           typename P5 = VariadicOperatorNoArg>
 class VariadicOperatorMatcher {
 public:
   VariadicOperatorMatcher(VariadicOperatorFunction Func, const P1 &Param1,
-                          const P2 &Param2,
+                          const P2 &Param2 = VariadicOperatorNoArg(),
                           const P3 &Param3 = VariadicOperatorNoArg(),
                           const P4 &Param4 = VariadicOperatorNoArg(),
                           const P5 &Param5 = VariadicOperatorNoArg())
@@ -1183,7 +1151,6 @@ public:
 
   template <typename T> operator Matcher<T>() const {
     std::vector<DynTypedMatcher> Matchers;
-
     addMatcher<T>(Param1, Matchers);
     addMatcher<T>(Param2, Matchers);
     addMatcher<T>(Param3, Matchers);
@@ -1215,26 +1182,38 @@ private:
 /// \brief Overloaded function object to generate VariadicOperatorMatcher
 ///   objects from arbitrary matchers.
 ///
-/// It supports 2-5 argument overloaded operator(). More can be added if needed.
+/// It supports 1-5 argument overloaded operator(). More can be added if needed.
+template <unsigned MinCount, unsigned MaxCount>
 struct VariadicOperatorMatcherFunc {
   VariadicOperatorFunction Func;
 
+  template <unsigned Count, typename T>
+  struct EnableIfValidArity
+      : public llvm::enable_if_c<MinCount <= Count &&Count <= MaxCount, T> {};
+
+  template <typename M1>
+  typename EnableIfValidArity<1, VariadicOperatorMatcher<M1> >::type
+  operator()(const M1 &P1) const {
+    return VariadicOperatorMatcher<M1>(Func, P1);
+  }
   template <typename M1, typename M2>
-  VariadicOperatorMatcher<M1, M2> operator()(const M1 &P1, const M2 &P2) const {
+  typename EnableIfValidArity<2, VariadicOperatorMatcher<M1, M2> >::type
+  operator()(const M1 &P1, const M2 &P2) const {
     return VariadicOperatorMatcher<M1, M2>(Func, P1, P2);
   }
   template <typename M1, typename M2, typename M3>
-  VariadicOperatorMatcher<M1, M2, M3> operator()(const M1 &P1, const M2 &P2,
-                                                 const M3 &P3) const {
+  typename EnableIfValidArity<3, VariadicOperatorMatcher<M1, M2, M3> >::type
+  operator()(const M1 &P1, const M2 &P2, const M3 &P3) const {
     return VariadicOperatorMatcher<M1, M2, M3>(Func, P1, P2, P3);
   }
   template <typename M1, typename M2, typename M3, typename M4>
-  VariadicOperatorMatcher<M1, M2, M3, M4>
+  typename EnableIfValidArity<4, VariadicOperatorMatcher<M1, M2, M3, M4> >::type
   operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4) const {
     return VariadicOperatorMatcher<M1, M2, M3, M4>(Func, P1, P2, P3, P4);
   }
   template <typename M1, typename M2, typename M3, typename M4, typename M5>
-  VariadicOperatorMatcher<M1, M2, M3, M4, M5>
+  typename EnableIfValidArity<
+      5, VariadicOperatorMatcher<M1, M2, M3, M4, M5> >::type
   operator()(const M1 &P1, const M2 &P2, const M3 &P3, const M4 &P4,
              const M5 &P5) const {
     return VariadicOperatorMatcher<M1, M2, M3, M4, M5>(Func, P1, P2, P3, P4,
@@ -1244,6 +1223,13 @@ struct VariadicOperatorMatcherFunc {
 
 /// @}
 
+/// \brief Matches nodes that do not match the provided matcher.
+///
+/// Uses the variadic matcher interface, but fails if InnerMatchers.size()!=1.
+bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode,
+                      ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
+                      ArrayRef<DynTypedMatcher> InnerMatchers);
+
 /// \brief Matches nodes for which all provided matchers match.
 bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
                            ASTMatchFinder *Finder,

Modified: cfe/trunk/lib/ASTMatchers/ASTMatchersInternal.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/ASTMatchersInternal.cpp?rev=195466&r1=195465&r2=195466&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/ASTMatchersInternal.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/ASTMatchersInternal.cpp Fri Nov 22 08:41:48 2013
@@ -34,6 +34,26 @@ void BoundNodesTreeBuilder::addMatch(con
   }
 }
 
+bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode,
+                      ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder,
+                      ArrayRef<DynTypedMatcher> InnerMatchers) {
+  if (InnerMatchers.size() != 1)
+    return false;
+
+  // The 'unless' matcher will always discard the result:
+  // If the inner matcher doesn't match, unless returns true,
+  // but the inner matcher cannot have bound anything.
+  // If the inner matcher matches, the result is false, and
+  // any possible binding will be discarded.
+  // We still need to hand in all the bound nodes up to this
+  // point so the inner matcher can depend on bound nodes,
+  // and we need to actively discard the bound nodes, otherwise
+  // the inner matcher will reset the bound nodes if it doesn't
+  // match, but this would be inversed by 'unless'.
+  BoundNodesTreeBuilder Discard(*Builder);
+  return !InnerMatchers[0].matches(DynNode, Finder, &Discard);
+}
+
 bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode,
                            ASTMatchFinder *Finder,
                            BoundNodesTreeBuilder *Builder,

Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h?rev=195466&r1=195465&r2=195466&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h Fri Nov 22 08:41:48 2013
@@ -347,12 +347,22 @@ private:
 class VariadicOperatorMatcherCreateCallback : public MatcherCreateCallback {
 public:
   typedef ast_matchers::internal::VariadicOperatorFunction VarFunc;
-  VariadicOperatorMatcherCreateCallback(VarFunc Func, StringRef MatcherName)
-      : Func(Func), MatcherName(MatcherName) {}
+  VariadicOperatorMatcherCreateCallback(unsigned MinCount, unsigned MaxCount,
+                                        VarFunc Func, StringRef MatcherName)
+      : MinCount(MinCount), MaxCount(MaxCount), Func(Func),
+        MatcherName(MatcherName) {}
 
   virtual VariantMatcher run(const SourceRange &NameRange,
                              ArrayRef<ParserValue> Args,
                              Diagnostics *Error) const {
+    if (Args.size() < MinCount || MaxCount < Args.size()) {
+      const std::string MaxStr =
+          (MaxCount == UINT_MAX ? "" : Twine(MaxCount)).str();
+      Error->addError(NameRange, Error->ET_RegistryWrongArgCount)
+          << ("(" + Twine(MinCount) + ", " + MaxStr + ")") << Args.size();
+      return VariantMatcher();
+    }
+
     std::vector<VariantMatcher> InnerArgs;
     for (size_t i = 0, e = Args.size(); i != e; ++i) {
       const ParserValue &Arg = Args[i];
@@ -368,6 +378,8 @@ public:
   }
 
 private:
+  const unsigned MinCount;
+  const unsigned MaxCount;
   const VarFunc Func;
   const StringRef MatcherName;
 };
@@ -439,10 +451,13 @@ AdaptativeOverloadCollector<ArgumentAdap
 }
 
 /// \brief Variadic operator overload.
-MatcherCreateCallback *makeMatcherAutoMarshall(
-    ast_matchers::internal::VariadicOperatorMatcherFunc Func,
-    StringRef MatcherName) {
-  return new VariadicOperatorMatcherCreateCallback(Func.Func, MatcherName);
+template <unsigned MinCount, unsigned MaxCount>
+MatcherCreateCallback *
+makeMatcherAutoMarshall(ast_matchers::internal::VariadicOperatorMatcherFunc<
+                            MinCount, MaxCount> Func,
+                        StringRef MatcherName) {
+  return new VariadicOperatorMatcherCreateCallback(MinCount, MaxCount,
+                                                   Func.Func, MatcherName);
 }
 
 }  // namespace internal

Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp?rev=195466&r1=195465&r2=195466&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp Fri Nov 22 08:41:48 2013
@@ -76,7 +76,6 @@ RegistryMaps::RegistryMaps() {
   // ofKind
   //
   // Polymorphic + argument overload:
-  // unless
   // findAll
   //
   // Other:
@@ -285,6 +284,7 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(typedefType);
   REGISTER_MATCHER(unaryExprOrTypeTraitExpr);
   REGISTER_MATCHER(unaryOperator);
+  REGISTER_MATCHER(unless);
   REGISTER_MATCHER(userDefinedLiteral);
   REGISTER_MATCHER(usingDecl);
   REGISTER_MATCHER(varDecl);

Modified: cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp?rev=195466&r1=195465&r2=195466&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp Fri Nov 22 08:41:48 2013
@@ -295,6 +295,17 @@ TEST_F(RegistryTest, VariadicOp) {
   EXPECT_FALSE(matches("int i = 0;", D));
   EXPECT_TRUE(matches("class Bar{};", D));
   EXPECT_FALSE(matches("class OtherBar{};", D));
+
+  D = constructMatcher(
+      "recordDecl",
+      constructMatcher(
+          "unless",
+          constructMatcher("namedDecl",
+                           constructMatcher("hasName", std::string("Bar")))))
+          .getTypedMatcher<Decl>();
+
+  EXPECT_FALSE(matches("class Bar{};", D));
+  EXPECT_TRUE(matches("class OtherBar{};", D));
 }
 
 TEST_F(RegistryTest, Errors) {
@@ -307,6 +318,15 @@ TEST_F(RegistryTest, Errors) {
   EXPECT_TRUE(constructMatcher("isArrow", std::string(), Error.get()).isNull());
   EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
             Error->toString());
+  Error.reset(new Diagnostics());
+  EXPECT_TRUE(constructMatcher("anyOf", Error.get()).isNull());
+  EXPECT_EQ("Incorrect argument count. (Expected = (2, )) != (Actual = 0)",
+            Error->toString());
+  Error.reset(new Diagnostics());
+  EXPECT_TRUE(constructMatcher("unless", std::string(), std::string(),
+                               Error.get()).isNull());
+  EXPECT_EQ("Incorrect argument count. (Expected = (1, 1)) != (Actual = 2)",
+            Error->toString());
 
   // Bad argument type
   Error.reset(new Diagnostics());
@@ -324,7 +344,8 @@ TEST_F(RegistryTest, Errors) {
 
   // Bad argument type with variadic.
   Error.reset(new Diagnostics());
-  EXPECT_TRUE(constructMatcher("anyOf", std::string(), Error.get()).isNull());
+  EXPECT_TRUE(constructMatcher("anyOf", std::string(), std::string(),
+                               Error.get()).isNull());
   EXPECT_EQ(
       "Incorrect type for arg 1. (Expected = Matcher<>) != (Actual = String)",
       Error->toString());





More information about the cfe-commits mailing list