зеркало из https://github.com/microsoft/clang-1.git
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
This commit is contained in:
Родитель
cda1650568
Коммит
7387673f83
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче