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
This commit is contained in:
Manuel Klimek 2013-02-04 09:42:38 +00:00
Родитель cda1650568
Коммит 7387673f83
3 изменённых файлов: 88 добавлений и 3 удалений

Просмотреть файл

@ -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.
/// @{

Просмотреть файл

@ -824,6 +824,41 @@ private:
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 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.
///
@ -835,18 +870,18 @@ 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.

Просмотреть файл

@ -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