steveire created this revision. steveire added a reviewer: aaron.ballman. steveire requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
Add an operator overload to ArgumentAdaptingMatcherFunc to allow use of mapAnyOf within hasAncestor, hasParent etc. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D94864 Files: clang/include/clang/ASTMatchers/ASTMatchersInternal.h clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
Index: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -491,6 +491,14 @@ Code, traverse(TK_IgnoreUnlessSpelledInSource, mapAnyOf(ifStmt, forStmt).with(hasCondition(falseExpr))))); + EXPECT_TRUE( + matches(Code, cxxBoolLiteral(equals(true), + hasAncestor(mapAnyOf(ifStmt, forStmt))))); + + EXPECT_TRUE( + matches(Code, cxxBoolLiteral(equals(false), + hasAncestor(mapAnyOf(ifStmt, forStmt))))); + Code = R"cpp( void func(bool b) {} struct S { Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -1171,6 +1171,232 @@ TemplateSpecializationType, TemplateTypeParmType, TypedefType, UnresolvedUsingType, ObjCIvarRefExpr>; +/// A Matcher that allows binding the node it matches to an id. +/// +/// BindableMatcher provides a \a bind() method that allows binding the +/// matched node to an id if the match was successful. +template <typename T> class BindableMatcher : public Matcher<T> { +public: + explicit BindableMatcher(const Matcher<T> &M) : Matcher<T>(M) {} + explicit BindableMatcher(MatcherInterface<T> *Implementation) + : Matcher<T>(Implementation) {} + + /// Returns a matcher that will bind the matched node on a match. + /// + /// The returned matcher is equivalent to this matcher, but will + /// bind the matched node on a match. + Matcher<T> bind(StringRef ID) const { + return DynTypedMatcher(*this) + .tryBind(ID) + ->template unconditionalConvertTo<T>(); + } + + /// Same as Matcher<T>'s conversion operator, but enables binding on + /// the returned matcher. + operator DynTypedMatcher() const { + DynTypedMatcher Result = static_cast<const Matcher<T> &>(*this); + Result.setAllowBind(true); + return Result; + } +}; + +/// Matches any instance of the given NodeType. +/// +/// This is useful when a matcher syntactically requires a child matcher, +/// but the context doesn't care. See for example: anything(). +class TrueMatcher { +public: + using ReturnTypes = AllNodeBaseTypes; + + template <typename T> operator Matcher<T>() const { + return DynTypedMatcher::trueMatcher(ASTNodeKind::getFromNodeKind<T>()) + .template unconditionalConvertTo<T>(); + } +}; + +/// Creates a Matcher<T> that matches if all inner matchers match. +template <typename T> +BindableMatcher<T> +makeAllOfComposite(ArrayRef<const Matcher<T> *> InnerMatchers) { + // For the size() == 0 case, we return a "true" matcher. + if (InnerMatchers.empty()) { + return BindableMatcher<T>(TrueMatcher()); + } + // For the size() == 1 case, we simply return that one matcher. + // No need to wrap it in a variadic operation. + if (InnerMatchers.size() == 1) { + return BindableMatcher<T>(*InnerMatchers[0]); + } + + using PI = llvm::pointee_iterator<const Matcher<T> *const *>; + + std::vector<DynTypedMatcher> DynMatchers(PI(InnerMatchers.begin()), + PI(InnerMatchers.end())); + return BindableMatcher<T>( + DynTypedMatcher::constructVariadic(DynTypedMatcher::VO_AllOf, + ASTNodeKind::getFromNodeKind<T>(), + std::move(DynMatchers)) + .template unconditionalConvertTo<T>()); +} + +/// Creates a Matcher<T> that matches if +/// T is dyn_cast'able into InnerT and all inner matchers match. +/// +/// Returns BindableMatcher, as matchers that use dyn_cast have +/// the same object both to match on and to run submatchers on, +/// so there is no ambiguity with what gets bound. +template <typename T, typename InnerT> +BindableMatcher<T> +makeDynCastAllOfComposite(ArrayRef<const Matcher<InnerT> *> InnerMatchers) { + return BindableMatcher<T>( + makeAllOfComposite(InnerMatchers).template dynCastTo<T>()); +} + +/// A VariadicDynCastAllOfMatcher<SourceT, TargetT> object is a +/// variadic functor that takes a number of Matcher<TargetT> and returns a +/// Matcher<SourceT> that matches TargetT nodes that are matched by all of the +/// given matchers, if SourceT can be dynamically casted into TargetT. +/// +/// For example: +/// const VariadicDynCastAllOfMatcher<Decl, CXXRecordDecl> record; +/// Creates a functor record(...) that creates a Matcher<Decl> given +/// a variable number of arguments of type Matcher<CXXRecordDecl>. +/// The returned matcher matches if the given Decl can by dynamically +/// casted to CXXRecordDecl and all given matchers match. +template <typename SourceT, typename TargetT> +class VariadicDynCastAllOfMatcher + : public VariadicFunction<BindableMatcher<SourceT>, Matcher<TargetT>, + makeDynCastAllOfComposite<SourceT, TargetT>> { +public: + VariadicDynCastAllOfMatcher() {} +}; + +/// A \c VariadicAllOfMatcher<T> object is a variadic functor that takes +/// a number of \c Matcher<T> and returns a \c Matcher<T> that matches \c T +/// nodes that are matched by all of the given matchers. +/// +/// For example: +/// const VariadicAllOfMatcher<NestedNameSpecifier> nestedNameSpecifier; +/// Creates a functor nestedNameSpecifier(...) that creates a +/// \c Matcher<NestedNameSpecifier> given a variable number of arguments of type +/// \c Matcher<NestedNameSpecifier>. +/// The returned matcher matches if all given matchers match. +template <typename T> +class VariadicAllOfMatcher + : public VariadicFunction<BindableMatcher<T>, Matcher<T>, + makeAllOfComposite<T>> { +public: + VariadicAllOfMatcher() {} +}; + +/// VariadicOperatorMatcher related types. +/// @{ + +/// Polymorphic matcher object that uses a \c +/// DynTypedMatcher::VariadicOperator operator. +/// +/// Input matchers can have any type (including other polymorphic matcher +/// types), and the actual Matcher<T> is generated on demand with an implicit +/// conversion operator. +template <typename... Ps> class VariadicOperatorMatcher { +public: + VariadicOperatorMatcher(DynTypedMatcher::VariadicOperator Op, Ps &&... Params) + : Op(Op), Params(std::forward<Ps>(Params)...) {} + + template <typename T> operator Matcher<T>() const { + return DynTypedMatcher::constructVariadic( + Op, ASTNodeKind::getFromNodeKind<T>(), + getMatchers<T>(std::index_sequence_for<Ps...>())) + .template unconditionalConvertTo<T>(); + } + +private: + // Helper method to unpack the tuple into a vector. + template <typename T, std::size_t... Is> + std::vector<DynTypedMatcher> getMatchers(std::index_sequence<Is...>) const { + return {Matcher<T>(std::get<Is>(Params))...}; + } + + const DynTypedMatcher::VariadicOperator Op; + std::tuple<Ps...> Params; +}; + +/// Overloaded function object to generate VariadicOperatorMatcher +/// objects from arbitrary matchers. +template <unsigned MinCount, unsigned MaxCount> +struct VariadicOperatorMatcherFunc { + DynTypedMatcher::VariadicOperator Op; + + template <typename... Ms> + VariadicOperatorMatcher<Ms...> operator()(Ms &&... Ps) const { + static_assert(MinCount <= sizeof...(Ms) && sizeof...(Ms) <= MaxCount, + "invalid number of parameters for variadic matcher"); + return VariadicOperatorMatcher<Ms...>(Op, std::forward<Ms>(Ps)...); + } +}; + +template <typename F, typename Tuple, std::size_t... I> +constexpr auto applyMatcherImpl(F &&f, Tuple &&args, + std::index_sequence<I...>) { + return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(args))...); +} + +template <typename F, typename Tuple> +constexpr auto applyMatcher(F &&f, Tuple &&args) { + return applyMatcherImpl( + std::forward<F>(f), std::forward<Tuple>(args), + std::make_index_sequence< + std::tuple_size<typename std::decay<Tuple>::type>::value>()); +} + +template <typename T, bool IsBaseOf, typename Head, typename Tail> +struct GetCladeImpl { + using Type = Head; +}; +template <typename T, typename Head, typename Tail> +struct GetCladeImpl<T, false, Head, Tail> + : GetCladeImpl<T, std::is_base_of<typename Tail::head, T>::value, + typename Tail::head, typename Tail::tail> {}; + +template <typename T, typename... U> +struct GetClade : GetCladeImpl<T, false, T, AllNodeBaseTypes> {}; + +template <typename CladeType, typename... MatcherTypes> +struct MapAnyOfMatcherImpl { + + template <typename... InnerMatchers> + BindableMatcher<CladeType> + operator()(InnerMatchers &&... InnerMatcher) const { + // TODO: Use std::apply from c++17 + return VariadicAllOfMatcher<CladeType>()(applyMatcher( + internal::VariadicOperatorMatcherFunc< + 0, std::numeric_limits<unsigned>::max()>{ + internal::DynTypedMatcher::VO_AnyOf}, + applyMatcher( + [&](auto... Matcher) { + return std::make_tuple(Matcher( + std::forward<decltype(InnerMatcher)>(InnerMatcher)...)...); + }, + std::tuple< + VariadicDynCastAllOfMatcher<CladeType, MatcherTypes>...>()))); + } +}; + +template <typename... MatcherTypes> +using MapAnyOfMatcher = + MapAnyOfMatcherImpl<typename GetClade<MatcherTypes...>::Type, + MatcherTypes...>; + +template <typename... MatcherTypes> struct MapAnyOfHelper { + using CladeType = typename GetClade<MatcherTypes...>::Type; + + MapAnyOfMatcher<MatcherTypes...> with; + + operator BindableMatcher<CladeType>() const { return with(); } + + Matcher<CladeType> bind(StringRef ID) const { return with().bind(ID); } +}; + template <template <typename ToArg, typename FromArg> class ArgumentAdapterT, typename T, typename ToTypes> class ArgumentAdaptingMatcherFuncAdaptor { @@ -1217,6 +1443,13 @@ operator()(const Matcher<T> &InnerMatcher) const { return create(InnerMatcher); } + + template <typename... T> + ArgumentAdaptingMatcherFuncAdaptor<ArgumentAdapterT, + typename GetClade<T...>::Type, ToTypes> + operator()(const MapAnyOfHelper<T...> &InnerMatcher) const { + return create(InnerMatcher.with()); + } }; template <typename T> class TraversalMatcher : public MatcherInterface<T> { @@ -1327,51 +1560,6 @@ const P2 Param2; }; -/// Matches any instance of the given NodeType. -/// -/// This is useful when a matcher syntactically requires a child matcher, -/// but the context doesn't care. See for example: anything(). -class TrueMatcher { -public: - using ReturnTypes = AllNodeBaseTypes; - - template <typename T> - operator Matcher<T>() const { - return DynTypedMatcher::trueMatcher(ASTNodeKind::getFromNodeKind<T>()) - .template unconditionalConvertTo<T>(); - } -}; - -/// A Matcher that allows binding the node it matches to an id. -/// -/// BindableMatcher provides a \a bind() method that allows binding the -/// matched node to an id if the match was successful. -template <typename T> -class BindableMatcher : public Matcher<T> { -public: - explicit BindableMatcher(const Matcher<T> &M) : Matcher<T>(M) {} - explicit BindableMatcher(MatcherInterface<T> *Implementation) - : Matcher<T>(Implementation) {} - - /// Returns a matcher that will bind the matched node on a match. - /// - /// The returned matcher is equivalent to this matcher, but will - /// bind the matched node on a match. - Matcher<T> bind(StringRef ID) const { - return DynTypedMatcher(*this) - .tryBind(ID) - ->template unconditionalConvertTo<T>(); - } - - /// Same as Matcher<T>'s conversion operator, but enables binding on - /// the returned matcher. - operator DynTypedMatcher() const { - DynTypedMatcher Result = static_cast<const Matcher<T>&>(*this); - Result.setAllowBind(true); - return Result; - } -}; - /// Matches nodes of type T that have child nodes of type ChildT for /// which a specified child matcher matches. /// @@ -1415,52 +1603,6 @@ } }; -/// VariadicOperatorMatcher related types. -/// @{ - -/// Polymorphic matcher object that uses a \c -/// DynTypedMatcher::VariadicOperator operator. -/// -/// Input matchers can have any type (including other polymorphic matcher -/// types), and the actual Matcher<T> is generated on demand with an implicit -/// conversion operator. -template <typename... Ps> class VariadicOperatorMatcher { -public: - VariadicOperatorMatcher(DynTypedMatcher::VariadicOperator Op, Ps &&... Params) - : Op(Op), Params(std::forward<Ps>(Params)...) {} - - template <typename T> operator Matcher<T>() const { - return DynTypedMatcher::constructVariadic( - Op, ASTNodeKind::getFromNodeKind<T>(), - getMatchers<T>(std::index_sequence_for<Ps...>())) - .template unconditionalConvertTo<T>(); - } - -private: - // Helper method to unpack the tuple into a vector. - template <typename T, std::size_t... Is> - std::vector<DynTypedMatcher> getMatchers(std::index_sequence<Is...>) const { - return {Matcher<T>(std::get<Is>(Params))...}; - } - - const DynTypedMatcher::VariadicOperator Op; - std::tuple<Ps...> Params; -}; - -/// Overloaded function object to generate VariadicOperatorMatcher -/// objects from arbitrary matchers. -template <unsigned MinCount, unsigned MaxCount> -struct VariadicOperatorMatcherFunc { - DynTypedMatcher::VariadicOperator Op; - - template <typename... Ms> - VariadicOperatorMatcher<Ms...> operator()(Ms &&... Ps) const { - static_assert(MinCount <= sizeof...(Ms) && sizeof...(Ms) <= MaxCount, - "invalid number of parameters for variadic matcher"); - return VariadicOperatorMatcher<Ms...>(Op, std::forward<Ms>(Ps)...); - } -}; - /// @} template <typename T> @@ -1468,44 +1610,6 @@ return Matcher<T>(*this); } -/// Creates a Matcher<T> that matches if all inner matchers match. -template<typename T> -BindableMatcher<T> makeAllOfComposite( - ArrayRef<const Matcher<T> *> InnerMatchers) { - // For the size() == 0 case, we return a "true" matcher. - if (InnerMatchers.empty()) { - return BindableMatcher<T>(TrueMatcher()); - } - // For the size() == 1 case, we simply return that one matcher. - // No need to wrap it in a variadic operation. - if (InnerMatchers.size() == 1) { - return BindableMatcher<T>(*InnerMatchers[0]); - } - - using PI = llvm::pointee_iterator<const Matcher<T> *const *>; - - std::vector<DynTypedMatcher> DynMatchers(PI(InnerMatchers.begin()), - PI(InnerMatchers.end())); - return BindableMatcher<T>( - DynTypedMatcher::constructVariadic(DynTypedMatcher::VO_AllOf, - ASTNodeKind::getFromNodeKind<T>(), - std::move(DynMatchers)) - .template unconditionalConvertTo<T>()); -} - -/// Creates a Matcher<T> that matches if -/// T is dyn_cast'able into InnerT and all inner matchers match. -/// -/// Returns BindableMatcher, as matchers that use dyn_cast have -/// the same object both to match on and to run submatchers on, -/// so there is no ambiguity with what gets bound. -template<typename T, typename InnerT> -BindableMatcher<T> makeDynCastAllOfComposite( - ArrayRef<const Matcher<InnerT> *> InnerMatchers) { - return BindableMatcher<T>( - makeAllOfComposite(InnerMatchers).template dynCastTo<T>()); -} - /// Matches nodes of type T that have at least one descendant node of /// type DescendantT for which the given inner matcher matches. /// @@ -1645,43 +1749,6 @@ return ExpectedValue.compare(Node.getValue()) == llvm::APFloat::cmpEqual; } -/// A VariadicDynCastAllOfMatcher<SourceT, TargetT> object is a -/// variadic functor that takes a number of Matcher<TargetT> and returns a -/// Matcher<SourceT> that matches TargetT nodes that are matched by all of the -/// given matchers, if SourceT can be dynamically casted into TargetT. -/// -/// For example: -/// const VariadicDynCastAllOfMatcher<Decl, CXXRecordDecl> record; -/// Creates a functor record(...) that creates a Matcher<Decl> given -/// a variable number of arguments of type Matcher<CXXRecordDecl>. -/// The returned matcher matches if the given Decl can by dynamically -/// casted to CXXRecordDecl and all given matchers match. -template <typename SourceT, typename TargetT> -class VariadicDynCastAllOfMatcher - : public VariadicFunction<BindableMatcher<SourceT>, Matcher<TargetT>, - makeDynCastAllOfComposite<SourceT, TargetT>> { -public: - VariadicDynCastAllOfMatcher() {} -}; - -/// A \c VariadicAllOfMatcher<T> object is a variadic functor that takes -/// a number of \c Matcher<T> and returns a \c Matcher<T> that matches \c T -/// nodes that are matched by all of the given matchers. -/// -/// For example: -/// const VariadicAllOfMatcher<NestedNameSpecifier> nestedNameSpecifier; -/// Creates a functor nestedNameSpecifier(...) that creates a -/// \c Matcher<NestedNameSpecifier> given a variable number of arguments of type -/// \c Matcher<NestedNameSpecifier>. -/// The returned matcher matches if all given matchers match. -template <typename T> -class VariadicAllOfMatcher - : public VariadicFunction<BindableMatcher<T>, Matcher<T>, - makeAllOfComposite<T>> { -public: - VariadicAllOfMatcher() {} -}; - /// Matches nodes of type \c TLoc for which the inner /// \c Matcher<T> matches. template <typename TLoc, typename T> @@ -2180,68 +2247,6 @@ llvm::Regex::RegexFlags Flags, StringRef MatcherID); -template <typename F, typename Tuple, std::size_t... I> -constexpr auto applyMatcherImpl(F &&f, Tuple &&args, - std::index_sequence<I...>) { - return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(args))...); -} - -template <typename F, typename Tuple> -constexpr auto applyMatcher(F &&f, Tuple &&args) { - return applyMatcherImpl( - std::forward<F>(f), std::forward<Tuple>(args), - std::make_index_sequence< - std::tuple_size<typename std::decay<Tuple>::type>::value>()); -} - -template <typename T, bool IsBaseOf, typename Head, typename Tail> -struct GetCladeImpl { - using Type = Head; -}; -template <typename T, typename Head, typename Tail> -struct GetCladeImpl<T, false, Head, Tail> - : GetCladeImpl<T, std::is_base_of<typename Tail::head, T>::value, - typename Tail::head, typename Tail::tail> {}; - -template <typename T, typename... U> -struct GetClade : GetCladeImpl<T, false, T, AllNodeBaseTypes> {}; - -template <typename CladeType, typename... MatcherTypes> -struct MapAnyOfMatcherImpl { - - template <typename... InnerMatchers> - BindableMatcher<CladeType> - operator()(InnerMatchers &&... InnerMatcher) const { - // TODO: Use std::apply from c++17 - return VariadicAllOfMatcher<CladeType>()(applyMatcher( - internal::VariadicOperatorMatcherFunc< - 0, std::numeric_limits<unsigned>::max()>{ - internal::DynTypedMatcher::VO_AnyOf}, - applyMatcher( - [&](auto... Matcher) { - return std::make_tuple(Matcher( - std::forward<decltype(InnerMatcher)>(InnerMatcher)...)...); - }, - std::tuple< - VariadicDynCastAllOfMatcher<CladeType, MatcherTypes>...>()))); - } -}; - -template <typename... MatcherTypes> -using MapAnyOfMatcher = - MapAnyOfMatcherImpl<typename GetClade<MatcherTypes...>::Type, - MatcherTypes...>; - -template <typename... MatcherTypes> struct MapAnyOfHelper { - using CladeType = typename GetClade<MatcherTypes...>::Type; - - MapAnyOfMatcher<MatcherTypes...> with; - - operator BindableMatcher<CladeType>() const { return with(); } - - Matcher<CladeType> bind(StringRef ID) const { return with().bind(ID); } -}; - } // namespace internal } // namespace ast_matchers
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits