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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits