From 632aea92a57b5611cf54fc159cc3f77547a24ff7 Mon Sep 17 00:00:00 2001 From: Daniel Jasper Date: Mon, 22 Oct 2012 16:26:51 +0000 Subject: [PATCH] Implement hasParent()-matcher. llvm-svn: 166421 --- clang/include/clang/ASTMatchers/ASTMatchers.h | 18 ++++++++++ .../clang/ASTMatchers/ASTMatchersInternal.h | 41 +++++++++++++++++++--- clang/lib/ASTMatchers/ASTMatchFinder.cpp | 9 +++-- clang/unittests/ASTMatchers/ASTMatchersTest.cpp | 12 +++++++ 4 files changed, 73 insertions(+), 7 deletions(-) diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 384b01f..712b324 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/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 +internal::ArgumentAdaptingMatcher +hasParent(const internal::Matcher &ParentMatcher) { + return internal::ArgumentAdaptingMatcher< + internal::HasParentMatcher, + ParentT>(ParentMatcher); +} + /// \brief Matches AST nodes that have an ancestor that matches the provided /// matcher. /// diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h index da6ce18..c675a3b 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/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 bool matchesAncestorOf(const T &Node, const DynTypedMatcher &Matcher, - BoundNodesTreeBuilder *Builder) { + BoundNodesTreeBuilder *Builder, + AncestorMatchMode MatchMode) { TOOLING_COMPILE_ASSERT((llvm::is_base_of::value || llvm::is_base_of::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 to a matcher of desired type \c To by @@ -864,6 +874,29 @@ public: const Matcher 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 +class HasParentMatcher : public MatcherInterface { + TOOLING_COMPILE_ASSERT(IsBaseType::value, + has_parent_only_accepts_base_type_matcher); +public: + explicit HasParentMatcher(const Matcher &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 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/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp index ebbadc4..c0d97df 100644 --- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -352,7 +352,7 @@ public: const Matcher &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/clang/unittests/ASTMatchers/ASTMatchersTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp index 9676fde..5c97f3a 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/clang/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"))); } -- 2.7.4