r184429 - Enhancements for the DynTypedMatcher system.

Samuel Benzaquen sbenza at google.com
Thu Jun 20 07:28:33 PDT 2013


Author: sbenza
Date: Thu Jun 20 09:28:32 2013
New Revision: 184429

URL: http://llvm.org/viewvc/llvm-project?rev=184429&view=rev
Log:
Enhancements for the DynTypedMatcher system.
- Added conversion routines and checks in Matcher<T> that take a DynTypedMatcher.
- Added type information on the error messages for the marshallers.
- Allows future work on Polymorphic/overloaded matchers. We should be
  able to disambiguate at runtime and choose the appropriate overload.

Modified:
    cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h
    cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
    cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h
    cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp
    cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp
    cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h
    cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp
    cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h
    cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp
    cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
    cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp

Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchFinder.h Thu Jun 20 09:28:32 2013
@@ -136,17 +136,6 @@ public:
                   MatchCallback *Action);
   /// @}
 
-  /// \brief Adds a matcher to execute when running over the AST.
-  ///
-  /// This is similar to \c addMatcher(), but it uses the dynamic interface. It
-  /// is more flexible, but the lost type information enables a caller to pass
-  /// a matcher that cannot match anything.
-  ///
-  /// \returns \c true if the matcher is a valid top-level matcher, \c false
-  ///   otherwise.
-  bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
-                         MatchCallback *Action);
-
   /// \brief Creates a clang ASTConsumer that finds all matches.
   clang::ASTConsumer *newASTConsumer();
 

Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h Thu Jun 20 09:28:32 2013
@@ -224,6 +224,12 @@ public:
   /// \return A new matcher with the \p ID bound to it if this matcher supports
   ///   binding. Otherwise, returns NULL. Returns NULL by default.
   virtual DynTypedMatcher* tryBind(StringRef ID) const;
+
+  /// \brief Returns the type this matcher works on.
+  ///
+  /// \c matches() will always return false unless the node passed is of this
+  /// or a derived type.
+  virtual ast_type_traits::ASTNodeKind getSupportedKind() const = 0;
 };
 
 /// \brief Wrapper of a MatcherInterface<T> *that allows copying.
@@ -261,6 +267,27 @@ public:
             llvm::is_same<TypeT, Type>::value >::type* = 0)
       : Implementation(new TypeToQualType<TypeT>(Other)) {}
 
+  /// \brief Returns \c true if the passed DynTypedMatcher can be converted
+  ///   to a \c Matcher<T>.
+  ///
+  /// This method verifies that the underlying matcher in \c Other can process
+  /// nodes of types T.
+  static bool canConstructFrom(const DynTypedMatcher &Other) {
+    return Other.getSupportedKind()
+        .isBaseOf(ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
+  }
+
+  /// \brief Construct a Matcher<T> interface around the dynamic matcher
+  ///   \c Other.
+  ///
+  /// This method asserts that canConstructFrom(Other) is \c true. Callers
+  /// should call canConstructFrom(Other) first to make sure that Other is
+  /// compatible with T.
+  static Matcher<T> constructFrom(const DynTypedMatcher &Other) {
+    assert(canConstructFrom(Other));
+    return Matcher<T>(new WrappedMatcher(Other));
+  }
+
   /// \brief Forwards the call to the underlying MatcherInterface<T> pointer.
   bool matches(const T &Node,
                ASTMatchFinder *Finder,
@@ -281,6 +308,11 @@ public:
     return reinterpret_cast<uint64_t>(Implementation.getPtr());
   }
 
+  /// \brief Returns the type this matcher works on.
+  ast_type_traits::ASTNodeKind getSupportedKind() const {
+    return ast_type_traits::ASTNodeKind::getFromNodeKind<T>();
+  }
+
   /// \brief Returns whether the matcher matches on the given \c DynNode.
   virtual bool matches(const ast_type_traits::DynTypedNode DynNode,
                        ASTMatchFinder *Finder,
@@ -335,6 +367,23 @@ private:
     const Matcher<Base> From;
   };
 
+  /// \brief Simple MatcherInterface<T> wrapper around a DynTypedMatcher.
+  class WrappedMatcher : public MatcherInterface<T> {
+  public:
+    explicit WrappedMatcher(const DynTypedMatcher &Matcher)
+        : Inner(Matcher.clone()) {}
+    virtual ~WrappedMatcher() {}
+
+    bool matches(const T &Node, ASTMatchFinder *Finder,
+                 BoundNodesTreeBuilder *Builder) const {
+      return Inner->matches(ast_type_traits::DynTypedNode::create(Node), Finder,
+                            Builder);
+    }
+
+  private:
+    const OwningPtr<DynTypedMatcher> Inner;
+  };
+
   IntrusiveRefCntPtr< MatcherInterface<T> > Implementation;
 };  // class Matcher
 
@@ -345,6 +394,34 @@ inline Matcher<T> makeMatcher(MatcherInt
   return Matcher<T>(Implementation);
 }
 
+/// \brief Specialization of the conversion functions for QualType.
+///
+/// These specializations provide the Matcher<Type>->Matcher<QualType>
+/// conversion that the static API does.
+template <>
+inline bool
+Matcher<QualType>::canConstructFrom(const DynTypedMatcher &Other) {
+  ast_type_traits::ASTNodeKind SourceKind = Other.getSupportedKind();
+  // We support implicit conversion from Matcher<Type> to Matcher<QualType>
+  return SourceKind.isSame(
+             ast_type_traits::ASTNodeKind::getFromNodeKind<Type>()) ||
+         SourceKind.isSame(
+             ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>());
+}
+
+template <>
+inline Matcher<QualType>
+Matcher<QualType>::constructFrom(const DynTypedMatcher &Other) {
+  assert(canConstructFrom(Other));
+  ast_type_traits::ASTNodeKind SourceKind = Other.getSupportedKind();
+  if (SourceKind.isSame(
+          ast_type_traits::ASTNodeKind::getFromNodeKind<Type>())) {
+    // We support implicit conversion from Matcher<Type> to Matcher<QualType>
+    return Matcher<Type>::constructFrom(Other);
+  }
+  return makeMatcher(new WrappedMatcher(Other));
+}
+
 /// \brief Finds the first node in a range that matches the given matcher.
 template <typename MatcherT, typename IteratorT>
 bool matchesFirstInRange(const MatcherT &Matcher, IteratorT Start,

Modified: cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/Dynamic/VariantValue.h Thu Jun 20 09:28:32 2013
@@ -70,44 +70,24 @@ public:
   /// \brief Set the value to be \c Matcher by taking ownership of the object.
   void takeMatcher(DynTypedMatcher *Matcher);
 
-  /// \brief Specialized Matcher<T> is/get functions.
+  /// \brief Specialized Matcher<T> functions.
   template <class T>
-  bool isTypedMatcher() const {
-    // TODO: Add some logic to test if T is actually valid for the underlying
-    // type of the matcher.
-    return isMatcher();
+  bool hasTypedMatcher() const {
+    return isMatcher() &&
+           ast_matchers::internal::Matcher<T>::canConstructFrom(getMatcher());
   }
 
   template <class T>
   ast_matchers::internal::Matcher<T> getTypedMatcher() const {
-    return ast_matchers::internal::makeMatcher(
-        new DerivedTypeMatcher<T>(getMatcher()));
+    return ast_matchers::internal::Matcher<T>::constructFrom(getMatcher());
   }
 
+  /// \brief String representation of the type of the value.
+  std::string getTypeAsString() const;
+
 private:
   void reset();
 
-  /// \brief Matcher bridge between a Matcher<T> and a generic DynTypedMatcher.
-  template <class T>
-  class DerivedTypeMatcher :
-      public ast_matchers::internal::MatcherInterface<T> {
-  public:
-    explicit DerivedTypeMatcher(const DynTypedMatcher &DynMatcher)
-        : DynMatcher(DynMatcher.clone()) {}
-    virtual ~DerivedTypeMatcher() {}
-
-    typedef ast_matchers::internal::ASTMatchFinder ASTMatchFinder;
-    typedef ast_matchers::internal::BoundNodesTreeBuilder BoundNodesTreeBuilder;
-    bool matches(const T &Node, ASTMatchFinder *Finder,
-                 BoundNodesTreeBuilder *Builder) const {
-      return DynMatcher->matches(ast_type_traits::DynTypedNode::create(Node),
-                                 Finder, Builder);
-    }
-
-  private:
-    const OwningPtr<DynTypedMatcher> DynMatcher;
-  };
-
   /// \brief All supported value types.
   enum ValueType {
     VT_Nothing,

Modified: cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp Thu Jun 20 09:28:32 2013
@@ -803,14 +803,6 @@ void MatchFinder::addMatcher(const TypeL
     new TypeLocMatcher(NodeMatch), Action));
 }
 
-bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
-                                    MatchCallback *Action) {
-  MatcherCallbackPairs.push_back(std::make_pair(NodeMatch.clone(), Action));
-  // TODO: Do runtime type checking to make sure the matcher is one of the valid
-  // top-level matchers.
-  return true;
-}
-
 ASTConsumer *MatchFinder::newASTConsumer() {
   return new internal::MatchASTConsumer(&MatcherCallbackPairs, ParsingDone);
 }

Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp Thu Jun 20 09:28:32 2013
@@ -36,7 +36,7 @@ StringRef ErrorTypeToString(Diagnostics:
   case Diagnostics::ET_RegistryWrongArgCount:
     return "Incorrect argument count. (Expected = $0) != (Actual = $1)";
   case Diagnostics::ET_RegistryWrongArgType:
-    return "Incorrect type on function $0 for arg $1.";
+    return "Incorrect type for arg $0. (Expected = $1) != (Actual = $2)";
   case Diagnostics::ET_RegistryNotBindable:
     return "Matcher does not support binding.";
 

Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Marshallers.h Thu Jun 20 09:28:32 2013
@@ -42,6 +42,7 @@ template <class T> struct ArgTypeTraits<
 };
 
 template <> struct ArgTypeTraits<std::string> {
+  static StringRef asString() { return "String"; }
   static bool is(const VariantValue &Value) { return Value.isString(); }
   static const std::string &get(const VariantValue &Value) {
     return Value.getString();
@@ -49,13 +50,21 @@ template <> struct ArgTypeTraits<std::st
 };
 
 template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T> > {
-  static bool is(const VariantValue &Value) { return Value.isMatcher(); }
+  static std::string asString() {
+    return (Twine("Matcher<") +
+            ast_type_traits::ASTNodeKind::getFromNodeKind<T>().asStringRef() +
+            ">").str();
+  }
+  static bool is(const VariantValue &Value) {
+    return Value.hasTypedMatcher<T>();
+  }
   static ast_matchers::internal::Matcher<T> get(const VariantValue &Value) {
     return Value.getTypedMatcher<T>();
   }
 };
 
 template <> struct ArgTypeTraits<unsigned> {
+  static std::string asString() { return "Unsigned"; }
   static bool is(const VariantValue &Value) { return Value.isUnsigned(); }
   static unsigned get(const VariantValue &Value) {
     return Value.getUnsigned();
@@ -147,7 +156,8 @@ private:
 #define CHECK_ARG_TYPE(index, type)                                            \
   if (!ArgTypeTraits<type>::is(Args[index].Value)) {                           \
     Error->pushErrorFrame(Args[index].Range, Error->ET_RegistryWrongArgType)   \
-        << MatcherName << (index + 1);                                         \
+        << (index + 1) << ArgTypeTraits<type>::asString()                      \
+        << Args[index].Value.getTypeAsString();                                \
     return NULL;                                                               \
   }
 
@@ -201,14 +211,16 @@ DynTypedMatcher *VariadicMatcherCreateCa
 
   bool HasError = false;
   for (size_t i = 0, e = Args.size(); i != e; ++i) {
-    if (!Args[i].Value.isTypedMatcher<DerivedType>()) {
-      Error->pushErrorFrame(Args[i].Range, Error->ET_RegistryWrongArgType)
-          << MatcherName << (i + 1);
+    typedef ArgTypeTraits<DerivedMatcherType> DerivedTraits;
+    const ParserValue &Arg = Args[i];
+    const VariantValue &Value = Arg.Value;
+    if (!DerivedTraits::is(Value)) {
+      Error->pushErrorFrame(Arg.Range, Error->ET_RegistryWrongArgType)
+          << (i + 1) << DerivedTraits::asString() << Value.getTypeAsString();
       HasError = true;
       break;
     }
-    InnerArgs[i] =
-        new DerivedMatcherType(Args[i].Value.getTypedMatcher<DerivedType>());
+    InnerArgs[i] = new DerivedMatcherType(DerivedTraits::get(Value));
   }
 
   DynTypedMatcher *Out = NULL;

Modified: cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/VariantValue.cpp Thu Jun 20 09:28:32 2013
@@ -14,6 +14,8 @@
 
 #include "clang/ASTMatchers/Dynamic/VariantValue.h"
 
+#include "clang/Basic/LLVM.h"
+
 namespace clang {
 namespace ast_matchers {
 namespace dynamic {
@@ -123,6 +125,18 @@ void VariantValue::takeMatcher(DynTypedM
   Value.Matcher = NewValue;
 }
 
+std::string VariantValue::getTypeAsString() const {
+  switch (Type) {
+  case VT_String: return "String";
+  case VT_Matcher:
+    return (Twine("Matcher<") + getMatcher().getSupportedKind().asStringRef() +
+            ">").str();
+  case VT_Unsigned: return "Unsigned";
+  case VT_Nothing: return "Nothing";
+  }
+  llvm_unreachable("Invalid Type");
+}
+
 } // end namespace dynamic
 } // end namespace ast_matchers
 } // end namespace clang

Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h (original)
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.h Thu Jun 20 09:28:32 2013
@@ -84,41 +84,6 @@ testing::AssertionResult notMatches(cons
   return matchesConditionally(Code, AMatcher, false, "-std=c++11");
 }
 
-inline testing::AssertionResult
-matchesConditionallyDynamic(const std::string &Code,
-                            const internal::DynTypedMatcher &AMatcher,
-                            bool ExpectMatch, llvm::StringRef CompileArg) {
-  bool Found = false;
-  MatchFinder Finder;
-  Finder.addDynamicMatcher(AMatcher, new VerifyMatch(0, &Found));
-  OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
-  // Some tests use typeof, which is a gnu extension.
-  std::vector<std::string> Args(1, CompileArg);
-  if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) {
-    return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
-  }
-  if (!Found && ExpectMatch) {
-    return testing::AssertionFailure()
-      << "Could not find match in \"" << Code << "\"";
-  } else if (Found && !ExpectMatch) {
-    return testing::AssertionFailure()
-      << "Found unexpected match in \"" << Code << "\"";
-  }
-  return testing::AssertionSuccess();
-}
-
-inline testing::AssertionResult
-matchesDynamic(const std::string &Code,
-               const internal::DynTypedMatcher &AMatcher) {
-  return matchesConditionallyDynamic(Code, AMatcher, true, "-std=c++11");
-}
-
-inline testing::AssertionResult
-notMatchesDynamic(const std::string &Code,
-                  const internal::DynTypedMatcher &AMatcher) {
-  return matchesConditionallyDynamic(Code, AMatcher, false, "-std=c++11");
-}
-
 template <typename T>
 testing::AssertionResult
 matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher,

Modified: cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp Thu Jun 20 09:28:32 2013
@@ -49,6 +49,9 @@ public:
 
   StringRef boundID() const { return BoundID; }
 
+  virtual ast_type_traits::ASTNodeKind getSupportedKind() const {
+    return ast_type_traits::ASTNodeKind();
+  }
 private:
   uint64_t ID;
   std::string BoundID;
@@ -172,15 +175,19 @@ TEST(ParserTest, ParseMatcher) {
 using ast_matchers::internal::Matcher;
 
 TEST(ParserTest, FullParserTest) {
-  OwningPtr<DynTypedMatcher> Matcher(Parser::parseMatcherExpression(
-      "hasInitializer(binaryOperator(hasLHS(integerLiteral())))", NULL));
-  EXPECT_TRUE(matchesDynamic("int x = 1 + false;", *Matcher));
-  EXPECT_FALSE(matchesDynamic("int x = true + 1;", *Matcher));
-
-  Matcher.reset(
-      Parser::parseMatcherExpression("hasParameter(1, hasName(\"x\"))", NULL));
-  EXPECT_TRUE(matchesDynamic("void f(int a, int x);", *Matcher));
-  EXPECT_FALSE(matchesDynamic("void f(int x, int a);", *Matcher));
+  OwningPtr<DynTypedMatcher> VarDecl(Parser::parseMatcherExpression(
+      "varDecl(hasInitializer(binaryOperator(hasLHS(integerLiteral()))))",
+      NULL));
+  Matcher<Decl> M = Matcher<Decl>::constructFrom(*VarDecl);
+  EXPECT_TRUE(matches("int x = 1 + false;", M));
+  EXPECT_FALSE(matches("int x = true + 1;", M));
+
+  OwningPtr<DynTypedMatcher> HasParameter(Parser::parseMatcherExpression(
+      "functionDecl(hasParameter(1, hasName(\"x\")))", NULL));
+  M = Matcher<Decl>::constructFrom(*HasParameter);
+
+  EXPECT_TRUE(matches("void f(int a, int x);", M));
+  EXPECT_FALSE(matches("void f(int x, int a);", M));
 
   Diagnostics Error;
   EXPECT_TRUE(Parser::parseMatcherExpression(
@@ -188,7 +195,8 @@ TEST(ParserTest, FullParserTest) {
   EXPECT_EQ("1:1: Error parsing argument 1 for matcher hasInitializer.\n"
             "2:5: Error parsing argument 1 for matcher binaryOperator.\n"
             "2:20: Error building matcher hasLHS.\n"
-            "2:27: Incorrect type on function hasLHS for arg 1.",
+            "2:27: Incorrect type for arg 1. "
+            "(Expected = Matcher<Expr>) != (Actual = String)",
             Error.ToStringFull());
 }
 

Modified: cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp Thu Jun 20 09:28:32 2013
@@ -20,98 +20,131 @@ namespace {
 
 using ast_matchers::internal::Matcher;
 
-DynTypedMatcher *constructMatcher(StringRef MatcherName, Diagnostics *Error) {
-  const std::vector<ParserValue> Args;
-  return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error);
-}
-
-DynTypedMatcher *constructMatcher(StringRef MatcherName,
-                                  const VariantValue &Arg1,
-                                  Diagnostics *Error) {
-  std::vector<ParserValue> Args(1);
-  Args[0].Value = Arg1;
-  return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error);
-}
-
-DynTypedMatcher *constructMatcher(StringRef MatcherName,
-                                  const VariantValue &Arg1,
-                                  const VariantValue &Arg2,
-                                  Diagnostics *Error) {
-  std::vector<ParserValue> Args(2);
-  Args[0].Value = Arg1;
-  Args[1].Value = Arg2;
-  return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error);
-}
-
-TEST(RegistryTest, CanConstructNoArgs) {
-  OwningPtr<DynTypedMatcher> IsArrowValue(constructMatcher("isArrow", NULL));
-  OwningPtr<DynTypedMatcher> BoolValue(constructMatcher("boolLiteral", NULL));
+class RegistryTest : public ::testing::Test {
+public:
+  std::vector<ParserValue> Args() { return std::vector<ParserValue>(); }
+  std::vector<ParserValue> Args(const VariantValue &Arg1) {
+    std::vector<ParserValue> Out(1);
+    Out[0].Value = Arg1;
+    return Out;
+  }
+  std::vector<ParserValue> Args(const VariantValue &Arg1,
+                                const VariantValue &Arg2) {
+    std::vector<ParserValue> Out(2);
+    Out[0].Value = Arg1;
+    Out[1].Value = Arg2;
+    return Out;
+  }
+
+  template <class T>
+  Matcher<T> constructMatcher(StringRef MatcherName, Diagnostics *Error) {
+    OwningPtr<DynTypedMatcher> Out(
+        Registry::constructMatcher(MatcherName, SourceRange(), Args(), Error));
+    return Matcher<T>::constructFrom(*Out);
+  }
+
+  template <class T>
+  Matcher<T> constructMatcher(StringRef MatcherName, const VariantValue &Arg1,
+                              Diagnostics *Error) {
+    OwningPtr<DynTypedMatcher> Out(Registry::constructMatcher(
+        MatcherName, SourceRange(), Args(Arg1), Error));
+    return Matcher<T>::constructFrom(*Out);
+  }
+
+  template <class T>
+  Matcher<T> constructMatcher(StringRef MatcherName, const VariantValue &Arg1,
+                              const VariantValue &Arg2, Diagnostics *Error) {
+    OwningPtr<DynTypedMatcher> Out(Registry::constructMatcher(
+        MatcherName, SourceRange(), Args(Arg1, Arg2), Error));
+    return Matcher<T>::constructFrom(*Out);
+  }
+};
+
+TEST_F(RegistryTest, CanConstructNoArgs) {
+  Matcher<Stmt> IsArrowValue = constructMatcher<Stmt>(
+      "memberExpr", constructMatcher<MemberExpr>("isArrow", NULL), NULL);
+  Matcher<Stmt> BoolValue = constructMatcher<Stmt>("boolLiteral", NULL);
 
   const std::string ClassSnippet = "struct Foo { int x; };\n"
                                    "Foo *foo = new Foo;\n"
                                    "int i = foo->x;\n";
   const std::string BoolSnippet = "bool Foo = true;\n";
 
-  EXPECT_TRUE(matchesDynamic(ClassSnippet, *IsArrowValue));
-  EXPECT_TRUE(matchesDynamic(BoolSnippet, *BoolValue));
-  EXPECT_FALSE(matchesDynamic(ClassSnippet, *BoolValue));
-  EXPECT_FALSE(matchesDynamic(BoolSnippet, *IsArrowValue));
-}
-
-TEST(RegistryTest, ConstructWithSimpleArgs) {
-  OwningPtr<DynTypedMatcher> Value(
-      constructMatcher("hasName", std::string("X"), NULL));
-  EXPECT_TRUE(matchesDynamic("class X {};", *Value));
-  EXPECT_FALSE(matchesDynamic("int x;", *Value));
-
-  Value.reset(constructMatcher("parameterCountIs", 2, NULL));
-  EXPECT_TRUE(matchesDynamic("void foo(int,int);", *Value));
-  EXPECT_FALSE(matchesDynamic("void foo(int);", *Value));
-}
-
-TEST(RegistryTest, ConstructWithMatcherArgs) {
-  OwningPtr<DynTypedMatcher> HasInitializerSimple(
-      constructMatcher("hasInitializer", stmt(), NULL));
-  OwningPtr<DynTypedMatcher> HasInitializerComplex(
-      constructMatcher("hasInitializer", callExpr(), NULL));
+  EXPECT_TRUE(matches(ClassSnippet, IsArrowValue));
+  EXPECT_TRUE(matches(BoolSnippet, BoolValue));
+  EXPECT_FALSE(matches(ClassSnippet, BoolValue));
+  EXPECT_FALSE(matches(BoolSnippet, IsArrowValue));
+}
+
+TEST_F(RegistryTest, ConstructWithSimpleArgs) {
+  Matcher<Decl> Value = constructMatcher<Decl>(
+      "namedDecl",
+      constructMatcher<NamedDecl>("hasName", std::string("X"), NULL), NULL);
+  EXPECT_TRUE(matches("class X {};", Value));
+  EXPECT_FALSE(matches("int x;", Value));
+
+  Value =
+      functionDecl(constructMatcher<FunctionDecl>("parameterCountIs", 2, NULL));
+  EXPECT_TRUE(matches("void foo(int,int);", Value));
+  EXPECT_FALSE(matches("void foo(int);", Value));
+}
+
+TEST_F(RegistryTest, ConstructWithMatcherArgs) {
+  Matcher<Decl> HasInitializerSimple = constructMatcher<Decl>(
+      "varDecl", constructMatcher<VarDecl>("hasInitializer", stmt(), NULL),
+      NULL);
+  Matcher<Decl> HasInitializerComplex = constructMatcher<Decl>(
+      "varDecl", constructMatcher<VarDecl>("hasInitializer", callExpr(), NULL),
+      NULL);
 
   std::string code = "int i;";
-  EXPECT_FALSE(matchesDynamic(code, *HasInitializerSimple));
-  EXPECT_FALSE(matchesDynamic(code, *HasInitializerComplex));
+  EXPECT_FALSE(matches(code, HasInitializerSimple));
+  EXPECT_FALSE(matches(code, HasInitializerComplex));
 
   code = "int i = 1;";
-  EXPECT_TRUE(matchesDynamic(code, *HasInitializerSimple));
-  EXPECT_FALSE(matchesDynamic(code, *HasInitializerComplex));
+  EXPECT_TRUE(matches(code, HasInitializerSimple));
+  EXPECT_FALSE(matches(code, HasInitializerComplex));
 
   code = "int y(); int i = y();";
-  EXPECT_TRUE(matchesDynamic(code, *HasInitializerSimple));
-  EXPECT_TRUE(matchesDynamic(code, *HasInitializerComplex));
+  EXPECT_TRUE(matches(code, HasInitializerSimple));
+  EXPECT_TRUE(matches(code, HasInitializerComplex));
 
-  OwningPtr<DynTypedMatcher> HasParameter(
-      constructMatcher("hasParameter", 1, hasName("x"), NULL));
-  EXPECT_TRUE(matchesDynamic("void f(int a, int x);", *HasParameter));
-  EXPECT_FALSE(matchesDynamic("void f(int x, int a);", *HasParameter));
+  Matcher<Decl> HasParameter = functionDecl(
+      constructMatcher<FunctionDecl>("hasParameter", 1, hasName("x"), NULL));
+  EXPECT_TRUE(matches("void f(int a, int x);", HasParameter));
+  EXPECT_FALSE(matches("void f(int x, int a);", HasParameter));
 }
 
-TEST(RegistryTest, Errors) {
+TEST_F(RegistryTest, Errors) {
   // Incorrect argument count.
   OwningPtr<Diagnostics> Error(new Diagnostics());
-  EXPECT_TRUE(NULL == constructMatcher("hasInitializer", Error.get()));
+  EXPECT_TRUE(NULL ==
+              Registry::constructMatcher("hasInitializer", SourceRange(),
+                                         Args(), Error.get()));
   EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)",
             Error->ToString());
   Error.reset(new Diagnostics());
-  EXPECT_TRUE(NULL == constructMatcher("isArrow", std::string(), Error.get()));
+  EXPECT_TRUE(NULL ==
+              Registry::constructMatcher("isArrow", SourceRange(),
+                                         Args(std::string()), Error.get()));
   EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
             Error->ToString());
 
   // Bad argument type
   Error.reset(new Diagnostics());
-  EXPECT_TRUE(NULL == constructMatcher("ofClass", std::string(), Error.get()));
-  EXPECT_EQ("Incorrect type on function ofClass for arg 1.", Error->ToString());
+  EXPECT_TRUE(NULL ==
+              Registry::constructMatcher("ofClass", SourceRange(),
+                                         Args(std::string()), Error.get()));
+  EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != "
+            "(Actual = String)",
+            Error->ToString());
   Error.reset(new Diagnostics());
-  EXPECT_TRUE(NULL == constructMatcher("recordDecl", recordDecl(),
-                                       ::std::string(), Error.get()));
-  EXPECT_EQ("Incorrect type on function recordDecl for arg 2.",
+  EXPECT_TRUE(NULL ==
+              Registry::constructMatcher(
+                  "recordDecl", SourceRange(),
+                  Args(recordDecl(), parameterCountIs(3)), Error.get()));
+  EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != "
+            "(Actual = Matcher<FunctionDecl>)",
             Error->ToString());
 }
 

Modified: cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp?rev=184429&r1=184428&r2=184429&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp Thu Jun 20 09:28:32 2013
@@ -28,8 +28,8 @@ TEST(VariantValueTest, Unsigned) {
 
   EXPECT_FALSE(Value.isString());
   EXPECT_FALSE(Value.isMatcher());
-  EXPECT_FALSE(Value.isTypedMatcher<clang::Decl>());
-  EXPECT_FALSE(Value.isTypedMatcher<clang::UnaryOperator>());
+  EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
+  EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
 }
 
 TEST(VariantValueTest, String) {
@@ -38,11 +38,12 @@ TEST(VariantValueTest, String) {
 
   EXPECT_TRUE(Value.isString());
   EXPECT_EQ(kString, Value.getString());
+  EXPECT_EQ("String", Value.getTypeAsString());
 
   EXPECT_FALSE(Value.isUnsigned());
   EXPECT_FALSE(Value.isMatcher());
-  EXPECT_FALSE(Value.isTypedMatcher<clang::Decl>());
-  EXPECT_FALSE(Value.isTypedMatcher<clang::UnaryOperator>());
+  EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
+  EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
 }
 
 TEST(VariantValueTest, DynTypedMatcher) {
@@ -52,22 +53,25 @@ TEST(VariantValueTest, DynTypedMatcher)
   EXPECT_FALSE(Value.isString());
 
   EXPECT_TRUE(Value.isMatcher());
-  EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>());
-  EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>());
+  EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
+  EXPECT_TRUE(Value.hasTypedMatcher<clang::UnaryOperator>());
+  EXPECT_EQ("Matcher<Stmt>", Value.getTypeAsString());
 
-  // Conversion to any type of matcher works.
-  // If they are not compatible it would just return a matcher that matches
-  // nothing. We test this below.
+  // Can only convert to compatible matchers.
   Value = recordDecl();
   EXPECT_TRUE(Value.isMatcher());
-  EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>());
-  EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>());
+  EXPECT_TRUE(Value.hasTypedMatcher<clang::Decl>());
+  EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
+  EXPECT_EQ("Matcher<Decl>", Value.getTypeAsString());
 
-  Value = unaryOperator();
+  Value = ignoringImpCasts(expr());
   EXPECT_TRUE(Value.isMatcher());
-  EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>());
-  EXPECT_TRUE(Value.isTypedMatcher<clang::Stmt>());
-  EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>());
+  EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
+  EXPECT_FALSE(Value.hasTypedMatcher<clang::Stmt>());
+  EXPECT_TRUE(Value.hasTypedMatcher<clang::Expr>());
+  EXPECT_TRUE(Value.hasTypedMatcher<clang::IntegerLiteral>());
+  EXPECT_FALSE(Value.hasTypedMatcher<clang::GotoStmt>());
+  EXPECT_EQ("Matcher<Expr>", Value.getTypeAsString());
 }
 
 TEST(VariantValueTest, Assignment) {
@@ -76,13 +80,15 @@ TEST(VariantValueTest, Assignment) {
   EXPECT_EQ("A", Value.getString());
   EXPECT_FALSE(Value.isUnsigned());
   EXPECT_FALSE(Value.isMatcher());
+  EXPECT_EQ("String", Value.getTypeAsString());
 
   Value = recordDecl();
   EXPECT_FALSE(Value.isUnsigned());
   EXPECT_FALSE(Value.isString());
   EXPECT_TRUE(Value.isMatcher());
-  EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>());
-  EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>());
+  EXPECT_TRUE(Value.hasTypedMatcher<clang::Decl>());
+  EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
+  EXPECT_EQ("Matcher<Decl>", Value.getTypeAsString());
 
   Value = 17;
   EXPECT_TRUE(Value.isUnsigned());
@@ -94,25 +100,28 @@ TEST(VariantValueTest, Assignment) {
   EXPECT_FALSE(Value.isUnsigned());
   EXPECT_FALSE(Value.isString());
   EXPECT_FALSE(Value.isMatcher());
+  EXPECT_EQ("Nothing", Value.getTypeAsString());
 }
 
 TEST(GeneicValueTest, Matcher) {
-  EXPECT_TRUE(matchesDynamic(
-      "class X {};", VariantValue(recordDecl(hasName("X"))).getMatcher()));
-  EXPECT_TRUE(matchesDynamic(
-      "int x;", VariantValue(varDecl()).getTypedMatcher<clang::Decl>()));
-  EXPECT_TRUE(matchesDynamic("int foo() { return 1 + 1; }",
-                             VariantValue(functionDecl()).getMatcher()));
-  // Going through the wrong Matcher<T> will fail to match, even if the
-  // underlying matcher is correct.
-  EXPECT_FALSE(matchesDynamic(
-      "int x;", VariantValue(varDecl()).getTypedMatcher<clang::Stmt>()));
+  EXPECT_TRUE(matches("class X {};", VariantValue(recordDecl(hasName("X")))
+                                         .getTypedMatcher<Decl>()));
+  EXPECT_TRUE(
+      matches("int x;", VariantValue(varDecl()).getTypedMatcher<Decl>()));
+  EXPECT_TRUE(matches("int foo() { return 1 + 1; }",
+                      VariantValue(functionDecl()).getTypedMatcher<Decl>()));
+  // Can't get the wrong matcher.
+  EXPECT_FALSE(VariantValue(varDecl()).hasTypedMatcher<Stmt>());
+#if GTEST_HAS_DEATH_TEST and DEBUG
+  // Trying to get the wrong matcher fails an assertion in Matcher<T>.
+  EXPECT_DEATH(VariantValue(varDecl()).getTypedMatcher<Stmt>(),
+               "canConstructFrom");
+#endif
 
   EXPECT_FALSE(
-      matchesDynamic("int x;", VariantValue(functionDecl()).getMatcher()));
-  EXPECT_FALSE(matchesDynamic(
-      "int foo() { return 1 + 1; }",
-      VariantValue(declRefExpr()).getTypedMatcher<clang::DeclRefExpr>()));
+      matches("int x;", VariantValue(functionDecl()).getTypedMatcher<Decl>()));
+  EXPECT_FALSE(matches("int foo() { return 1 + 1; }",
+                       VariantValue(declRefExpr()).getTypedMatcher<Stmt>()));
 }
 
 } // end anonymous namespace





More information about the cfe-commits mailing list