From 3f84bb341bfb1312842b09db71d76bc3898ba247 Mon Sep 17 00:00:00 2001 From: Samuel Benzaquen <sbenza@google.com> 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 ee7476ba80d..a3c6b13d45c 100644 --- a/docs/LibASTMatchersReference.html +++ b/docs/LibASTMatchersReference.html @@ -2367,8 +2367,8 @@ arraySubscriptExpression(hasIndex(integerLiteral())) </pre></td></tr> -<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayTypeLoc.html">ArrayTypeLoc</a>></td><td class="name" onclick="toggle('hasElementTypeLoc1')"><a name="hasElementTypeLoc1Anchor">hasElementTypeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr> -<tr><td colspan="4" class="doc" id="hasElementTypeLoc1"><pre>Matches arrays and C99 complex types that have a specific element +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayTypeLoc.html">ArrayTypeLoc</a>></td><td class="name" onclick="toggle('hasElementTypeLoc0')"><a name="hasElementTypeLoc0Anchor">hasElementTypeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr> +<tr><td colspan="4" class="doc" id="hasElementTypeLoc0"><pre>Matches arrays and C99 complex types that have a specific element type. Given @@ -2382,8 +2382,8 @@ Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayT </pre></td></tr> -<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>></td><td class="name" onclick="toggle('hasElementType1')"><a name="hasElementType1Anchor">hasElementType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr> -<tr><td colspan="4" class="doc" id="hasElementType1"><pre>Matches arrays and C99 complex types that have a specific element +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayType.html">ArrayType</a>></td><td class="name" onclick="toggle('hasElementType0')"><a name="hasElementType0Anchor">hasElementType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr> +<tr><td colspan="4" class="doc" id="hasElementType0"><pre>Matches arrays and C99 complex types that have a specific element type. Given @@ -2461,8 +2461,8 @@ Example matches b (matcher = binaryOperator(hasRHS())) </pre></td></tr> -<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerTypeLoc.html">BlockPointerTypeLoc</a>></td><td class="name" onclick="toggle('pointeeLoc3')"><a name="pointeeLoc3Anchor">pointeeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr> -<tr><td colspan="4" class="doc" id="pointeeLoc3"><pre>Narrows PointerType (and similar) matchers to those where the +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerTypeLoc.html">BlockPointerTypeLoc</a>></td><td class="name" onclick="toggle('pointeeLoc0')"><a name="pointeeLoc0Anchor">pointeeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr> +<tr><td colspan="4" class="doc" id="pointeeLoc0"><pre>Narrows PointerType (and similar) matchers to those where the pointee matches a given matcher. Given @@ -2477,8 +2477,8 @@ Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockP </pre></td></tr> -<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>></td><td class="name" onclick="toggle('pointee3')"><a name="pointee3Anchor">pointee</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr> -<tr><td colspan="4" class="doc" id="pointee3"><pre>Narrows PointerType (and similar) matchers to those where the +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockPointerType.html">BlockPointerType</a>></td><td class="name" onclick="toggle('pointee0')"><a name="pointee0Anchor">pointee</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr> +<tr><td colspan="4" class="doc" id="pointee0"><pre>Narrows PointerType (and similar) matchers to those where the pointee matches a given matcher. Given @@ -2771,8 +2771,8 @@ classTemplateSpecializationDecl(hasTemplateArgument( </pre></td></tr> -<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexTypeLoc.html">ComplexTypeLoc</a>></td><td class="name" onclick="toggle('hasElementTypeLoc0')"><a name="hasElementTypeLoc0Anchor">hasElementTypeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr> -<tr><td colspan="4" class="doc" id="hasElementTypeLoc0"><pre>Matches arrays and C99 complex types that have a specific element +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexTypeLoc.html">ComplexTypeLoc</a>></td><td class="name" onclick="toggle('hasElementTypeLoc1')"><a name="hasElementTypeLoc1Anchor">hasElementTypeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr> +<tr><td colspan="4" class="doc" id="hasElementTypeLoc1"><pre>Matches arrays and C99 complex types that have a specific element type. Given @@ -2786,8 +2786,8 @@ Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ArrayT </pre></td></tr> -<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>></td><td class="name" onclick="toggle('hasElementType0')"><a name="hasElementType0Anchor">hasElementType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr> -<tr><td colspan="4" class="doc" id="hasElementType0"><pre>Matches arrays and C99 complex types that have a specific element +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ComplexType.html">ComplexType</a>></td><td class="name" onclick="toggle('hasElementType1')"><a name="hasElementType1Anchor">hasElementType</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr> +<tr><td colspan="4" class="doc" id="hasElementType1"><pre>Matches arrays and C99 complex types that have a specific element type. Given @@ -3227,8 +3227,8 @@ memberExpr(member(hasName("first"))) </pre></td></tr> -<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerTypeLoc.html">MemberPointerTypeLoc</a>></td><td class="name" onclick="toggle('pointeeLoc2')"><a name="pointeeLoc2Anchor">pointeeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr> -<tr><td colspan="4" class="doc" id="pointeeLoc2"><pre>Narrows PointerType (and similar) matchers to those where the +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerTypeLoc.html">MemberPointerTypeLoc</a>></td><td class="name" onclick="toggle('pointeeLoc1')"><a name="pointeeLoc1Anchor">pointeeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr> +<tr><td colspan="4" class="doc" id="pointeeLoc1"><pre>Narrows PointerType (and similar) matchers to those where the pointee matches a given matcher. Given @@ -3243,8 +3243,8 @@ Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockP </pre></td></tr> -<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>></td><td class="name" onclick="toggle('pointee2')"><a name="pointee2Anchor">pointee</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr> -<tr><td colspan="4" class="doc" id="pointee2"><pre>Narrows PointerType (and similar) matchers to those where the +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1MemberPointerType.html">MemberPointerType</a>></td><td class="name" onclick="toggle('pointee1')"><a name="pointee1Anchor">pointee</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr> +<tr><td colspan="4" class="doc" id="pointee1"><pre>Narrows PointerType (and similar) matchers to those where the pointee matches a given matcher. Given @@ -3338,8 +3338,8 @@ Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ParenT </pre></td></tr> -<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerTypeLoc.html">PointerTypeLoc</a>></td><td class="name" onclick="toggle('pointeeLoc1')"><a name="pointeeLoc1Anchor">pointeeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr> -<tr><td colspan="4" class="doc" id="pointeeLoc1"><pre>Narrows PointerType (and similar) matchers to those where the +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerTypeLoc.html">PointerTypeLoc</a>></td><td class="name" onclick="toggle('pointeeLoc2')"><a name="pointeeLoc2Anchor">pointeeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr> +<tr><td colspan="4" class="doc" id="pointeeLoc2"><pre>Narrows PointerType (and similar) matchers to those where the pointee matches a given matcher. Given @@ -3354,8 +3354,8 @@ Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockP </pre></td></tr> -<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>></td><td class="name" onclick="toggle('pointee1')"><a name="pointee1Anchor">pointee</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr> -<tr><td colspan="4" class="doc" id="pointee1"><pre>Narrows PointerType (and similar) matchers to those where the +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1PointerType.html">PointerType</a>></td><td class="name" onclick="toggle('pointee2')"><a name="pointee2Anchor">pointee</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr> +<tr><td colspan="4" class="doc" id="pointee2"><pre>Narrows PointerType (and similar) matchers to those where the pointee matches a given matcher. Given @@ -3414,8 +3414,8 @@ Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualTy </pre></td></tr> -<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceTypeLoc.html">ReferenceTypeLoc</a>></td><td class="name" onclick="toggle('pointeeLoc0')"><a name="pointeeLoc0Anchor">pointeeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr> -<tr><td colspan="4" class="doc" id="pointeeLoc0"><pre>Narrows PointerType (and similar) matchers to those where the +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceTypeLoc.html">ReferenceTypeLoc</a>></td><td class="name" onclick="toggle('pointeeLoc3')"><a name="pointeeLoc3Anchor">pointeeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td></tr> +<tr><td colspan="4" class="doc" id="pointeeLoc3"><pre>Narrows PointerType (and similar) matchers to those where the pointee matches a given matcher. Given @@ -3430,8 +3430,8 @@ Usable as: Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1BlockP </pre></td></tr> -<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>></td><td class="name" onclick="toggle('pointee0')"><a name="pointee0Anchor">pointee</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr> -<tr><td colspan="4" class="doc" id="pointee0"><pre>Narrows PointerType (and similar) matchers to those where the +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1ReferenceType.html">ReferenceType</a>></td><td class="name" onclick="toggle('pointee3')"><a name="pointee3Anchor">pointee</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>></td></tr> +<tr><td colspan="4" class="doc" id="pointee3"><pre>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 267cdb054c9..bbf48c7646d 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<Type>', comment) if loc: diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index aa2e4f7cb83..151bed5a837 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<ArrayType>, Matcher<ComplexType> -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<AtomicType> -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<AutoType> -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<ParenType> -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<BlockPointerType>, Matcher<MemberPointerType>, /// Matcher<PointerType>, Matcher<ReferenceType> -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 f29ea0e1dcc..915f1bd6afe 100644 --- a/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -1434,9 +1434,53 @@ private: TypeLoc (T::*TraverseFunction)() const; }; -template <typename T, typename InnerT> -T makeTypeAllOfComposite(ArrayRef<const Matcher<InnerT> *> InnerMatchers) { - return T(makeAllOfComposite<InnerT>(InnerMatchers)); +/// \brief Converts a \c Matcher<InnerT> to a \c Matcher<OuterT>, where +/// \c OuterT is any type that is supported by \c Getter. +/// +/// \code Getter<OuterT>::value() \endcode returns a +/// \code InnerTBase (OuterT::*)() \endcode, which is used to adapt a \c OuterT +/// object into a \c InnerT +template <typename InnerTBase, + template <typename OuterT> class Getter, + template <typename OuterT> class MatcherImpl, + typename ReturnTypesF> +class TypeTraversePolymorphicMatcher { +private: + typedef TypeTraversePolymorphicMatcher<InnerTBase, Getter, MatcherImpl, + ReturnTypesF> Self; + static Self create(ArrayRef<const Matcher<InnerTBase> *> InnerMatchers); + +public: + typedef typename ExtractFunctionArgMeta<ReturnTypesF>::type ReturnTypes; + + explicit TypeTraversePolymorphicMatcher( + ArrayRef<const Matcher<InnerTBase> *> InnerMatchers) + : InnerMatcher(makeAllOfComposite(InnerMatchers)) {} + + template <typename OuterT> operator Matcher<OuterT>() const { + return Matcher<OuterT>( + new MatcherImpl<OuterT>(InnerMatcher, Getter<OuterT>::value())); + } + + struct Func : public llvm::VariadicFunction<Self, Matcher<InnerTBase>, + &Self::create> { + Func() {} + }; + +private: + const Matcher<InnerTBase> 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 <typename InnerTBase, template <typename OuterT> class Getter, + template <typename OuterT> class MatcherImpl, typename ReturnTypesF> +TypeTraversePolymorphicMatcher<InnerTBase, Getter, MatcherImpl, ReturnTypesF> +TypeTraversePolymorphicMatcher< + InnerTBase, Getter, MatcherImpl, + ReturnTypesF>::create(ArrayRef<const Matcher<InnerTBase> *> InnerMatchers) { + return Self(InnerMatchers); } } // end namespace internal diff --git a/include/clang/ASTMatchers/ASTMatchersMacros.h b/include/clang/ASTMatchers/ASTMatchersMacros.h index 91e254eb571..79e9daae8a8 100644 --- a/include/clang/ASTMatchers/ASTMatchersMacros.h +++ b/include/clang/ASTMatchers/ASTMatchersMacros.h @@ -163,6 +163,7 @@ /// \c void(TypeList<Foo, Bar>), 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<t1>) #define AST_POLYMORPHIC_SUPPORTED_TYPES_2(t1, t2) \ void(internal::TypeList<t1, t2>) #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<QualType> &InnerMatcher) \ - : InnerMatcher(InnerMatcher) { \ - } \ - template <typename T> operator internal:: Matcher< T>() { \ - return internal::Matcher<T>(new internal::TypeTraverseMatcher<T>( \ - InnerMatcher, &T::FunctionName)); \ - } \ - private: \ - const internal::Matcher<QualType> InnerMatcher; \ - } \ - ; \ - class Variadic##MatcherName##TypeTraverseMatcher \ - : public llvm::VariadicFunction< \ - Polymorphic##MatcherName##TypeMatcher, internal::Matcher<QualType>, \ - internal::makeTypeAllOfComposite< \ - Polymorphic##MatcherName##TypeMatcher, QualType> > { \ - public: \ - Variadic##MatcherName##TypeTraverseMatcher() { \ - } \ +#define AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName, ReturnTypesF) \ + namespace internal { \ + template <typename T> 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<TypeLoc> &InnerMatcher) \ - : InnerMatcher(InnerMatcher) { \ - } \ - template <typename T> operator internal:: Matcher< T>() { \ - return internal::Matcher<T>( \ - new internal::TypeLocTraverseMatcher<T>(InnerMatcher, \ - &T::FunctionName##Loc)); \ - } \ - private: \ - const internal::Matcher<TypeLoc> InnerMatcher; \ - } \ - ; \ - class Variadic##MatcherName##TypeLocTraverseMatcher \ - : public llvm::VariadicFunction< \ - Polymorphic##MatcherName##TypeLocMatcher, internal::Matcher<TypeLoc>,\ - internal::makeTypeAllOfComposite< \ - Polymorphic##MatcherName##TypeLocMatcher, TypeLoc> > { \ - public: \ - Variadic##MatcherName##TypeLocTraverseMatcher() { \ - } \ +#define AST_TYPELOC_TRAVERSE_MATCHER(MatcherName, FunctionName, ReturnTypesF) \ + namespace internal { \ + template <typename T> 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 c3a5260eb43..3aa55d0a5a5 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 <typename BaseType, typename DerivedType> -MatcherList VariadicMatcherCreateCallback(StringRef MatcherName, +template <typename ResultT, typename ArgT, + ResultT (*Func)(ArrayRef<const ArgT *>)> +MatcherList variadicMatcherCreateCallback(StringRef MatcherName, const SourceRange &NameRange, ArrayRef<ParserValue> Args, Diagnostics *Error) { - typedef ast_matchers::internal::Matcher<DerivedType> 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<DerivedMatcherType> DerivedTraits; + typedef ArgTypeTraits<ArgT> 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<BaseType>( - ArrayRef<const DerivedMatcherType *>(InnerArgs, Args.size())); + Out = outvalueToMatcherList( + Func(ArrayRef<const ArgT *>(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 <typename MatcherType> -MatcherCreateCallback *makeMatcherAutoMarshall( - ast_matchers::internal::VariadicAllOfMatcher<MatcherType> Func, - StringRef MatcherName) { - return new FreeFuncMatcherCreateCallback( - &VariadicMatcherCreateCallback<MatcherType, MatcherType>, MatcherName); -} - -template <typename BaseType, typename MatcherType> +/// \brief Variadic overload. +template <typename ResultT, typename ArgT, + ResultT (*Func)(ArrayRef<const ArgT *>)> MatcherCreateCallback * -makeMatcherAutoMarshall(ast_matchers::internal::VariadicDynCastAllOfMatcher< - BaseType, MatcherType> Func, +makeMatcherAutoMarshall(llvm::VariadicFunction<ResultT, ArgT, Func> VarFunc, StringRef MatcherName) { return new FreeFuncMatcherCreateCallback( - &VariadicMatcherCreateCallback<BaseType, MatcherType>, MatcherName); + &variadicMatcherCreateCallback<ResultT, ArgT, Func>, MatcherName); } } // namespace internal diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp index c887f3da603..9e8898e95d8 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 e6b04e0f762..6ef32dd47ac 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<DynTypedMatcher> VarDecl(Parser::parseMatcherExpression( "varDecl(hasInitializer(binaryOperator(hasLHS(integerLiteral())," " hasOperatorName(\"+\"))))", - NULL)); + &Error)); + EXPECT_EQ("", Error.ToStringFull()); Matcher<Decl> M = Matcher<Decl>::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<DynTypedMatcher> HasParameter(Parser::parseMatcherExpression( - "functionDecl(hasParameter(1, hasName(\"x\")))", NULL)); + "functionDecl(hasParameter(1, hasName(\"x\")))", &Error)); + EXPECT_EQ("", Error.ToStringFull()); 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( "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 9de22130999..b7e29ed0cbb 100644 --- a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp +++ b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp @@ -36,32 +36,43 @@ public: return Out; } - template <class T> - Matcher<T> constructMatcher(StringRef MatcherName, Diagnostics *Error) { - return Registry::constructMatcher(MatcherName, SourceRange(), Args(), Error) - .getTypedMatcher<T>(); + 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 <class T> - Matcher<T> constructMatcher(StringRef MatcherName, const VariantValue &Arg1, - Diagnostics *Error) { - return Registry::constructMatcher(MatcherName, SourceRange(), Args(Arg1), - Error).getTypedMatcher<T>(); + 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 <class T> - Matcher<T> constructMatcher(StringRef MatcherName, const VariantValue &Arg1, - const VariantValue &Arg2, Diagnostics *Error) { - return Registry::constructMatcher(MatcherName, SourceRange(), - Args(Arg1, Arg2), Error) - .getTypedMatcher<T>(); + 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<Stmt> IsArrowValue = constructMatcher<Stmt>( - "memberExpr", constructMatcher<MemberExpr>("isArrow", NULL), NULL); - Matcher<Stmt> BoolValue = constructMatcher<Stmt>("boolLiteral", NULL); + Matcher<Stmt> IsArrowValue = constructMatcher( + "memberExpr", constructMatcher("isArrow")).getTypedMatcher<Stmt>(); + Matcher<Stmt> BoolValue = + constructMatcher("boolLiteral").getTypedMatcher<Stmt>(); 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<Decl> Value = constructMatcher<Decl>( - "namedDecl", - constructMatcher<NamedDecl>("hasName", std::string("X"), NULL), NULL); + Matcher<Decl> Value = constructMatcher( + "namedDecl", constructMatcher("hasName", std::string("X"))) + .getTypedMatcher<Decl>(); EXPECT_TRUE(matches("class X {};", Value)); EXPECT_FALSE(matches("int x;", Value)); - Value = - functionDecl(constructMatcher<FunctionDecl>("parameterCountIs", 2, NULL)); + Value = functionDecl(constructMatcher("parameterCountIs", 2) + .getTypedMatcher<FunctionDecl>()); 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); + Matcher<Decl> HasInitializerSimple = + constructMatcher("varDecl", constructMatcher("hasInitializer", stmt())) + .getTypedMatcher<Decl>(); + Matcher<Decl> HasInitializerComplex = constructMatcher( + "varDecl", constructMatcher("hasInitializer", callExpr())) + .getTypedMatcher<Decl>(); 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<Decl> HasParameter = functionDecl( - constructMatcher<FunctionDecl>("hasParameter", 1, hasName("x"), NULL)); + Matcher<Decl> HasParameter = functionDecl(constructMatcher( + "hasParameter", 1, hasName("x")).getTypedMatcher<FunctionDecl>()); 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<Decl> Var = constructMatcher<Decl>("varDecl", IsDefinition, NULL); + const MatcherList IsDefinition = constructMatcher("isDefinition"); + Matcher<Decl> Var = + constructMatcher("varDecl", IsDefinition).getTypedMatcher<Decl>(); Matcher<Decl> Class = - constructMatcher<Decl>("recordDecl", IsDefinition, NULL); + constructMatcher("recordDecl", IsDefinition).getTypedMatcher<Decl>(); Matcher<Decl> Func = - constructMatcher<Decl>("functionDecl", IsDefinition, NULL); + constructMatcher("functionDecl", IsDefinition).getTypedMatcher<Decl>(); 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<Decl> Anything = constructMatcher<Decl>("anything", NULL); + Matcher<Decl> Anything = constructMatcher("anything").getTypedMatcher<Decl>(); Matcher<Decl> RecordDecl = - constructMatcher<Decl>("recordDecl", Anything, NULL); + constructMatcher("recordDecl", Anything).getTypedMatcher<Decl>(); 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<Type> M = constructMatcher( + "pointerType", + constructMatcher("pointee", constructMatcher("isConstQualified"), + constructMatcher("isInteger"))).getTypedMatcher<Type>(); + EXPECT_FALSE(matches("int *a;", M)); + EXPECT_TRUE(matches("int const *b;", M)); + + M = constructMatcher( + "arrayType", + constructMatcher("hasElementType", constructMatcher("builtinType"))) + .getTypedMatcher<Type>(); + EXPECT_FALSE(matches("struct A{}; A a[7];;", M)); + EXPECT_TRUE(matches("int b[7];", M)); +} + TEST_F(RegistryTest, Errors) { // Incorrect argument count. OwningPtr<Diagnostics> 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<CXXRecordDecl>) != " "(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<CXXRecordDecl>) != " "(Actual = Matcher<FunctionDecl>)", Error->ToString()); -- GitLab