aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Jasper <djasper@google.com>2012-10-22 16:26:51 +0000
committerDaniel Jasper <djasper@google.com>2012-10-22 16:26:51 +0000
commitc99a3ad8c2bf29da45a0c64b88d58bfbd2f78ef2 (patch)
tree46666ad15f3d32214b14a00619023b24cb63ad6e
parent03e6fda61f48a6f11fb3c9459d5ac3d5b1db2809 (diff)
Implement hasParent()-matcher.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166421 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/ASTMatchers/ASTMatchers.h18
-rw-r--r--include/clang/ASTMatchers/ASTMatchersInternal.h41
-rw-r--r--lib/ASTMatchers/ASTMatchFinder.cpp9
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.cpp12
4 files changed, 73 insertions, 7 deletions
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index 384b01f2e9..712b324d75 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -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.
///
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
index da6ce18b42..c675a3bcca 100644
--- a/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -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:
diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp
index ebbadc424d..c0d97df075 100644
--- a/lib/ASTMatchers/ASTMatchFinder.cpp
+++ b/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -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;
}
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index 9676fde96b..5c97f3abac 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -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")));
}