Implement hasParent()-matcher.

llvm-svn: 166421
This commit is contained in:
Daniel Jasper 2012-10-22 16:26:51 +00:00
parent 7bc31332b8
commit 632aea92a5
4 changed files with 73 additions and 7 deletions

View File

@ -1402,6 +1402,24 @@ forEachDescendant(
DescendantT>(DescendantMatcher);
}
/// \brief Matches AST nodes that have a parent that matches the provided
/// matcher.
///
/// Given
/// \code
/// void f() { for (;;) { int x = 42; if (true) { int x = 43; } } }
/// \endcode
/// \c compoundStmt(hasParent(ifStmt())) matches "{ int x = 43; }".
///
/// Usable as: Any Matcher
template <typename ParentT>
internal::ArgumentAdaptingMatcher<internal::HasParentMatcher, ParentT>
hasParent(const internal::Matcher<ParentT> &ParentMatcher) {
return internal::ArgumentAdaptingMatcher<
internal::HasParentMatcher,
ParentT>(ParentMatcher);
}
/// \brief Matches AST nodes that have an ancestor that matches the provided
/// matcher.
///

View File

@ -460,6 +460,14 @@ public:
BK_All
};
/// \brief Defines which ancestors are considered for a match.
enum AncestorMatchMode {
/// All ancestors.
AMM_All,
/// Direct parent only.
AMM_ParentOnly
};
virtual ~ASTMatchFinder() {}
/// \brief Returns true if the given class is directly or indirectly derived
@ -499,12 +507,13 @@ public:
template <typename T>
bool matchesAncestorOf(const T &Node,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder) {
BoundNodesTreeBuilder *Builder,
AncestorMatchMode MatchMode) {
TOOLING_COMPILE_ASSERT((llvm::is_base_of<Decl, T>::value ||
llvm::is_base_of<Stmt, T>::value),
only_Decl_or_Stmt_allowed_for_recursive_matching);
return matchesAncestorOf(ast_type_traits::DynTypedNode::create(Node),
Matcher, Builder);
Matcher, Builder, MatchMode);
}
protected:
@ -521,7 +530,8 @@ protected:
virtual bool matchesAncestorOf(const ast_type_traits::DynTypedNode &Node,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder) = 0;
BoundNodesTreeBuilder *Builder,
AncestorMatchMode MatchMode) = 0;
};
/// \brief Converts a \c Matcher<T> to a matcher of desired type \c To by
@ -864,6 +874,29 @@ public:
const Matcher<DescendantT> DescendantMatcher;
};
/// \brief Matches nodes of type \c T that have a parent node of type \c ParentT
/// for which the given inner matcher matches.
///
/// \c ParentT must be an AST base type.
template <typename T, typename ParentT>
class HasParentMatcher : public MatcherInterface<T> {
TOOLING_COMPILE_ASSERT(IsBaseType<ParentT>::value,
has_parent_only_accepts_base_type_matcher);
public:
explicit HasParentMatcher(const Matcher<ParentT> &ParentMatcher)
: ParentMatcher(ParentMatcher) {}
virtual bool matches(const T &Node,
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
return Finder->matchesAncestorOf(
Node, ParentMatcher, Builder, ASTMatchFinder::AMM_ParentOnly);
}
private:
const Matcher<ParentT> ParentMatcher;
};
/// \brief Matches nodes of type \c T that have at least one ancestor node of
/// type \c AncestorT for which the given inner matcher matches.
///
@ -880,7 +913,7 @@ public:
ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
return Finder->matchesAncestorOf(
Node, AncestorMatcher, Builder);
Node, AncestorMatcher, Builder, ASTMatchFinder::AMM_All);
}
private:

View File

@ -352,7 +352,7 @@ public:
const Matcher<NamedDecl> &Base,
BoundNodesTreeBuilder *Builder);
// Implements ASTMatchFinder::MatchesChildOf.
// Implements ASTMatchFinder::matchesChildOf.
virtual bool matchesChildOf(const ast_type_traits::DynTypedNode &Node,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
@ -361,7 +361,7 @@ public:
return matchesRecursively(Node, Matcher, Builder, 1, Traversal,
Bind);
}
// Implements ASTMatchFinder::MatchesDescendantOf.
// Implements ASTMatchFinder::matchesDescendantOf.
virtual bool matchesDescendantOf(const ast_type_traits::DynTypedNode &Node,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder,
@ -372,7 +372,8 @@ public:
// Implements ASTMatchFinder::matchesAncestorOf.
virtual bool matchesAncestorOf(const ast_type_traits::DynTypedNode &Node,
const DynTypedMatcher &Matcher,
BoundNodesTreeBuilder *Builder) {
BoundNodesTreeBuilder *Builder,
AncestorMatchMode MatchMode) {
if (!Parents) {
// We always need to run over the whole translation unit, as
// \c hasAncestor can escape any subtree.
@ -395,6 +396,8 @@ public:
Ancestor = I->second;
if (Matcher.matches(Ancestor, this, Builder))
return true;
if (MatchMode == ASTMatchFinder::AMM_ParentOnly)
return false;
}
return false;
}

View File

@ -2884,6 +2884,18 @@ TEST(HasAncestor, MatchesInImplicitCode) {
hasAncestor(recordDecl(hasName("A")))))))));
}
TEST(HasParent, MatchesOnlyParent) {
EXPECT_TRUE(matches(
"void f() { if (true) { int x = 42; } }",
compoundStmt(hasParent(ifStmt()))));
EXPECT_TRUE(notMatches(
"void f() { for (;;) { int x = 42; } }",
compoundStmt(hasParent(ifStmt()))));
EXPECT_TRUE(notMatches(
"void f() { if (true) for (;;) { int x = 42; } }",
compoundStmt(hasParent(ifStmt()))));
}
TEST(TypeMatching, MatchesTypes) {
EXPECT_TRUE(matches("struct S {};", qualType().bind("loc")));
}