diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/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 class BindableMatcher : public Matcher { +public: + explicit BindableMatcher(const Matcher &M) : Matcher(M) {} + explicit BindableMatcher(MatcherInterface *Implementation) + : Matcher(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 bind(StringRef ID) const { + return DynTypedMatcher(*this) + .tryBind(ID) + ->template unconditionalConvertTo(); + } + + /// Same as Matcher's conversion operator, but enables binding on + /// the returned matcher. + operator DynTypedMatcher() const { + DynTypedMatcher Result = static_cast &>(*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 operator Matcher() const { + return DynTypedMatcher::trueMatcher(ASTNodeKind::getFromNodeKind()) + .template unconditionalConvertTo(); + } +}; + +/// Creates a Matcher that matches if all inner matchers match. +template +BindableMatcher +makeAllOfComposite(ArrayRef *> InnerMatchers) { + // For the size() == 0 case, we return a "true" matcher. + if (InnerMatchers.empty()) { + return BindableMatcher(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(*InnerMatchers[0]); + } + + using PI = llvm::pointee_iterator *const *>; + + std::vector DynMatchers(PI(InnerMatchers.begin()), + PI(InnerMatchers.end())); + return BindableMatcher( + DynTypedMatcher::constructVariadic(DynTypedMatcher::VO_AllOf, + ASTNodeKind::getFromNodeKind(), + std::move(DynMatchers)) + .template unconditionalConvertTo()); +} + +/// Creates a Matcher 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 +BindableMatcher +makeDynCastAllOfComposite(ArrayRef *> InnerMatchers) { + return BindableMatcher( + makeAllOfComposite(InnerMatchers).template dynCastTo()); +} + +/// A VariadicDynCastAllOfMatcher object is a +/// variadic functor that takes a number of Matcher and returns a +/// Matcher 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 record; +/// Creates a functor record(...) that creates a Matcher given +/// a variable number of arguments of type Matcher. +/// The returned matcher matches if the given Decl can by dynamically +/// casted to CXXRecordDecl and all given matchers match. +template +class VariadicDynCastAllOfMatcher + : public VariadicFunction, Matcher, + makeDynCastAllOfComposite> { +public: + VariadicDynCastAllOfMatcher() {} +}; + +/// A \c VariadicAllOfMatcher object is a variadic functor that takes +/// a number of \c Matcher and returns a \c Matcher that matches \c T +/// nodes that are matched by all of the given matchers. +/// +/// For example: +/// const VariadicAllOfMatcher nestedNameSpecifier; +/// Creates a functor nestedNameSpecifier(...) that creates a +/// \c Matcher given a variable number of arguments of type +/// \c Matcher. +/// The returned matcher matches if all given matchers match. +template +class VariadicAllOfMatcher + : public VariadicFunction, Matcher, + makeAllOfComposite> { +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 is generated on demand with an implicit +/// conversion operator. +template class VariadicOperatorMatcher { +public: + VariadicOperatorMatcher(DynTypedMatcher::VariadicOperator Op, Ps &&... Params) + : Op(Op), Params(std::forward(Params)...) {} + + template operator Matcher() const { + return DynTypedMatcher::constructVariadic( + Op, ASTNodeKind::getFromNodeKind(), + getMatchers(std::index_sequence_for())) + .template unconditionalConvertTo(); + } + +private: + // Helper method to unpack the tuple into a vector. + template + std::vector getMatchers(std::index_sequence) const { + return {Matcher(std::get(Params))...}; + } + + const DynTypedMatcher::VariadicOperator Op; + std::tuple Params; +}; + +/// Overloaded function object to generate VariadicOperatorMatcher +/// objects from arbitrary matchers. +template +struct VariadicOperatorMatcherFunc { + DynTypedMatcher::VariadicOperator Op; + + template + VariadicOperatorMatcher operator()(Ms &&... Ps) const { + static_assert(MinCount <= sizeof...(Ms) && sizeof...(Ms) <= MaxCount, + "invalid number of parameters for variadic matcher"); + return VariadicOperatorMatcher(Op, std::forward(Ps)...); + } +}; + +template +constexpr auto applyMatcherImpl(F &&f, Tuple &&args, + std::index_sequence) { + return std::forward(f)(std::get(std::forward(args))...); +} + +template +constexpr auto applyMatcher(F &&f, Tuple &&args) { + return applyMatcherImpl( + std::forward(f), std::forward(args), + std::make_index_sequence< + std::tuple_size::type>::value>()); +} + +template +struct GetCladeImpl { + using Type = Head; +}; +template +struct GetCladeImpl + : GetCladeImpl::value, + typename Tail::head, typename Tail::tail> {}; + +template +struct GetClade : GetCladeImpl {}; + +template +struct MapAnyOfMatcherImpl { + + template + BindableMatcher + operator()(InnerMatchers &&... InnerMatcher) const { + // TODO: Use std::apply from c++17 + return VariadicAllOfMatcher()(applyMatcher( + internal::VariadicOperatorMatcherFunc< + 0, std::numeric_limits::max()>{ + internal::DynTypedMatcher::VO_AnyOf}, + applyMatcher( + [&](auto... Matcher) { + return std::make_tuple(Matcher( + std::forward(InnerMatcher)...)...); + }, + std::tuple< + VariadicDynCastAllOfMatcher...>()))); + } +}; + +template +using MapAnyOfMatcher = + MapAnyOfMatcherImpl::Type, + MatcherTypes...>; + +template struct MapAnyOfHelper { + using CladeType = typename GetClade::Type; + + MapAnyOfMatcher with; + + operator BindableMatcher() const { return with(); } + + Matcher bind(StringRef ID) const { return with().bind(ID); } +}; + template