forked from OSchip/llvm-project
parent
7bc31332b8
commit
632aea92a5
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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")));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue