ymandel updated this revision to Diff 294348. ymandel added a comment. Fixed to use more standard type adaptors. Registration now works.
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D88275/new/ https://reviews.llvm.org/D88275 Files: clang/docs/LibASTMatchersReference.html clang/include/clang/ASTMatchers/ASTMatchers.h clang/include/clang/ASTMatchers/ASTMatchersInternal.h clang/lib/ASTMatchers/ASTMatchFinder.cpp clang/lib/ASTMatchers/Dynamic/Registry.cpp clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -3190,6 +3190,26 @@ compoundStmt(hasParent(recordDecl())))); } +TEST(HasParentIgnoringImplicit, MatchesExplicitParents) { + std::string Input = R"cc( + float f() { + int x = 3; + int y = 3.0; + return y; + } + )cc"; + EXPECT_TRUE( + matches(Input, declRefExpr(hasParentIgnoringImplicit(returnStmt())))); + EXPECT_TRUE( + matches(Input, floatLiteral(hasParentIgnoringImplicit(varDecl())))); + EXPECT_TRUE( + matches(Input, integerLiteral(hasParentIgnoringImplicit(varDecl())))); + + // Make sure it only ignores implicit ancestors. + EXPECT_TRUE( + notMatches(Input, integerLiteral(hasParentIgnoringImplicit(declStmt())))); +} + TEST(HasParent, NoDuplicateParents) { class HasDuplicateParents : public BoundNodesCallback { public: Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp =================================================================== --- clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -311,6 +311,7 @@ REGISTER_MATCHER(hasOverloadedOperatorName); REGISTER_MATCHER(hasParameter); REGISTER_MATCHER(hasParent); + REGISTER_MATCHER(hasParentIgnoringImplicit); REGISTER_MATCHER(hasQualifier); REGISTER_MATCHER(hasRHS); REGISTER_MATCHER(hasRangeInit); Index: clang/lib/ASTMatchers/ASTMatchFinder.cpp =================================================================== --- clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -544,9 +544,14 @@ // don't invalidate any iterators. if (ResultCache.size() > MaxMemoizationEntries) ResultCache.clear(); - if (MatchMode == AncestorMatchMode::AMM_ParentOnly) + switch (MatchMode) { + case AncestorMatchMode::AMM_ParentOnly: return matchesParentOf(Node, Matcher, Builder); - return matchesAnyAncestorOf(Node, Ctx, Matcher, Builder); + case AncestorMatchMode::AMM_FirstExplicitOnly: + return matchesFirstExplicitAncestorOf(Node, Matcher, Builder); + case AncestorMatchMode::AMM_All: + return matchesAnyAncestorOf(Node, Ctx, Matcher, Builder); + } } // Matches all registered matchers on the given node and calls the @@ -714,6 +719,33 @@ return false; } + // Returns whether the first explicit (`Expr`) ancestor of \p Node matches \p + // Matcher. That is, like matchesParentOf but skipping implicit parents. + // Unlike matchesAnyAncestorOf there's no memoization: it doesn't save much. + bool matchesFirstExplicitAncestorOf(const DynTypedNode &Node, + const DynTypedMatcher &Matcher, + BoundNodesTreeBuilder *Builder) { + for (const auto &Parent : ActiveASTContext->getParents(Node)) { + if (const auto *E = Parent.get<clang::Expr>()) + // If the parent is an implicit node, match on *its* parents + // instead. Use DFS, since we expect that expressions are relatively + // shallow. + if (clang::isa<ImplicitCastExpr>(E) || clang::isa<FullExpr>(E) || + clang::isa<MaterializeTemporaryExpr>(E) || + clang::isa<CXXBindTemporaryExpr>(E)) { + if (matchesFirstExplicitAncestorOf(Parent, Matcher, Builder)) + return true; + continue; + } + BoundNodesTreeBuilder BuilderCopy = *Builder; + if (Matcher.matches(Parent, this, &BuilderCopy)) { + *Builder = std::move(BuilderCopy); + return true; + } + } + return false; + } + // Returns whether an ancestor of \p Node matches \p Matcher. // // The order of matching (which can lead to different nodes being bound in Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -985,7 +985,11 @@ AMM_All, /// Direct parent only. - AMM_ParentOnly + AMM_ParentOnly, + + /// Considers the first non-implicit `Expr` ancestor. Intuitively, like + /// `ignoringImplicit` for matching parents. + AMM_FirstExplicitOnly }; virtual ~ASTMatchFinder() = default; @@ -1515,6 +1519,33 @@ } }; +/// Matches \c Stmt nodes that have an ancestor note that is separated from +/// `Node` only by implicit expression nodes and matches `ParentMatcher`. We +/// limit to \c Stmt because implicit expressions only ever contain statements +/// (expressions, in particular). +/// +/// \c ParentT must be an AST base type. +template <typename T, typename ParentT> +class HasParentIgnoringImplicitMatcher : public MatcherInterface<T> { + static_assert(IsBaseType<ParentT>::value, + "has-parent-ignoring-implicit only accepts base type matcher"); + static_assert(std::is_base_of<Stmt, T>::value, + "has-parent-ignoring-implict only matches statements"); + + const DynTypedMatcher ParentMatcher; + +public: + explicit HasParentIgnoringImplicitMatcher( + const Matcher<ParentT> &ParentMatcher) + : ParentMatcher(ParentMatcher) {} + + bool matches(const T &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + return Finder->matchesAncestorOf(Node, this->ParentMatcher, Builder, + ASTMatchFinder::AMM_FirstExplicitOnly); + } +}; + /// Matches nodes of type \c T that have at least one ancestor node of /// type \c AncestorT for which the given inner matcher matches. /// Index: clang/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchers.h +++ clang/include/clang/ASTMatchers/ASTMatchers.h @@ -3176,6 +3176,23 @@ internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>> hasParent; +/// Matches \c Stmt nodes that have an ancestor, reachable only through +/// implicit-expression nodes, that matches the provided matcher. +/// +/// Given +/// \code +/// float f() { return 3; } +/// \endcode +/// \c integerLiteral(hasParentIgnoringImplicit(returnStmt())) matches "3", +/// while \c integerLiteral(hasParent(returnStmt())) does not. +/// +/// Usable as: Matcher<Stmt> +extern const internal::ArgumentAdaptingMatcherFunc< + internal::HasParentIgnoringImplicitMatcher, + internal::TypeList<Decl, NestedNameSpecifierLoc, Stmt, TypeLoc>, + internal::TypeList<Stmt>> + hasParentIgnoringImplicit; + /// Matches AST nodes that have an ancestor that matches the provided /// matcher. /// Index: clang/docs/LibASTMatchersReference.html =================================================================== --- clang/docs/LibASTMatchersReference.html +++ clang/docs/LibASTMatchersReference.html @@ -422,7 +422,7 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('objcIvarDecl0')"><a name="objcIvarDecl0Anchor">objcIvarDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCIvarDecl.html">ObjCIvarDecl</a>>...</td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('objcIvarDecl0')"><a name="objcIvarDecl0Anchor">objcIvarDecl</a></td><td>Matcher<ObjCIvarDecl>...</td></tr> <tr><td colspan="4" class="doc" id="objcIvarDecl0"><pre>Matches Objective-C instance variable declarations. Example matches _enabled @@ -447,7 +447,7 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('objcPropertyDecl0')"><a name="objcPropertyDecl0Anchor">objcPropertyDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCPropertyDecl.html">ObjCPropertyDecl</a>>...</td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('objcPropertyDecl0')"><a name="objcPropertyDecl0Anchor">objcPropertyDecl</a></td><td>Matcher<ObjCPropertyDecl>...</td></tr> <tr><td colspan="4" class="doc" id="objcPropertyDecl0"><pre>Matches Objective-C property declarations. Example matches enabled @@ -487,7 +487,7 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('staticAssertDecl0')"><a name="staticAssertDecl0Anchor">staticAssertDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1StaticAssertDecl.html">StaticAssertDecl</a>>...</td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('staticAssertDecl0')"><a name="staticAssertDecl0Anchor">staticAssertDecl</a></td><td>Matcher<StaticAssertDecl>...</td></tr> <tr><td colspan="4" class="doc" id="staticAssertDecl0"><pre>Matches a C++ static_assert declaration. Example: @@ -762,7 +762,7 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('binaryConditionalOperator0')"><a name="binaryConditionalOperator0Anchor">binaryConditionalOperator</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BinaryConditionalOperator.html">BinaryConditionalOperator</a>>...</td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('binaryConditionalOperator0')"><a name="binaryConditionalOperator0Anchor">binaryConditionalOperator</a></td><td>Matcher<BinaryConditionalOperator>...</td></tr> <tr><td colspan="4" class="doc" id="binaryConditionalOperator0"><pre>Matches binary conditional operator expressions (GNU extension). Example matches a ?: b @@ -935,7 +935,7 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxConstCastExpr0')"><a name="cxxConstCastExpr0Anchor">cxxConstCastExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXConstCastExpr.html">CXXConstCastExpr</a>>...</td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxConstCastExpr0')"><a name="cxxConstCastExpr0Anchor">cxxConstCastExpr</a></td><td>Matcher<CXXConstCastExpr>...</td></tr> <tr><td colspan="4" class="doc" id="cxxConstCastExpr0"><pre>Matches a const_cast expression. Example: Matches const_cast<int*>(&r) in @@ -989,7 +989,7 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxDynamicCastExpr0')"><a name="cxxDynamicCastExpr0Anchor">cxxDynamicCastExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXDynamicCastExpr.html">CXXDynamicCastExpr</a>>...</td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxDynamicCastExpr0')"><a name="cxxDynamicCastExpr0Anchor">cxxDynamicCastExpr</a></td><td>Matcher<CXXDynamicCastExpr>...</td></tr> <tr><td colspan="4" class="doc" id="cxxDynamicCastExpr0"><pre>Matches a dynamic_cast expression. Example: @@ -1077,7 +1077,7 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxReinterpretCastExpr0')"><a name="cxxReinterpretCastExpr0Anchor">cxxReinterpretCastExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXReinterpretCastExpr.html">CXXReinterpretCastExpr</a>>...</td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxReinterpretCastExpr0')"><a name="cxxReinterpretCastExpr0Anchor">cxxReinterpretCastExpr</a></td><td>Matcher<CXXReinterpretCastExpr>...</td></tr> <tr><td colspan="4" class="doc" id="cxxReinterpretCastExpr0"><pre>Matches a reinterpret_cast expression. Either the source expression or the destination type can be matched @@ -1089,7 +1089,7 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxStaticCastExpr0')"><a name="cxxStaticCastExpr0Anchor">cxxStaticCastExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXStaticCastExpr.html">CXXStaticCastExpr</a>>...</td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('cxxStaticCastExpr0')"><a name="cxxStaticCastExpr0Anchor">cxxStaticCastExpr</a></td><td>Matcher<CXXStaticCastExpr>...</td></tr> <tr><td colspan="4" class="doc" id="cxxStaticCastExpr0"><pre>Matches a C++ static_cast expression. See also: hasDestinationType @@ -1241,7 +1241,7 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('exprWithCleanups0')"><a name="exprWithCleanups0Anchor">exprWithCleanups</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ExprWithCleanups.html">ExprWithCleanups</a>>...</td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('exprWithCleanups0')"><a name="exprWithCleanups0Anchor">exprWithCleanups</a></td><td>Matcher<ExprWithCleanups>...</td></tr> <tr><td colspan="4" class="doc" id="exprWithCleanups0"><pre>Matches expressions that introduce cleanups to be run at the end of the sub-expression's evaluation. @@ -1398,7 +1398,7 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('objcCatchStmt0')"><a name="objcCatchStmt0Anchor">objcCatchStmt</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCAtCatchStmt.html">ObjCAtCatchStmt</a>>...</td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('objcCatchStmt0')"><a name="objcCatchStmt0Anchor">objcCatchStmt</a></td><td>Matcher<ObjCAtCatchStmt>...</td></tr> <tr><td colspan="4" class="doc" id="objcCatchStmt0"><pre>Matches Objective-C @catch statements. Example matches @catch @@ -1407,7 +1407,7 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('objcFinallyStmt0')"><a name="objcFinallyStmt0Anchor">objcFinallyStmt</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCAtFinallyStmt.html">ObjCAtFinallyStmt</a>>...</td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('objcFinallyStmt0')"><a name="objcFinallyStmt0Anchor">objcFinallyStmt</a></td><td>Matcher<ObjCAtFinallyStmt>...</td></tr> <tr><td colspan="4" class="doc" id="objcFinallyStmt0"><pre>Matches Objective-C @finally statements. Example matches @finally @@ -1440,14 +1440,14 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('objcThrowStmt0')"><a name="objcThrowStmt0Anchor">objcThrowStmt</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCAtThrowStmt.html">ObjCAtThrowStmt</a>>...</td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('objcThrowStmt0')"><a name="objcThrowStmt0Anchor">objcThrowStmt</a></td><td>Matcher<ObjCAtThrowStmt>...</td></tr> <tr><td colspan="4" class="doc" id="objcThrowStmt0"><pre>Matches Objective-C statements. Example matches @throw obj; </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('objcTryStmt0')"><a name="objcTryStmt0Anchor">objcTryStmt</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCAtTryStmt.html">ObjCAtTryStmt</a>>...</td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('objcTryStmt0')"><a name="objcTryStmt0Anchor">objcTryStmt</a></td><td>Matcher<ObjCAtTryStmt>...</td></tr> <tr><td colspan="4" class="doc" id="objcTryStmt0"><pre>Matches Objective-C @try statements. Example matches @try @@ -1470,7 +1470,7 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('opaqueValueExpr0')"><a name="opaqueValueExpr0Anchor">opaqueValueExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1OpaqueValueExpr.html">OpaqueValueExpr</a>>...</td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('opaqueValueExpr0')"><a name="opaqueValueExpr0Anchor">opaqueValueExpr</a></td><td>Matcher<OpaqueValueExpr>...</td></tr> <tr><td colspan="4" class="doc" id="opaqueValueExpr0"><pre>Matches opaque value expressions. They are used as helpers to reference another expressions and can be met in BinaryConditionalOperators, for example. @@ -2157,6 +2157,19 @@ </pre></td></tr> +<tr><td>Matcher<*></td><td class="name" onclick="toggle('hasParentIgnoringImplicit0')"><a name="hasParentIgnoringImplicit0Anchor">hasParentIgnoringImplicit</a></td><td>MatcherT InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasParentIgnoringImplicit0"><pre>Matches AST nodes that have an ancestor, reachable only through +implicit-expression nodes, that matches the provided matcher. + +Given +float f() { return 3; } +integerLiteral(hasParentIgnoringImplicit(returnStmt())) matches "3", +while integerLiteral(hasParent(returnStmt())) does not. + +Usable as: Any Matcher +</pre></td></tr> + + <tr><td>Matcher<*></td><td class="name" onclick="toggle('unless0')"><a name="unless0Anchor">unless</a></td><td>Matcher<*></td></tr> <tr><td colspan="4" class="doc" id="unless0"><pre>Matches if the provided matcher does not match. @@ -7239,7 +7252,7 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1OpaqueValueExpr.html">OpaqueValueExpr</a>></td><td class="name" onclick="toggle('hasSourceExpression1')"><a name="hasSourceExpression1Anchor">hasSourceExpression</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr> +<tr><td>Matcher<OpaqueValueExpr></td><td class="name" onclick="toggle('hasSourceExpression1')"><a name="hasSourceExpression1Anchor">hasSourceExpression</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr> <tr><td colspan="4" class="doc" id="hasSourceExpression1"><pre>Matches if the cast's source expression or opaque value's source expression matches the given matcher.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits