https://github.com/5chmidti updated https://github.com/llvm/llvm-project/pull/71245
>From bd26678cd8a444aac6c7362df7eadedbb614b7fe Mon Sep 17 00:00:00 2001 From: Julian Schmidt <44101708+5chmi...@users.noreply.github.com> Date: Fri, 3 Nov 2023 21:51:57 +0100 Subject: [PATCH] [clang][ASTMatcher] Add matchers for CXXFoldExpr --- clang/docs/LibASTMatchersReference.html | 209 +++++++++++++++++- clang/docs/ReleaseNotes.rst | 3 + clang/include/clang/ASTMatchers/ASTMatchers.h | 196 ++++++++++++++-- clang/lib/ASTMatchers/ASTMatchersInternal.cpp | 1 + clang/lib/ASTMatchers/Dynamic/Registry.cpp | 1 + clang/unittests/AST/ASTImporterTest.cpp | 22 +- .../ASTMatchers/ASTMatchersNarrowingTest.cpp | 99 ++++++++- .../ASTMatchers/ASTMatchersNodeTest.cpp | 13 ++ .../ASTMatchers/ASTMatchersTraversalTest.cpp | 89 ++++++++ 9 files changed, 592 insertions(+), 41 deletions(-) diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index fcd3114bb523105..39d1ffe3d2dee3b 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -1629,6 +1629,17 @@ <h2 id="decl-matchers">Node Matchers</h2> </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('cxxFoldExpr0')"><a name="cxxFoldExpr0Anchor">cxxFoldExpr</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFoldExpr.html">CXXFoldExpr</a>>...</td></tr> +<tr><td colspan="4" class="doc" id="cxxFoldExpr0"><pre>Matches C++17 fold expressions. + +Example matches `(0 + ... + args)`: + template <typename... Args> + auto sum(Args... args) { + return (0 + ... + args); + } +</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('cxxForRangeStmt0')"><a name="cxxForRangeStmt0Anchor">cxxForRangeStmt</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXForRangeStmt.html">CXXForRangeStmt</a>>...</td></tr> <tr><td colspan="4" class="doc" id="cxxForRangeStmt0"><pre>Matches range-based for statements. @@ -3430,6 +3441,92 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2> </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFoldExpr.html">CXXFoldExpr</a>></td><td class="name" onclick="toggle('hasOperator0')"><a name="hasOperator0Anchor">hasOperator</a></td><td>BinaryOperatorKind Op</td></tr> +<tr><td colspan="4" class="doc" id="hasOperator0"><pre>Matches the operator kind of the fold expression. + +Example matches `(0 + ... + args)` + (matcher = cxxFoldExpr(hasOperator(BO_Add))) + template <typename... Args> + auto sum(Args... args) { + return (0 + ... + args); + } + + template <typename... Args> + auto multiply(Args... args) { + return (args * ... * 1); + } +</pre></td></tr> + + +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFoldExpr.html">CXXFoldExpr</a>></td><td class="name" onclick="toggle('isBinaryFold0')"><a name="isBinaryFold0Anchor">isBinaryFold</a></td><td></td></tr> +<tr><td colspan="4" class="doc" id="isBinaryFold0"><pre>Matches binary fold expressions, i.e. fold expressions with an initializer. + +Example matches `(0 + ... + args)` + (matcher = cxxFoldExpr(isBinaryFold())) + template <typename... Args> + auto sum(Args... args) { + return (0 + ... + args); + } + + template <typename... Args> + auto multiply(Args... args) { + return (args * ...); + } +</pre></td></tr> + + +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFoldExpr.html">CXXFoldExpr</a>></td><td class="name" onclick="toggle('isLeftFold0')"><a name="isLeftFold0Anchor">isLeftFold</a></td><td></td></tr> +<tr><td colspan="4" class="doc" id="isLeftFold0"><pre>Matches left-folding fold expressions. + +Example matches `(0 + ... + args)` + (matcher = cxxFoldExpr(isLeftFold())) + template <typename... Args> + auto sum(Args... args) { + return (0 + ... + args); + } + + template <typename... Args> + auto multiply(Args... args) { + return (args * ... * 1); + } +</pre></td></tr> + + +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFoldExpr.html">CXXFoldExpr</a>></td><td class="name" onclick="toggle('isRightFold0')"><a name="isRightFold0Anchor">isRightFold</a></td><td></td></tr> +<tr><td colspan="4" class="doc" id="isRightFold0"><pre>Matches right-folding fold expressions. + +Example matches `(args * ... * 1)` + (matcher = cxxFoldExpr(isRightFold())) + template <typename... Args> + auto sum(Args... args) { + return (0 + ... + args); + } + + template <typename... Args> + auto multiply(Args... args) { + return (args * ... * 1); + } +</pre></td></tr> + + +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFoldExpr.html">CXXFoldExpr</a>></td><td class="name" onclick="toggle('isUnaryFold0')"><a name="isUnaryFold0Anchor">isUnaryFold</a></td><td></td></tr> +<tr><td colspan="4" class="doc" id="isUnaryFold0"><pre>Matches unary fold expressions, i.e. fold expressions without an +initializer. + +Example matches `(args * ...)` + (matcher = cxxFoldExpr(isUnaryFold())) + template <typename... Args> + auto sum(Args... args) { + return (0 + ... + args); + } + + template <typename... Args> + auto multiply(Args... args) { + return (args * ...); + } +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>></td><td class="name" onclick="toggle('isConst0')"><a name="isConst0Anchor">isConst</a></td><td></td></tr> <tr><td colspan="4" class="doc" id="isConst0"><pre>Matches if the given method declaration is const. @@ -6885,6 +6982,93 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFoldExpr.html">CXXFoldExpr</a>></td><td class="name" onclick="toggle('callee1')"><a name="callee1Anchor">callee</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="callee1"><pre>Matches if the call or fold expression's callee expression matches. + +Given + class Y { void x() { this->x(); x(); Y y; y.x(); } }; + void f() { f(); } +callExpr(callee(expr())) + matches this->x(), x(), y.x(), f() +with callee(...) + matching this->x, x, y.x, f respectively + +Given + template <typename... Args> + auto sum(Args... args) { + return (0 + ... + args); + } + + template <typename... Args> + auto multiply(Args... args) { + return (args * ... * 1); + } +cxxFoldExpr(callee(expr())) + matches (args * ... * 1) +with callee(...) + matching * + +Note: Callee cannot take the more general internal::Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> +because this introduces ambiguous overloads with calls to Callee taking a +internal::Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, as the matcher hierarchy is purely +implemented in terms of implicit casts. +</pre></td></tr> + + +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFoldExpr.html">CXXFoldExpr</a>></td><td class="name" onclick="toggle('hasFoldInit0')"><a name="hasFoldInit0Anchor">hasFoldInit</a></td><td>ast_matchers::Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMacher</td></tr> +<tr><td colspan="4" class="doc" id="hasFoldInit0"><pre>Matches the operand that does not contain the parameter pack. + +Example matches `(0 + ... + args)` and `(args * ... * 1)` + (matcher = cxxFoldExpr(hasFoldInit(expr()))) + with hasFoldInit(...) + matching `0` and `1` respectively + template <typename... Args> + auto sum(Args... args) { + return (0 + ... + args); + } + + template <typename... Args> + auto multiply(Args... args) { + return (args * ... * 1); + } +</pre></td></tr> + + +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFoldExpr.html">CXXFoldExpr</a>></td><td class="name" onclick="toggle('hasLHS4')"><a name="hasLHS4Anchor">hasLHS</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="hasLHS4"><pre>Matches the left hand side of binary operator expressions. + +Example matches a (matcher = binaryOperator(hasLHS())) + a || b +</pre></td></tr> + + +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFoldExpr.html">CXXFoldExpr</a>></td><td class="name" onclick="toggle('hasPattern0')"><a name="hasPattern0Anchor">hasPattern</a></td><td>ast_matchers::Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMacher</td></tr> +<tr><td colspan="4" class="doc" id="hasPattern0"><pre>Matches the operand that contains the parameter pack. + +Example matches `(0 + ... + args)` + (matcher = cxxFoldExpr(hasPattern(expr()))) + with hasPattern(...) + matching `args` + template <typename... Args> + auto sum(Args... args) { + return (0 + ... + args); + } + + template <typename... Args> + auto multiply(Args... args) { + return (args * ... * 1); + } +</pre></td></tr> + + +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXFoldExpr.html">CXXFoldExpr</a>></td><td class="name" onclick="toggle('hasRHS4')"><a name="hasRHS4Anchor">hasRHS</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="hasRHS4"><pre>Matches the right hand side of binary operator expressions. + +Example matches b (matcher = binaryOperator(hasRHS())) + a || b +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXForRangeStmt.html">CXXForRangeStmt</a>></td><td class="name" onclick="toggle('hasBody3')"><a name="hasBody3Anchor">hasBody</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr> <tr><td colspan="4" class="doc" id="hasBody3"><pre>Matches a 'for', 'while', 'while' statement or a function or coroutine definition that has a given body. Note that in case of functions or @@ -7436,8 +7620,8 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('callee2')"><a name="callee2Anchor">callee</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr> -<tr><td colspan="4" class="doc" id="callee2"><pre>Matches 1) if the call expression's callee's declaration matches the +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('callee3')"><a name="callee3Anchor">callee</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="callee3"><pre>Matches 1) if the call expression's callee's declaration matches the given matcher; or 2) if the Obj-C message expression's callee's method declaration matches the given matcher. @@ -7458,7 +7642,7 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('callee0')"><a name="callee0Anchor">callee</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>> InnerMatcher</td></tr> -<tr><td colspan="4" class="doc" id="callee0"><pre>Matches if the call expression's callee expression matches. +<tr><td colspan="4" class="doc" id="callee0"><pre>Matches if the call or fold expression's callee expression matches. Given class Y { void x() { this->x(); x(); Y y; y.x(); } }; @@ -7468,6 +7652,21 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> with callee(...) matching this->x, x, y.x, f respectively +Given + template <typename... Args> + auto sum(Args... args) { + return (0 + ... + args); + } + + template <typename... Args> + auto multiply(Args... args) { + return (args * ... * 1); + } +cxxFoldExpr(callee(expr())) + matches (args * ... * 1) +with callee(...) + matching * + Note: Callee cannot take the more general internal::Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> because this introduces ambiguous overloads with calls to Callee taking a internal::Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, as the matcher hierarchy is purely @@ -9087,8 +9286,8 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('callee1')"><a name="callee1Anchor">callee</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr> -<tr><td colspan="4" class="doc" id="callee1"><pre>Matches 1) if the call expression's callee's declaration matches the +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('callee2')"><a name="callee2Anchor">callee</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="callee2"><pre>Matches 1) if the call expression's callee's declaration matches the given matcher; or 2) if the Obj-C message expression's callee's method declaration matches the given matcher. diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index afe7e2e79c2d087..9f753af4f7dfe6f 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -830,6 +830,9 @@ AST Matchers - Add ``convertVectorExpr``. - Add ``dependentSizedExtVectorType``. - Add ``macroQualifiedType``. +- Add ``CXXFoldExpr`` related matchers: ``cxxFoldExpr``, ``callee``, + ``hasInit``, ``hasPattern``, ``isRightFold``, ``isLeftFold``, + ``isUnaryFold``, ``isBinaryFold``, ``hasOperator``, ``hasLHS``, ``hasRHS``. clang-format ------------ diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 82a26356c58f556..4e67faa155f003a 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -2062,6 +2062,18 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDefaultArgExpr> extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXOperatorCallExpr> cxxOperatorCallExpr; +/// Matches C++17 fold expressions. +/// +/// Example matches `(0 + ... + args)`: +/// \code +/// template <typename... Args> +/// auto sum(Args... args) { +/// return (0 + ... + args); +/// } +/// \endcode +extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXFoldExpr> + cxxFoldExpr; + /// Matches rewritten binary operators /// /// Example matches use of "<": @@ -3881,7 +3893,7 @@ AST_MATCHER_P(ObjCMessageExpr, numSelectorArgs, unsigned, N) { return Node.getSelector().getNumArgs() == N; } -/// Matches if the call expression's callee expression matches. +/// Matches if the call or fold expression's callee expression matches. /// /// Given /// \code @@ -3893,13 +3905,32 @@ AST_MATCHER_P(ObjCMessageExpr, numSelectorArgs, unsigned, N) { /// with callee(...) /// matching this->x, x, y.x, f respectively /// +/// Given +/// \code +/// template <typename... Args> +/// auto sum(Args... args) { +/// return (0 + ... + args); +/// } +/// +/// template <typename... Args> +/// auto multiply(Args... args) { +/// return (args * ... * 1); +/// } +/// \endcode +/// cxxFoldExpr(callee(expr())) +/// matches (args * ... * 1) +/// with callee(...) +/// matching * +/// /// Note: Callee cannot take the more general internal::Matcher<Expr> /// because this introduces ambiguous overloads with calls to Callee taking a /// internal::Matcher<Decl>, as the matcher hierarchy is purely /// implemented in terms of implicit casts. -AST_MATCHER_P(CallExpr, callee, internal::Matcher<Stmt>, - InnerMatcher) { - const Expr *ExprNode = Node.getCallee(); +AST_POLYMORPHIC_MATCHER_P_OVERLOAD(callee, + AST_POLYMORPHIC_SUPPORTED_TYPES(CallExpr, + CXXFoldExpr), + internal::Matcher<Stmt>, InnerMatcher, 0) { + const auto *ExprNode = Node.getCallee(); return (ExprNode != nullptr && InnerMatcher.matches(*ExprNode, Finder, Builder)); } @@ -4532,6 +4563,139 @@ AST_POLYMORPHIC_MATCHER_P2(hasArgument, return InnerMatcher.matches(*Arg->IgnoreParenImpCasts(), Finder, Builder); } +/// Matches the operand that does not contain the parameter pack. +/// +/// Example matches `(0 + ... + args)` and `(args * ... * 1)` +/// (matcher = cxxFoldExpr(hasFoldInit(expr()))) +/// with hasFoldInit(...) +/// matching `0` and `1` respectively +/// \code +/// template <typename... Args> +/// auto sum(Args... args) { +/// return (0 + ... + args); +/// } +/// +/// template <typename... Args> +/// auto multiply(Args... args) { +/// return (args * ... * 1); +/// } +/// \endcode +AST_MATCHER_P(CXXFoldExpr, hasFoldInit, ast_matchers::internal::Matcher<Expr>, + InnerMacher) { + const auto *const Init = Node.getInit(); + return Init && InnerMacher.matches(*Init, Finder, Builder); +} + +/// Matches the operand that contains the parameter pack. +/// +/// Example matches `(0 + ... + args)` +/// (matcher = cxxFoldExpr(hasPattern(expr()))) +/// with hasPattern(...) +/// matching `args` +/// \code +/// template <typename... Args> +/// auto sum(Args... args) { +/// return (0 + ... + args); +/// } +/// +/// template <typename... Args> +/// auto multiply(Args... args) { +/// return (args * ... * 1); +/// } +/// \endcode +AST_MATCHER_P(CXXFoldExpr, hasPattern, ast_matchers::internal::Matcher<Expr>, + InnerMacher) { + return InnerMacher.matches(*Node.getPattern(), Finder, Builder); +} + +/// Matches right-folding fold expressions. +/// +/// Example matches `(args * ... * 1)` +/// (matcher = cxxFoldExpr(isRightFold())) +/// \code +/// template <typename... Args> +/// auto sum(Args... args) { +/// return (0 + ... + args); +/// } +/// +/// template <typename... Args> +/// auto multiply(Args... args) { +/// return (args * ... * 1); +/// } +/// \endcode +AST_MATCHER(CXXFoldExpr, isRightFold) { return Node.isRightFold(); } + +/// Matches left-folding fold expressions. +/// +/// Example matches `(0 + ... + args)` +/// (matcher = cxxFoldExpr(isLeftFold())) +/// \code +/// template <typename... Args> +/// auto sum(Args... args) { +/// return (0 + ... + args); +/// } +/// +/// template <typename... Args> +/// auto multiply(Args... args) { +/// return (args * ... * 1); +/// } +/// \endcode +AST_MATCHER(CXXFoldExpr, isLeftFold) { return Node.isLeftFold(); } + +/// Matches unary fold expressions, i.e. fold expressions without an +/// initializer. +/// +/// Example matches `(args * ...)` +/// (matcher = cxxFoldExpr(isUnaryFold())) +/// \code +/// template <typename... Args> +/// auto sum(Args... args) { +/// return (0 + ... + args); +/// } +/// +/// template <typename... Args> +/// auto multiply(Args... args) { +/// return (args * ...); +/// } +/// \endcode +AST_MATCHER(CXXFoldExpr, isUnaryFold) { return Node.getInit() == nullptr; } + +/// Matches binary fold expressions, i.e. fold expressions with an initializer. +/// +/// Example matches `(0 + ... + args)` +/// (matcher = cxxFoldExpr(isBinaryFold())) +/// \code +/// template <typename... Args> +/// auto sum(Args... args) { +/// return (0 + ... + args); +/// } +/// +/// template <typename... Args> +/// auto multiply(Args... args) { +/// return (args * ...); +/// } +/// \endcode +AST_MATCHER(CXXFoldExpr, isBinaryFold) { return Node.getInit() != nullptr; } + +/// Matches the operator kind of the fold expression. +/// +/// Example matches `(0 + ... + args)` +/// (matcher = cxxFoldExpr(hasOperator(BO_Add))) +/// \code +/// template <typename... Args> +/// auto sum(Args... args) { +/// return (0 + ... + args); +/// } +/// +/// template <typename... Args> +/// auto multiply(Args... args) { +/// return (args * ... * 1); +/// } +/// \endcode +AST_MATCHER_P(CXXFoldExpr, hasOperator, BinaryOperatorKind, Op) { + return Node.getOperator() == Op; +} + /// Matches the n'th item of an initializer list expression. /// /// Example matches y. @@ -4540,7 +4704,7 @@ AST_POLYMORPHIC_MATCHER_P2(hasArgument, /// int x{y}. /// \endcode AST_MATCHER_P2(InitListExpr, hasInit, unsigned, N, - ast_matchers::internal::Matcher<Expr>, InnerMatcher) { + ast_matchers::internal::Matcher<Expr>, InnerMatcher) { return N < Node.getNumInits() && InnerMatcher.matches(*Node.getInit(N), Finder, Builder); } @@ -5789,11 +5953,12 @@ AST_POLYMORPHIC_MATCHER( /// \code /// a || b /// \endcode -AST_POLYMORPHIC_MATCHER_P(hasLHS, - AST_POLYMORPHIC_SUPPORTED_TYPES( - BinaryOperator, CXXOperatorCallExpr, - CXXRewrittenBinaryOperator, ArraySubscriptExpr), - internal::Matcher<Expr>, InnerMatcher) { +AST_POLYMORPHIC_MATCHER_P( + hasLHS, + AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, CXXOperatorCallExpr, + CXXRewrittenBinaryOperator, + ArraySubscriptExpr, CXXFoldExpr), + internal::Matcher<Expr>, InnerMatcher) { const Expr *LeftHandSide = internal::getLHS(Node); return (LeftHandSide != nullptr && InnerMatcher.matches(*LeftHandSide, Finder, Builder)); @@ -5805,11 +5970,12 @@ AST_POLYMORPHIC_MATCHER_P(hasLHS, /// \code /// a || b /// \endcode -AST_POLYMORPHIC_MATCHER_P(hasRHS, - AST_POLYMORPHIC_SUPPORTED_TYPES( - BinaryOperator, CXXOperatorCallExpr, - CXXRewrittenBinaryOperator, ArraySubscriptExpr), - internal::Matcher<Expr>, InnerMatcher) { +AST_POLYMORPHIC_MATCHER_P( + hasRHS, + AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, CXXOperatorCallExpr, + CXXRewrittenBinaryOperator, + ArraySubscriptExpr, CXXFoldExpr), + internal::Matcher<Expr>, InnerMatcher) { const Expr *RightHandSide = internal::getRHS(Node); return (RightHandSide != nullptr && InnerMatcher.matches(*RightHandSide, Finder, Builder)); diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index 435bbdeda22066e..616e6a959e0f59d 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -893,6 +893,7 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, CXXOperatorCallExpr> cxxOperatorCallExpr; const internal::VariadicDynCastAllOfMatcher<Stmt, CXXRewrittenBinaryOperator> cxxRewrittenBinaryOperator; +const internal::VariadicDynCastAllOfMatcher<Stmt, CXXFoldExpr> cxxFoldExpr; const internal::VariadicDynCastAllOfMatcher<Stmt, Expr> expr; const internal::VariadicDynCastAllOfMatcher<Stmt, DeclRefExpr> declRefExpr; const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCIvarRefExpr> objcIvarRefExpr; diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp index 2e43dec331b75f8..8ce9e27aa36d692 100644 --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -319,6 +319,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasExplicitSpecifier); REGISTER_MATCHER(hasExternalFormalLinkage); REGISTER_MATCHER(hasFalseExpression); + REGISTER_MATCHER(hasFoldInit); REGISTER_MATCHER(hasGlobalStorage); REGISTER_MATCHER(hasImplicitDestinationType); REGISTER_MATCHER(hasInClassInitializer); diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp index 5f4d8d040772cb1..a312ffa7070d5b5 100644 --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -803,22 +803,14 @@ TEST_P(ImportExpr, ImportSizeOfPackExpr) { hasUnqualifiedDesugaredType(constantArrayType(hasSize(7)))))))))); } -const internal::VariadicDynCastAllOfMatcher<Stmt, CXXFoldExpr> cxxFoldExpr; - -AST_MATCHER_P(CXXFoldExpr, hasOperator, BinaryOperatorKind, Op) { - return Node.getOperator() == Op; -} -AST_MATCHER(CXXFoldExpr, hasInit) { return Node.getInit(); } -AST_MATCHER(CXXFoldExpr, isRightFold) { return Node.isRightFold(); } -AST_MATCHER(CXXFoldExpr, isLeftFold) { return Node.isLeftFold(); } - TEST_P(ImportExpr, ImportCXXFoldExpr) { auto Match1 = - cxxFoldExpr(hasOperator(BO_Add), isLeftFold(), unless(hasInit())); - auto Match2 = cxxFoldExpr(hasOperator(BO_Sub), isLeftFold(), hasInit()); + cxxFoldExpr(hasOperator(BO_Add), isLeftFold(), unless(hasFoldInit(expr()))); + auto Match2 = cxxFoldExpr(hasOperator(BO_Sub), isLeftFold(), hasFoldInit(expr())); auto Match3 = - cxxFoldExpr(hasOperator(BO_Mul), isRightFold(), unless(hasInit())); - auto Match4 = cxxFoldExpr(hasOperator(BO_Div), isRightFold(), hasInit()); + cxxFoldExpr(hasOperator(BO_Mul), isRightFold(), unless(hasFoldInit(expr()))); + auto Match4 = + cxxFoldExpr(hasOperator(BO_Div), isRightFold(), hasFoldInit(expr())); MatchVerifier<Decl> Verifier; testImport("template <typename... Ts>" @@ -1704,7 +1696,7 @@ TEST_P(ASTImporterOptionSpecificTestBase, R"s( struct declToImport { int a = d; - union { + union { int b; int c; }; @@ -3999,7 +3991,7 @@ TEST_P(ImportVariables, ImportBindingDecl) { int a[2] = {1,2}; auto [x1,y1] = a; auto& [x2,y2] = a; - + struct S { mutable int x1 : 2; volatile double y1; diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp index d78676fd289d5e5..ff107995715c745 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -4103,15 +4103,102 @@ TEST_P(ASTMatchersTest, IsComparisonOperator) { notMatches("void x() { int a; if(a = 0) return; }", BinCompOperator)); } -TEST_P(ASTMatchersTest, HasInit) { - if (!GetParam().isCXX11OrLater()) { - // FIXME: Add a test for `hasInit()` that does not depend on C++. +TEST_P(ASTMatchersTest, isRightFold) { + if (!GetParam().isCXX17OrLater()) { + return; + } + + EXPECT_FALSE(matches("template <typename... Args> auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(isRightFold()))); + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(isRightFold()))); + EXPECT_FALSE(matches("template <typename... Args> auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(isRightFold()))); + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (args + ...); };", + cxxFoldExpr(isRightFold()))); +} + +TEST_P(ASTMatchersTest, isLeftFold) { + if (!GetParam().isCXX17OrLater()) { + return; + } + + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(isLeftFold()))); + EXPECT_FALSE(matches("template <typename... Args> auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(isLeftFold()))); + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(isLeftFold()))); + EXPECT_FALSE(matches("template <typename... Args> auto sum(Args... args) { " + "return (args + ...); };", + cxxFoldExpr(isLeftFold()))); +} + +TEST_P(ASTMatchersTest, isUnaryFold) { + if (!GetParam().isCXX17OrLater()) { return; } - EXPECT_TRUE(matches("int x{0};", initListExpr(hasInit(0, expr())))); - EXPECT_FALSE(matches("int x{0};", initListExpr(hasInit(1, expr())))); - EXPECT_FALSE(matches("int x;", initListExpr(hasInit(0, expr())))); + EXPECT_FALSE(matches("template <typename... Args> auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(isUnaryFold()))); + EXPECT_FALSE(matches("template <typename... Args> auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(isUnaryFold()))); + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(isUnaryFold()))); + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (args + ...); };", + cxxFoldExpr(isUnaryFold()))); +} + +TEST_P(ASTMatchersTest, isBinaryFold) { + if (!GetParam().isCXX17OrLater()) { + return; + } + + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(isBinaryFold()))); + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(isBinaryFold()))); + EXPECT_FALSE(matches("template <typename... Args> auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(isBinaryFold()))); + EXPECT_FALSE(matches("template <typename... Args> auto sum(Args... args) { " + "return (args + ...); };", + cxxFoldExpr(isBinaryFold()))); +} + +TEST_P(ASTMatchersTest, hasOperator) { + if (!GetParam().isCXX17OrLater()) { + return; + } + + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(hasOperator(BO_Add)))); + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(hasOperator(BO_Add)))); + + EXPECT_FALSE( + matches("template <typename... Args> auto multiply(Args... args) { " + "return (0 * ... * args); }", + cxxFoldExpr(hasOperator(BO_Add)))); + EXPECT_FALSE( + matches("template <typename... Args> auto multiply(Args... args) { " + "return (... * args); };", + cxxFoldExpr(hasOperator(BO_Add)))); } TEST_P(ASTMatchersTest, IsMain) { diff --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp index 8f0dd5602307c53..ae30c03126d768c 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -471,6 +471,19 @@ TEST_P(ASTMatchersTest, CXXOperatorCallExpr) { EXPECT_TRUE(notMatches("int t = 5 << 2;", OpCall)); } +TEST_P(ASTMatchersTest, FoldExpr) { + if (!GetParam().isCXX() || !GetParam().isCXX17OrLater()) { + return; + } + + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr())); + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (args + ...); }", + cxxFoldExpr())); +} + TEST_P(ASTMatchersTest, ThisPointerType) { if (!GetParam().isCXX()) { return; diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp index d4a695b974bf0e5..0e7a4b4657ed439 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -2000,6 +2000,95 @@ TEST(Matcher, UnaryOperatorTypes) { "void x() { A a; !a; }", unaryOperator(hasOperatorName("!")))); } +TEST_P(ASTMatchersTest, HasInit) { + if (!GetParam().isCXX11OrLater()) { + // FIXME: Add a test for `hasInit()` that does not depend on C++. + return; + } + + EXPECT_TRUE(matches("int x{0};", initListExpr(hasInit(0, expr())))); + EXPECT_FALSE(matches("int x{0};", initListExpr(hasInit(1, expr())))); + EXPECT_FALSE(matches("int x;", initListExpr(hasInit(0, expr())))); +} + +TEST_P(ASTMatchersTest, HasFoldInit) { + if (!GetParam().isCXX17OrLater()) { + return; + } + + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(hasFoldInit(expr())))); + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(hasFoldInit(expr())))); + EXPECT_FALSE(matches("template <typename... Args> auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(hasFoldInit(expr())))); +} + +TEST_P(ASTMatchersTest, HasPattern) { + if (!GetParam().isCXX17OrLater()) { + return; + } + + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(hasPattern(expr())))); + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(hasPattern(expr())))); + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(hasPattern(expr())))); +} + +TEST_P(ASTMatchersTest, HasLHSAndHasRHS) { + if (!GetParam().isCXX17OrLater()) { + return; + } + + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(hasLHS(expr())))); + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(hasLHS(expr())))); + EXPECT_FALSE(matches("template <typename... Args> auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(hasLHS(expr())))); + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (args + ...); };", + cxxFoldExpr(hasLHS(expr())))); + + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(hasRHS(expr())))); + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(hasRHS(expr())))); + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(hasRHS(expr())))); + EXPECT_FALSE(matches("template <typename... Args> auto sum(Args... args) { " + "return (args + ...); };", + cxxFoldExpr(hasRHS(expr())))); +} + +TEST_P(ASTMatchersTest, Callee) { + if (!GetParam().isCXX17OrLater()) { + return; + } + + EXPECT_TRUE(matches( + "struct Dummy {}; Dummy operator+(Dummy, Dummy); template " + "<typename... Args> auto sum(Args... args) { return (0 + ... + args); }", + cxxFoldExpr(callee(expr())))); + EXPECT_FALSE(matches("template <typename... Args> auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(callee(expr())))); +} + TEST(ArraySubscriptMatchers, ArrayIndex) { EXPECT_TRUE(matches( "int i[2]; void f() { i[1] = 1; }", _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits