diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/include/clang/ASTMatchers/ASTMatchers.h | 18 | ||||
| -rw-r--r-- | clang/include/clang/ASTMatchers/ASTMatchersInternal.h | 41 | ||||
| -rw-r--r-- | clang/lib/ASTMatchers/ASTMatchFinder.cpp | 9 | ||||
| -rw-r--r-- | 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 384b01f2e94..712b324d754 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 <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/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h index da6ce18b42d..c675a3bccaa 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 <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/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp index ebbadc424d4..c0d97df0758 100644 --- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/clang/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/clang/unittests/ASTMatchers/ASTMatchersTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp index 9676fde96b8..5c97f3abacd 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")));  }  | 

