diff options
author | Manuel Klimek <klimek@google.com> | 2013-02-04 09:42:38 +0000 |
---|---|---|
committer | Manuel Klimek <klimek@google.com> | 2013-02-04 09:42:38 +0000 |
commit | 7387673f83b8b37f660422947c9990778ba88193 (patch) | |
tree | 898952d19423f3cd49a7d5579e6024bb485c63ec | |
parent | cda165056890b8ccfc6e2897c711388c5fb518c0 (diff) |
Add an eachOf matcher.
eachOf gives closure on the forEach and forEachDescendant matchers.
Before, it was impossible to implement a findAll matcher, as matching
the node or any of its descendants was not expressible (since anyOf
only triggers the first match).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@174315 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchers.h | 26 | ||||
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchersInternal.h | 41 | ||||
-rw-r--r-- | unittests/ASTMatchers/ASTMatchersTest.cpp | 24 |
3 files changed, 88 insertions, 3 deletions
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index 9dbd5d18d9..bd26d09b8b 100644 --- a/include/clang/ASTMatchers/ASTMatchers.h +++ b/include/clang/ASTMatchers/ASTMatchers.h @@ -1095,6 +1095,32 @@ const internal::VariadicDynCastAllOfMatcher<Type, Type> type; /// \brief Matches \c TypeLocs in the clang AST. const internal::VariadicDynCastAllOfMatcher<TypeLoc, TypeLoc> typeLoc; +/// \brief Matches if any of the given matchers matches. +/// +/// Unlike \c anyOf, \c eachOf will generate a match result for each +/// matching submatcher. +/// +/// For example, in: +/// \code +/// class A { int a; int b; }; +/// \endcode +/// The matcher: +/// \code +/// recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")), +/// has(fieldDecl(hasName("b")).bind("v")))) +/// \endcode +/// will generate two results binding "v", the first of which binds +/// the field declaration of \c a, the second the field declaration of +/// \c b. +/// +/// Usable as: Any Matcher +template <typename M1, typename M2> +internal::PolymorphicMatcherWithParam2<internal::EachOfMatcher, M1, M2> +eachOf(const M1 &P1, const M2 &P2) { + return internal::PolymorphicMatcherWithParam2<internal::EachOfMatcher, M1, + M2>(P1, P2); +} + /// \brief Various overloads for the anyOf matcher. /// @{ diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h index ac0e30e750..a6661f5d31 100644 --- a/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -832,21 +832,56 @@ private: /// used. They will always be instantiated with types convertible to /// Matcher<T>. template <typename T, typename MatcherT1, typename MatcherT2> +class EachOfMatcher : public MatcherInterface<T> { +public: + EachOfMatcher(const Matcher<T> &InnerMatcher1, + const Matcher<T> &InnerMatcher2) + : InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) { + } + + virtual bool matches(const T &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + BoundNodesTreeBuilder Builder1; + bool Matched1 = InnerMatcher1.matches(Node, Finder, &Builder1); + if (Matched1) + Builder->addMatch(Builder1.build()); + + BoundNodesTreeBuilder Builder2; + bool Matched2 = InnerMatcher2.matches(Node, Finder, &Builder2); + if (Matched2) + Builder->addMatch(Builder2.build()); + + return Matched1 || Matched2; + } + +private: + const Matcher<T> InnerMatcher1; + const Matcher<T> InnerMatcher2; +}; + +/// \brief Matches nodes of type T for which at least one of the two provided +/// matchers matches. +/// +/// Type arguments MatcherT1 and MatcherT2 are +/// required by PolymorphicMatcherWithParam2 but not actually +/// used. They will always be instantiated with types convertible to +/// Matcher<T>. +template <typename T, typename MatcherT1, typename MatcherT2> class AnyOfMatcher : public MatcherInterface<T> { public: AnyOfMatcher(const Matcher<T> &InnerMatcher1, const Matcher<T> &InnerMatcher2) - : InnerMatcher1(InnerMatcher1), InnertMatcher2(InnerMatcher2) {} + : InnerMatcher1(InnerMatcher1), InnerMatcher2(InnerMatcher2) {} virtual bool matches(const T &Node, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { return InnerMatcher1.matches(Node, Finder, Builder) || - InnertMatcher2.matches(Node, Finder, Builder); + InnerMatcher2.matches(Node, Finder, Builder); } private: const Matcher<T> InnerMatcher1; - const Matcher<T> InnertMatcher2; + const Matcher<T> InnerMatcher2; }; /// \brief Creates a Matcher<T> that matches if all inner matchers match. diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp index 670f0d4052..dc8b15fde1 100644 --- a/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/unittests/ASTMatchers/ASTMatchersTest.cpp @@ -2854,6 +2854,30 @@ TEST(ForEachDescendant, BindsCorrectNodes) { new VerifyIdIsBoundTo<FunctionDecl>("decl", 1))); } +TEST(EachOf, TriggersForEachMatch) { + EXPECT_TRUE(matchAndVerifyResultTrue( + "class A { int a; int b; };", + recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")), + has(fieldDecl(hasName("b")).bind("v")))), + new VerifyIdIsBoundTo<FieldDecl>("v", 2))); +} + +TEST(EachOf, BehavesLikeAnyOfUnlessBothMatch) { + EXPECT_TRUE(matchAndVerifyResultTrue( + "class A { int a; int c; };", + recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")), + has(fieldDecl(hasName("b")).bind("v")))), + new VerifyIdIsBoundTo<FieldDecl>("v", 1))); + EXPECT_TRUE(matchAndVerifyResultTrue( + "class A { int c; int b; };", + recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")), + has(fieldDecl(hasName("b")).bind("v")))), + new VerifyIdIsBoundTo<FieldDecl>("v", 1))); + EXPECT_TRUE(notMatches( + "class A { int c; int d; };", + recordDecl(eachOf(has(fieldDecl(hasName("a")).bind("v")), + has(fieldDecl(hasName("b")).bind("v")))))); +} TEST(IsTemplateInstantiation, MatchesImplicitClassTemplateInstantiation) { // Make sure that we can both match the class by name (::X) and by the type |