From 3f84bb341bfb1312842b09db71d76bc3898ba247 Mon Sep 17 00:00:00 2001 From: Samuel Benzaquen Date: Mon, 15 Jul 2013 19:25:06 +0000 Subject: [PATCH] Add support for type traversal matchers. Summary: Fixup the type traversal macros/matchers to specify the supported types. Make the marshallers a little more generic to support any variadic function. Update the doc script. Reviewers: klimek CC: cfe-commits, revane Differential Revision: http://llvm-reviews.chandlerc.com/D1023 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@186340 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/LibASTMatchersReference.html | 48 +++---- docs/tools/dump_ast_matchers.py | 15 ++- include/clang/ASTMatchers/ASTMatchers.h | 18 ++- .../clang/ASTMatchers/ASTMatchersInternal.h | 50 +++++++- include/clang/ASTMatchers/ASTMatchersMacros.h | 70 +++-------- lib/ASTMatchers/Dynamic/Marshallers.h | 38 +++--- lib/ASTMatchers/Dynamic/Registry.cpp | 12 +- unittests/ASTMatchers/Dynamic/ParserTest.cpp | 8 +- .../ASTMatchers/Dynamic/RegistryTest.cpp | 117 +++++++++++------- 9 files changed, 206 insertions(+), 170 deletions(-) diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html index ee7476ba80..a3c6b13d45 100644 --- a/docs/LibASTMatchersReference.html +++ b/docs/LibASTMatchersReference.html @@ -2367,8 +2367,8 @@ arraySubscriptExpression(hasIndex(integerLiteral())) -Matcher<ArrayTypeLoc>hasElementTypeLocMatcher<TypeLoc> -
Matches arrays and C99 complex types that have a specific element
+Matcher<ArrayTypeLoc>hasElementTypeLocMatcher<TypeLoc>
+
Matches arrays and C99 complex types that have a specific element
 type.
 
 Given
@@ -2382,8 +2382,8 @@ Usable as: Matcher<ArrayType>hasElementTypeMatcher<Type>
-
Matches arrays and C99 complex types that have a specific element
+Matcher<ArrayType>hasElementTypeMatcher<Type>
+
Matches arrays and C99 complex types that have a specific element
 type.
 
 Given
@@ -2461,8 +2461,8 @@ Example matches b (matcher = binaryOperator(hasRHS()))
 
-Matcher<BlockPointerTypeLoc>pointeeLocMatcher<TypeLoc> -
Narrows PointerType (and similar) matchers to those where the
+Matcher<BlockPointerTypeLoc>pointeeLocMatcher<TypeLoc>
+
Narrows PointerType (and similar) matchers to those where the
 pointee matches a given matcher.
 
 Given
@@ -2477,8 +2477,8 @@ Usable as: Matcher<BlockPointerType>pointeeMatcher<Type>
-
Narrows PointerType (and similar) matchers to those where the
+Matcher<BlockPointerType>pointeeMatcher<Type>
+
Narrows PointerType (and similar) matchers to those where the
 pointee matches a given matcher.
 
 Given
@@ -2771,8 +2771,8 @@ classTemplateSpecializationDecl(hasTemplateArgument(
 
-Matcher<ComplexTypeLoc>hasElementTypeLocMatcher<TypeLoc> -
Matches arrays and C99 complex types that have a specific element
+Matcher<ComplexTypeLoc>hasElementTypeLocMatcher<TypeLoc>
+
Matches arrays and C99 complex types that have a specific element
 type.
 
 Given
@@ -2786,8 +2786,8 @@ Usable as: Matcher<ComplexType>hasElementTypeMatcher<Type>
-
Matches arrays and C99 complex types that have a specific element
+Matcher<ComplexType>hasElementTypeMatcher<Type>
+
Matches arrays and C99 complex types that have a specific element
 type.
 
 Given
@@ -3227,8 +3227,8 @@ memberExpr(member(hasName("first")))
 
-Matcher<MemberPointerTypeLoc>pointeeLocMatcher<TypeLoc> -
Narrows PointerType (and similar) matchers to those where the
+Matcher<MemberPointerTypeLoc>pointeeLocMatcher<TypeLoc>
+
Narrows PointerType (and similar) matchers to those where the
 pointee matches a given matcher.
 
 Given
@@ -3243,8 +3243,8 @@ Usable as: Matcher<MemberPointerType>pointeeMatcher<Type>
-
Narrows PointerType (and similar) matchers to those where the
+Matcher<MemberPointerType>pointeeMatcher<Type>
+
Narrows PointerType (and similar) matchers to those where the
 pointee matches a given matcher.
 
 Given
@@ -3338,8 +3338,8 @@ Usable as: Matcher<PointerTypeLoc>pointeeLocMatcher<TypeLoc>
-
Narrows PointerType (and similar) matchers to those where the
+Matcher<PointerTypeLoc>pointeeLocMatcher<TypeLoc>
+
Narrows PointerType (and similar) matchers to those where the
 pointee matches a given matcher.
 
 Given
@@ -3354,8 +3354,8 @@ Usable as: Matcher<PointerType>pointeeMatcher<Type>
-
Narrows PointerType (and similar) matchers to those where the
+Matcher<PointerType>pointeeMatcher<Type>
+
Narrows PointerType (and similar) matchers to those where the
 pointee matches a given matcher.
 
 Given
@@ -3414,8 +3414,8 @@ Usable as: Matcher<ReferenceTypeLoc>pointeeLocMatcher<TypeLoc>
-
Narrows PointerType (and similar) matchers to those where the
+Matcher<ReferenceTypeLoc>pointeeLocMatcher<TypeLoc>
+
Narrows PointerType (and similar) matchers to those where the
 pointee matches a given matcher.
 
 Given
@@ -3430,8 +3430,8 @@ Usable as: Matcher<ReferenceType>pointeeMatcher<Type>
-
Narrows PointerType (and similar) matchers to those where the
+Matcher<ReferenceType>pointeeMatcher<Type>
+
Narrows PointerType (and similar) matchers to those where the
 pointee matches a given matcher.
 
 Given
diff --git a/docs/tools/dump_ast_matchers.py b/docs/tools/dump_ast_matchers.py
index 267cdb054c..bbf48c7646 100644
--- a/docs/tools/dump_ast_matchers.py
+++ b/docs/tools/dump_ast_matchers.py
@@ -160,14 +160,17 @@ def act_on_decl(declaration, comment, allowed_types):
 
     m = re.match(""".*AST_TYPE(LOC)?_TRAVERSE_MATCHER\(
                        \s*([^\s,]+\s*),
-                       \s*(?:[^\s,]+\s*)
+                       \s*(?:[^\s,]+\s*),
+                       \s*AST_POLYMORPHIC_SUPPORTED_TYPES_([^(]*)\(([^)]*)\)
                      \)\s*;\s*$""", declaration, flags=re.X)
     if m:
-      loc = m.group(1)
-      name = m.group(2)
-      result_types = extract_result_types(comment)
-      if not result_types:
-        raise Exception('Did not find allowed result types for: %s' % name)
+      loc, name, n_results, results = m.groups()[0:4]
+      result_types = [r.strip() for r in results.split(',')]
+
+      comment_result_types = extract_result_types(comment)
+      if (comment_result_types and
+          sorted(result_types) != sorted(comment_result_types)):
+        raise Exception('Inconsistent documentation for: %s' % name)
       for result_type in result_types:
         add_matcher(result_type, name, 'Matcher', comment)
         if loc:
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index aa2e4f7cb8..151bed5a83 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -2905,7 +2905,9 @@ AST_TYPE_MATCHER(ComplexType, complexType);
 ///   matches "int b[7]"
 ///
 /// Usable as: Matcher, Matcher
-AST_TYPELOC_TRAVERSE_MATCHER(hasElementType, getElement);
+AST_TYPELOC_TRAVERSE_MATCHER(
+    hasElementType, getElement,
+    AST_POLYMORPHIC_SUPPORTED_TYPES_2(ArrayType, ComplexType));
 
 /// \brief Matches C arrays with a specified constant size.
 ///
@@ -3012,7 +3014,8 @@ AST_TYPE_MATCHER(AtomicType, atomicType);
 ///  matches "_Atomic(int) i"
 ///
 /// Usable as: Matcher
-AST_TYPELOC_TRAVERSE_MATCHER(hasValueType, getValue);
+AST_TYPELOC_TRAVERSE_MATCHER(hasValueType, getValue,
+                             AST_POLYMORPHIC_SUPPORTED_TYPES_1(AtomicType));
 
 /// \brief Matches types nodes representing C++11 auto types.
 ///
@@ -3040,7 +3043,8 @@ AST_TYPE_MATCHER(AutoType, autoType);
 ///   matches "auto a"
 ///
 /// Usable as: Matcher
-AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType);
+AST_TYPE_TRAVERSE_MATCHER(hasDeducedType, getDeducedType,
+                          AST_POLYMORPHIC_SUPPORTED_TYPES_1(AutoType));
 
 /// \brief Matches \c FunctionType nodes.
 ///
@@ -3077,7 +3081,8 @@ AST_TYPE_MATCHER(ParenType, parenType);
 /// \c ptr_to_func but not \c ptr_to_array.
 ///
 /// Usable as: Matcher
-AST_TYPE_TRAVERSE_MATCHER(innerType, getInnerType);
+AST_TYPE_TRAVERSE_MATCHER(innerType, getInnerType,
+                          AST_POLYMORPHIC_SUPPORTED_TYPES_1(ParenType));
 
 /// \brief Matches block pointer types, i.e. types syntactically represented as
 /// "void (^)(int)".
@@ -3171,7 +3176,10 @@ AST_TYPE_MATCHER(RValueReferenceType, rValueReferenceType);
 ///
 /// Usable as: Matcher, Matcher,
 ///   Matcher, Matcher
-AST_TYPELOC_TRAVERSE_MATCHER(pointee, getPointee);
+AST_TYPELOC_TRAVERSE_MATCHER(
+    pointee, getPointee,
+    AST_POLYMORPHIC_SUPPORTED_TYPES_4(BlockPointerType, MemberPointerType,
+                                      PointerType, ReferenceType));
 
 /// \brief Matches typedef types.
 ///
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
index f29ea0e1dc..915f1bd6af 100644
--- a/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1434,9 +1434,53 @@ private:
   TypeLoc (T::*TraverseFunction)() const;
 };
 
-template 
-T makeTypeAllOfComposite(ArrayRef *> InnerMatchers) {
-  return T(makeAllOfComposite(InnerMatchers));
+/// \brief Converts a \c Matcher to a \c Matcher, where
+/// \c OuterT is any type that is supported by \c Getter.
+///
+/// \code Getter::value() \endcode returns a
+/// \code InnerTBase (OuterT::*)() \endcode, which is used to adapt a \c OuterT
+/// object into a \c InnerT
+template  class Getter,
+          template  class MatcherImpl,
+          typename ReturnTypesF>
+class TypeTraversePolymorphicMatcher {
+private:
+  typedef TypeTraversePolymorphicMatcher Self;
+  static Self create(ArrayRef *> InnerMatchers);
+
+public:
+  typedef typename ExtractFunctionArgMeta::type ReturnTypes;
+
+  explicit TypeTraversePolymorphicMatcher(
+      ArrayRef *> InnerMatchers)
+      : InnerMatcher(makeAllOfComposite(InnerMatchers)) {}
+
+  template  operator Matcher() const {
+    return Matcher(
+        new MatcherImpl(InnerMatcher, Getter::value()));
+  }
+
+  struct Func : public llvm::VariadicFunction,
+                                              &Self::create> {
+    Func() {}
+  };
+
+private:
+  const Matcher InnerMatcher;
+};
+
+// Define the create() method out of line to silence a GCC warning about
+// the struct "Func" having greater visibility than its base, which comes from
+// using the flag -fvisibility-inlines-hidden.
+template  class Getter,
+          template  class MatcherImpl, typename ReturnTypesF>
+TypeTraversePolymorphicMatcher
+TypeTraversePolymorphicMatcher<
+    InnerTBase, Getter, MatcherImpl,
+    ReturnTypesF>::create(ArrayRef *> InnerMatchers) {
+  return Self(InnerMatchers);
 }
 
 } // end namespace internal
diff --git a/include/clang/ASTMatchers/ASTMatchersMacros.h b/include/clang/ASTMatchers/ASTMatchersMacros.h
index 91e254eb57..79e9daae8a 100644
--- a/include/clang/ASTMatchers/ASTMatchersMacros.h
+++ b/include/clang/ASTMatchers/ASTMatchersMacros.h
@@ -163,6 +163,7 @@
 /// \c void(TypeList), which works thanks to the parenthesis.
 /// The \c PolymorphicMatcherWithParam* classes will unpack the function type to
 /// extract the TypeList object.
+#define AST_POLYMORPHIC_SUPPORTED_TYPES_1(t1) void(internal::TypeList)
 #define AST_POLYMORPHIC_SUPPORTED_TYPES_2(t1, t2)                              \
   void(internal::TypeList)
 #define AST_POLYMORPHIC_SUPPORTED_TYPES_3(t1, t2, t3)                          \
@@ -307,62 +308,27 @@
 /// For a specific \c SpecificType, the traversal is done using 
 /// \c SpecificType::FunctionName. The existance of such a function determines
 /// whether a corresponding matcher can be used on \c SpecificType.
-#define AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName)                   \
-  class Polymorphic##MatcherName##TypeMatcher {                                \
-  public:                                                                      \
-    Polymorphic##MatcherName##TypeMatcher(                                     \
-        const internal::Matcher &InnerMatcher)                       \
-        : InnerMatcher(InnerMatcher) {                                         \
-    }                                                                          \
-    template  operator internal:: Matcher< T>() {                  \
-      return internal::Matcher(new internal::TypeTraverseMatcher(        \
-                                          InnerMatcher, &T::FunctionName));    \
-    }                                                                          \
-  private:                                                                     \
-    const internal::Matcher InnerMatcher;                            \
-  }                                                                            \
-  ;                                                                            \
-  class Variadic##MatcherName##TypeTraverseMatcher                             \
-      : public llvm::VariadicFunction<                                         \
-          Polymorphic##MatcherName##TypeMatcher, internal::Matcher,  \
-          internal::makeTypeAllOfComposite<                                    \
-              Polymorphic##MatcherName##TypeMatcher, QualType> > {             \
-  public:                                                                      \
-    Variadic##MatcherName##TypeTraverseMatcher() {                             \
-    }                                                                          \
+#define AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName, ReturnTypesF)     \
+  namespace internal {                                                         \
+  template  struct TypeMatcher##MatcherName##Getter {              \
+    static QualType (T::*value())() const { return &T::FunctionName; }         \
+  };                                                                           \
   }                                                                            \
-  ;                                                                            \
-  const Variadic##MatcherName##TypeTraverseMatcher MatcherName
+  const internal::TypeTraversePolymorphicMatcher<                              \
+      QualType, internal::TypeMatcher##MatcherName##Getter,                    \
+      internal::TypeTraverseMatcher, ReturnTypesF>::Func MatcherName
 
 /// \brief AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName) works
 /// identical to \c AST_TYPE_TRAVERSE_MATCHER but operates on \c TypeLocs.
-#define AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName)                \
-  class Polymorphic##MatcherName##TypeLocMatcher {                             \
-  public:                                                                      \
-    Polymorphic##MatcherName##TypeLocMatcher(                                  \
-        const internal::Matcher &InnerMatcher)                        \
-        : InnerMatcher(InnerMatcher) {                                         \
-    }                                                                          \
-    template  operator internal:: Matcher< T>() {                  \
-      return internal::Matcher(                                             \
-          new internal::TypeLocTraverseMatcher(InnerMatcher,                \
-                                                  &T::FunctionName##Loc));     \
-    }                                                                          \
-  private:                                                                     \
-    const internal::Matcher InnerMatcher;                             \
-  }                                                                            \
-  ;                                                                            \
-  class Variadic##MatcherName##TypeLocTraverseMatcher                          \
-      : public llvm::VariadicFunction<                                         \
-          Polymorphic##MatcherName##TypeLocMatcher, internal::Matcher,\
-          internal::makeTypeAllOfComposite<                                    \
-              Polymorphic##MatcherName##TypeLocMatcher, TypeLoc> > {           \
-  public:                                                                      \
-    Variadic##MatcherName##TypeLocTraverseMatcher() {                          \
-    }                                                                          \
+#define AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName, ReturnTypesF)  \
+  namespace internal {                                                         \
+  template  struct TypeLocMatcher##MatcherName##Getter {           \
+    static TypeLoc (T::*value())() const { return &T::FunctionName##Loc; }     \
+  };                                                                           \
   }                                                                            \
-  ;                                                                            \
-  const Variadic##MatcherName##TypeLocTraverseMatcher MatcherName##Loc;        \
-  AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName##Type)
+  const internal::TypeTraversePolymorphicMatcher<                              \
+      TypeLoc, internal::TypeLocMatcher##MatcherName##Getter,                  \
+      internal::TypeLocTraverseMatcher, ReturnTypesF>::Func MatcherName##Loc;  \
+  AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName##Type, ReturnTypesF)
 
 #endif // LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
diff --git a/lib/ASTMatchers/Dynamic/Marshallers.h b/lib/ASTMatchers/Dynamic/Marshallers.h
index c3a5260eb4..3aa55d0a5a 100644
--- a/lib/ASTMatchers/Dynamic/Marshallers.h
+++ b/lib/ASTMatchers/Dynamic/Marshallers.h
@@ -240,32 +240,32 @@ static MatcherList matcherMarshall2(ReturnType (*Func)(ArgType1, ArgType2),
 #undef CHECK_ARG_TYPE
 
 /// \brief Variadic marshaller function.
-template 
-MatcherList VariadicMatcherCreateCallback(StringRef MatcherName,
+template )>
+MatcherList variadicMatcherCreateCallback(StringRef MatcherName,
                                           const SourceRange &NameRange,
                                           ArrayRef Args,
                                           Diagnostics *Error) {
-  typedef ast_matchers::internal::Matcher DerivedMatcherType;
-  DerivedMatcherType **InnerArgs = new DerivedMatcherType *[Args.size()]();
+  ArgT **InnerArgs = new ArgT *[Args.size()]();
 
   bool HasError = false;
   for (size_t i = 0, e = Args.size(); i != e; ++i) {
-    typedef ArgTypeTraits DerivedTraits;
+    typedef ArgTypeTraits ArgTraits;
     const ParserValue &Arg = Args[i];
     const VariantValue &Value = Arg.Value;
-    if (!DerivedTraits::is(Value)) {
+    if (!ArgTraits::is(Value)) {
       Error->pushErrorFrame(Arg.Range, Error->ET_RegistryWrongArgType)
-          << (i + 1) << DerivedTraits::asString() << Value.getTypeAsString();
+          << (i + 1) << ArgTraits::asString() << Value.getTypeAsString();
       HasError = true;
       break;
     }
-    InnerArgs[i] = new DerivedMatcherType(DerivedTraits::get(Value));
+    InnerArgs[i] = new ArgT(ArgTraits::get(Value));
   }
 
   MatcherList Out;
   if (!HasError) {
-    Out = ast_matchers::internal::makeDynCastAllOfComposite(
-        ArrayRef(InnerArgs, Args.size()));
+    Out = outvalueToMatcherList(
+        Func(ArrayRef(InnerArgs, Args.size())));
   }
 
   for (size_t i = 0, e = Args.size(); i != e; ++i) {
@@ -303,22 +303,14 @@ MatcherCreateCallback *makeMatcherAutoMarshall(ReturnType (*Func)(ArgType1,
       ReturnType (*)(ArgType1, ArgType2)>(matcherMarshall2, Func, MatcherName);
 }
 
-/// \brief Variadic overloads.
-template 
-MatcherCreateCallback *makeMatcherAutoMarshall(
-    ast_matchers::internal::VariadicAllOfMatcher Func,
-    StringRef MatcherName) {
-  return new FreeFuncMatcherCreateCallback(
-      &VariadicMatcherCreateCallback, MatcherName);
-}
-
-template 
+/// \brief Variadic overload.
+template )>
 MatcherCreateCallback *
-makeMatcherAutoMarshall(ast_matchers::internal::VariadicDynCastAllOfMatcher<
-                            BaseType, MatcherType> Func,
+makeMatcherAutoMarshall(llvm::VariadicFunction VarFunc,
                         StringRef MatcherName) {
   return new FreeFuncMatcherCreateCallback(
-      &VariadicMatcherCreateCallback, MatcherName);
+      &variadicMatcherCreateCallback, MatcherName);
 }
 
 }  // namespace internal
diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp
index c887f3da60..9e8898e95d 100644
--- a/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -69,13 +69,6 @@ RegistryMaps::RegistryMaps() {
   // withInitializer
   // isWritten
   //
-  // Type traversal:
-  // hasElementType
-  // hasValueType
-  // hasDeducedType
-  // innerType
-  // pointee
-  //
   // Function overloaded by args:
   // hasType
   // callee
@@ -175,8 +168,10 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(hasCondition);
   REGISTER_MATCHER(hasConditionVariableStatement);
   REGISTER_MATCHER(hasDeclContext);
+  REGISTER_MATCHER(hasDeducedType);
   REGISTER_MATCHER(hasDestinationType);
   REGISTER_MATCHER(hasEitherOperand);
+  REGISTER_MATCHER(hasElementType);
   REGISTER_MATCHER(hasFalseExpression);
   REGISTER_MATCHER(hasImplicitDestinationType);
   REGISTER_MATCHER(hasIncrement);
@@ -200,6 +195,7 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(hasTargetDecl);
   REGISTER_MATCHER(hasTrueExpression);
   REGISTER_MATCHER(hasUnaryOperand);
+  REGISTER_MATCHER(hasValueType);
   REGISTER_MATCHER(ifStmt);
   REGISTER_MATCHER(ignoringImpCasts);
   REGISTER_MATCHER(ignoringParenCasts);
@@ -207,6 +203,7 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(implicitCastExpr);
   REGISTER_MATCHER(incompleteArrayType);
   REGISTER_MATCHER(initListExpr);
+  REGISTER_MATCHER(innerType);
   REGISTER_MATCHER(integerLiteral);
   REGISTER_MATCHER(isArrow);
   REGISTER_MATCHER(isConstQualified);
@@ -245,6 +242,7 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(operatorCallExpr);
   REGISTER_MATCHER(parameterCountIs);
   REGISTER_MATCHER(parenType);
+  REGISTER_MATCHER(pointee);
   REGISTER_MATCHER(pointerType);
   REGISTER_MATCHER(qualType);
   REGISTER_MATCHER(rValueReferenceType);
diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
index e6b04e0f76..6ef32dd47a 100644
--- a/unittests/ASTMatchers/Dynamic/ParserTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -179,10 +179,12 @@ TEST(ParserTest, ParseMatcher) {
 using ast_matchers::internal::Matcher;
 
 TEST(ParserTest, FullParserTest) {
+  Diagnostics Error;
   OwningPtr VarDecl(Parser::parseMatcherExpression(
       "varDecl(hasInitializer(binaryOperator(hasLHS(integerLiteral()),"
       "                                      hasOperatorName(\"+\"))))",
-      NULL));
+      &Error));
+  EXPECT_EQ("", Error.ToStringFull());
   Matcher M = Matcher::constructFrom(*VarDecl);
   EXPECT_TRUE(matches("int x = 1 + false;", M));
   EXPECT_FALSE(matches("int x = true + 1;", M));
@@ -190,13 +192,13 @@ TEST(ParserTest, FullParserTest) {
   EXPECT_FALSE(matches("int x = true - 1;", M));
 
   OwningPtr HasParameter(Parser::parseMatcherExpression(
-      "functionDecl(hasParameter(1, hasName(\"x\")))", NULL));
+      "functionDecl(hasParameter(1, hasName(\"x\")))", &Error));
+  EXPECT_EQ("", Error.ToStringFull());
   M = Matcher::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(
       "hasInitializer(\n    binaryOperator(hasLHS(\"A\")))", &Error) == NULL);
   EXPECT_EQ("1:1: Error parsing argument 1 for matcher hasInitializer.\n"
diff --git a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
index 9de2213099..b7e29ed0cb 100644
--- a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
@@ -36,32 +36,43 @@ public:
     return Out;
   }
 
-  template 
-  Matcher constructMatcher(StringRef MatcherName, Diagnostics *Error) {
-    return Registry::constructMatcher(MatcherName, SourceRange(), Args(), Error)
-        .getTypedMatcher();
+  MatcherList constructMatcher(StringRef MatcherName,
+                               Diagnostics *Error = NULL) {
+    Diagnostics DummyError;
+    if (!Error) Error = &DummyError;
+    const MatcherList Out =
+        Registry::constructMatcher(MatcherName, SourceRange(), Args(), Error);
+    EXPECT_EQ("", DummyError.ToStringFull());
+    return Out;
   }
 
-  template 
-  Matcher constructMatcher(StringRef MatcherName, const VariantValue &Arg1,
-                              Diagnostics *Error) {
-    return Registry::constructMatcher(MatcherName, SourceRange(), Args(Arg1),
-                                      Error).getTypedMatcher();
+  MatcherList constructMatcher(StringRef MatcherName, const VariantValue &Arg1,
+                               Diagnostics *Error = NULL) {
+    Diagnostics DummyError;
+    if (!Error) Error = &DummyError;
+    const MatcherList Out = Registry::constructMatcher(
+        MatcherName, SourceRange(), Args(Arg1), Error);
+    EXPECT_EQ("", DummyError.ToStringFull());
+    return Out;
   }
 
-  template 
-  Matcher constructMatcher(StringRef MatcherName, const VariantValue &Arg1,
-                              const VariantValue &Arg2, Diagnostics *Error) {
-    return Registry::constructMatcher(MatcherName, SourceRange(),
-                                      Args(Arg1, Arg2), Error)
-        .getTypedMatcher();
+  MatcherList constructMatcher(StringRef MatcherName, const VariantValue &Arg1,
+                               const VariantValue &Arg2,
+                               Diagnostics *Error = NULL) {
+    Diagnostics DummyError;
+    if (!Error) Error = &DummyError;
+    const MatcherList Out = Registry::constructMatcher(
+        MatcherName, SourceRange(), Args(Arg1, Arg2), Error);
+    EXPECT_EQ("", DummyError.ToStringFull());
+    return Out;
   }
 };
 
 TEST_F(RegistryTest, CanConstructNoArgs) {
-  Matcher IsArrowValue = constructMatcher(
-      "memberExpr", constructMatcher("isArrow", NULL), NULL);
-  Matcher BoolValue = constructMatcher("boolLiteral", NULL);
+  Matcher IsArrowValue = constructMatcher(
+      "memberExpr", constructMatcher("isArrow")).getTypedMatcher();
+  Matcher BoolValue =
+      constructMatcher("boolLiteral").getTypedMatcher();
 
   const std::string ClassSnippet = "struct Foo { int x; };\n"
                                    "Foo *foo = new Foo;\n"
@@ -75,25 +86,25 @@ TEST_F(RegistryTest, CanConstructNoArgs) {
 }
 
 TEST_F(RegistryTest, ConstructWithSimpleArgs) {
-  Matcher Value = constructMatcher(
-      "namedDecl",
-      constructMatcher("hasName", std::string("X"), NULL), NULL);
+  Matcher Value = constructMatcher(
+      "namedDecl", constructMatcher("hasName", std::string("X")))
+      .getTypedMatcher();
   EXPECT_TRUE(matches("class X {};", Value));
   EXPECT_FALSE(matches("int x;", Value));
 
-  Value =
-      functionDecl(constructMatcher("parameterCountIs", 2, NULL));
+  Value = functionDecl(constructMatcher("parameterCountIs", 2)
+                           .getTypedMatcher());
   EXPECT_TRUE(matches("void foo(int,int);", Value));
   EXPECT_FALSE(matches("void foo(int);", Value));
 }
 
 TEST_F(RegistryTest, ConstructWithMatcherArgs) {
-  Matcher HasInitializerSimple = constructMatcher(
-      "varDecl", constructMatcher("hasInitializer", stmt(), NULL),
-      NULL);
-  Matcher HasInitializerComplex = constructMatcher(
-      "varDecl", constructMatcher("hasInitializer", callExpr(), NULL),
-      NULL);
+  Matcher HasInitializerSimple =
+      constructMatcher("varDecl", constructMatcher("hasInitializer", stmt()))
+          .getTypedMatcher();
+  Matcher HasInitializerComplex = constructMatcher(
+      "varDecl", constructMatcher("hasInitializer", callExpr()))
+      .getTypedMatcher();
 
   std::string code = "int i;";
   EXPECT_FALSE(matches(code, HasInitializerSimple));
@@ -107,20 +118,20 @@ TEST_F(RegistryTest, ConstructWithMatcherArgs) {
   EXPECT_TRUE(matches(code, HasInitializerSimple));
   EXPECT_TRUE(matches(code, HasInitializerComplex));
 
-  Matcher HasParameter = functionDecl(
-      constructMatcher("hasParameter", 1, hasName("x"), NULL));
+  Matcher HasParameter = functionDecl(constructMatcher(
+      "hasParameter", 1, hasName("x")).getTypedMatcher());
   EXPECT_TRUE(matches("void f(int a, int x);", HasParameter));
   EXPECT_FALSE(matches("void f(int x, int a);", HasParameter));
 }
 
 TEST_F(RegistryTest, PolymorphicMatchers) {
-  const MatcherList IsDefinition =
-      Registry::constructMatcher("isDefinition", SourceRange(), Args(), NULL);
-  Matcher Var = constructMatcher("varDecl", IsDefinition, NULL);
+  const MatcherList IsDefinition = constructMatcher("isDefinition");
+  Matcher Var =
+      constructMatcher("varDecl", IsDefinition).getTypedMatcher();
   Matcher Class =
-      constructMatcher("recordDecl", IsDefinition, NULL);
+      constructMatcher("recordDecl", IsDefinition).getTypedMatcher();
   Matcher Func =
-      constructMatcher("functionDecl", IsDefinition, NULL);
+      constructMatcher("functionDecl", IsDefinition).getTypedMatcher();
   EXPECT_TRUE(matches("int a;", Var));
   EXPECT_FALSE(matches("extern int a;", Var));
   EXPECT_TRUE(matches("class A {};", Class));
@@ -128,9 +139,9 @@ TEST_F(RegistryTest, PolymorphicMatchers) {
   EXPECT_TRUE(matches("void f(){};", Func));
   EXPECT_FALSE(matches("void f();", Func));
 
-  Matcher Anything = constructMatcher("anything", NULL);
+  Matcher Anything = constructMatcher("anything").getTypedMatcher();
   Matcher RecordDecl =
-      constructMatcher("recordDecl", Anything, NULL);
+      constructMatcher("recordDecl", Anything).getTypedMatcher();
 
   EXPECT_TRUE(matches("int a;", Anything));
   EXPECT_TRUE(matches("class A {};", Anything));
@@ -146,30 +157,42 @@ TEST_F(RegistryTest, PolymorphicMatchers) {
 #endif
 }
 
+TEST_F(RegistryTest, TypeTraversal) {
+  Matcher M = constructMatcher(
+      "pointerType",
+      constructMatcher("pointee", constructMatcher("isConstQualified"),
+                       constructMatcher("isInteger"))).getTypedMatcher();
+  EXPECT_FALSE(matches("int *a;", M));
+  EXPECT_TRUE(matches("int const *b;", M));
+
+  M = constructMatcher(
+      "arrayType",
+      constructMatcher("hasElementType", constructMatcher("builtinType")))
+      .getTypedMatcher();
+  EXPECT_FALSE(matches("struct A{}; A a[7];;", M));
+  EXPECT_TRUE(matches("int b[7];", M));
+}
+
 TEST_F(RegistryTest, Errors) {
   // Incorrect argument count.
   OwningPtr Error(new Diagnostics());
-  EXPECT_TRUE(Registry::constructMatcher("hasInitializer", SourceRange(),
-                                         Args(), Error.get()).empty());
+  EXPECT_TRUE(constructMatcher("hasInitializer", Error.get()).empty());
   EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)",
             Error->ToString());
   Error.reset(new Diagnostics());
-  EXPECT_TRUE(Registry::constructMatcher(
-      "isArrow", SourceRange(), Args(std::string()), Error.get()).empty());
+  EXPECT_TRUE(constructMatcher("isArrow", std::string(), Error.get()).empty());
   EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
             Error->ToString());
 
   // Bad argument type
   Error.reset(new Diagnostics());
-  EXPECT_TRUE(Registry::constructMatcher(
-      "ofClass", SourceRange(), Args(std::string()), Error.get()).empty());
+  EXPECT_TRUE(constructMatcher("ofClass", std::string(), Error.get()).empty());
   EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher) != "
             "(Actual = String)",
             Error->ToString());
   Error.reset(new Diagnostics());
-  EXPECT_TRUE(Registry::constructMatcher(
-      "recordDecl", SourceRange(), Args(recordDecl(), parameterCountIs(3)),
-      Error.get()).empty());
+  EXPECT_TRUE(constructMatcher("recordDecl", recordDecl(), parameterCountIs(3),
+                               Error.get()).empty());
   EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher) != "
             "(Actual = Matcher)",
             Error->ToString());
-- 
2.40.0