Author: Julian Schmidt Date: 2024-01-16T17:13:38+01:00 New Revision: cbaadb1f0ff9966a65c926b3d8c32f2f47281b73
URL: https://github.com/llvm/llvm-project/commit/cbaadb1f0ff9966a65c926b3d8c32f2f47281b73 DIFF: https://github.com/llvm/llvm-project/commit/cbaadb1f0ff9966a65c926b3d8c32f2f47281b73.diff LOG: [clang][ASTMatcher] Add matchers for CXXFoldExpr (#71245) Adds support for the following matchers related to `CXXFoldExpr`: `cxxFoldExpr`, `callee`, `hasInit`, `hasPattern`, `isRightFold`, `isLeftFold`, `isUnaryFold`, `isBinaryFold`, `hasOperator`, `hasLHS`, `hasRHS`. Added: Modified: clang/docs/LibASTMatchersReference.html clang/docs/ReleaseNotes.rst clang/include/clang/ASTMatchers/ASTMatchers.h clang/include/clang/ASTMatchers/ASTMatchersInternal.h clang/lib/ASTMatchers/ASTMatchersInternal.cpp clang/lib/ASTMatchers/Dynamic/Registry.cpp clang/unittests/AST/ASTImporterTest.cpp clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp Removed: ################################################################################ diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index fcd3114bb523105..c40d679e383bb2a 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. @@ -2965,11 +2976,18 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2> <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>></td><td class="name" onclick="toggle('hasOperatorName0')"><a name="hasOperatorName0Anchor">hasOperatorName</a></td><td>std::string Name</td></tr> -<tr><td colspan="4" class="doc" id="hasOperatorName0"><pre>Matches the operator Name of operator expressions (binary or -unary). +<tr><td colspan="4" class="doc" id="hasOperatorName0"><pre>Matches the operator Name of operator expressions and fold expressions +(binary or unary). Example matches a || b (matcher = binaryOperator(hasOperatorName("||"))) !(a || b) + +Example matches `(0 + ... + args)` + (matcher = cxxFoldExpr(hasOperatorName("+"))) + template <typename... Args> + auto sum(Args... args) { + return (0 + ... + args); + } </pre></td></tr> @@ -3430,6 +3448,91 @@ <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('hasOperatorName3')"><a name="hasOperatorName3Anchor">hasOperatorName</a></td><td>std::string Name</td></tr> +<tr><td colspan="4" class="doc" id="hasOperatorName3"><pre>Matches the operator Name of operator expressions and fold expressions +(binary or unary). + +Example matches a || b (matcher = binaryOperator(hasOperatorName("||"))) + !(a || b) + +Example matches `(0 + ... + args)` + (matcher = cxxFoldExpr(hasOperatorName("+"))) + 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_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. @@ -3599,11 +3702,18 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2> <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>></td><td class="name" onclick="toggle('hasOperatorName1')"><a name="hasOperatorName1Anchor">hasOperatorName</a></td><td>std::string Name</td></tr> -<tr><td colspan="4" class="doc" id="hasOperatorName1"><pre>Matches the operator Name of operator expressions (binary or -unary). +<tr><td colspan="4" class="doc" id="hasOperatorName1"><pre>Matches the operator Name of operator expressions and fold expressions +(binary or unary). Example matches a || b (matcher = binaryOperator(hasOperatorName("||"))) !(a || b) + +Example matches `(0 + ... + args)` + (matcher = cxxFoldExpr(hasOperatorName("+"))) + template <typename... Args> + auto sum(Args... args) { + return (0 + ... + args); + } </pre></td></tr> @@ -3757,11 +3867,18 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2> <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRewrittenBinaryOperator.html">CXXRewrittenBinaryOperator</a>></td><td class="name" onclick="toggle('hasOperatorName2')"><a name="hasOperatorName2Anchor">hasOperatorName</a></td><td>std::string Name</td></tr> -<tr><td colspan="4" class="doc" id="hasOperatorName2"><pre>Matches the operator Name of operator expressions (binary or -unary). +<tr><td colspan="4" class="doc" id="hasOperatorName2"><pre>Matches the operator Name of operator expressions and fold expressions +(binary or unary). Example matches a || b (matcher = binaryOperator(hasOperatorName("||"))) !(a || b) + +Example matches `(0 + ... + args)` + (matcher = cxxFoldExpr(hasOperatorName("+"))) + template <typename... Args> + auto sum(Args... args) { + return (0 + ... + args); + } </pre></td></tr> @@ -5711,12 +5828,19 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2> </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UnaryOperator.html">UnaryOperator</a>></td><td class="name" onclick="toggle('hasOperatorName3')"><a name="hasOperatorName3Anchor">hasOperatorName</a></td><td>std::string Name</td></tr> -<tr><td colspan="4" class="doc" id="hasOperatorName3"><pre>Matches the operator Name of operator expressions (binary or -unary). +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UnaryOperator.html">UnaryOperator</a>></td><td class="name" onclick="toggle('hasOperatorName4')"><a name="hasOperatorName4Anchor">hasOperatorName</a></td><td>std::string Name</td></tr> +<tr><td colspan="4" class="doc" id="hasOperatorName4"><pre>Matches the operator Name of operator expressions and fold expressions +(binary or unary). Example matches a || b (matcher = binaryOperator(hasOperatorName("||"))) !(a || b) + +Example matches `(0 + ... + args)` + (matcher = cxxFoldExpr(hasOperatorName("+"))) + template <typename... Args> + auto sum(Args... args) { + return (0 + ... + args); + } </pre></td></tr> @@ -6453,7 +6577,7 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>></td><td class="name" onclick="toggle('hasEitherOperand0')"><a name="hasEitherOperand0Anchor">hasEitherOperand</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="hasEitherOperand0"><pre>Matches if either the left hand side or the right hand side of a -binary operator matches. +binary operator or fold expression matches. </pre></td></tr> @@ -6466,7 +6590,8 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>></td><td class="name" onclick="toggle('hasOperands0')"><a name="hasOperands0Anchor">hasOperands</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> Matcher1, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> Matcher2</td></tr> -<tr><td colspan="4" class="doc" id="hasOperands0"><pre>Matches if both matchers match with opposite sides of the binary operator. +<tr><td colspan="4" class="doc" id="hasOperands0"><pre>Matches if both matchers match with opposite sides of the binary operator +or fold expression. Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1), integerLiteral(equals(2))) @@ -6885,6 +7010,112 @@ <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('hasEitherOperand2')"><a name="hasEitherOperand2Anchor">hasEitherOperand</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="hasEitherOperand2"><pre>Matches if either the left hand side or the right hand side of a +binary operator or fold expression matches. +</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('hasOperands2')"><a name="hasOperands2Anchor">hasOperands</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> Matcher1, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> Matcher2</td></tr> +<tr><td colspan="4" class="doc" id="hasOperands2"><pre>Matches if both matchers match with opposite sides of the binary operator +or fold expression. + +Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1), + integerLiteral(equals(2))) + 1 + 2 // Match + 2 + 1 // Match + 1 + 1 // No match + 2 + 2 // No match +</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 @@ -7179,7 +7410,7 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>></td><td class="name" onclick="toggle('hasEitherOperand1')"><a name="hasEitherOperand1Anchor">hasEitherOperand</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="hasEitherOperand1"><pre>Matches if either the left hand side or the right hand side of a -binary operator matches. +binary operator or fold expression matches. </pre></td></tr> @@ -7192,7 +7423,8 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXOperatorCallExpr.html">CXXOperatorCallExpr</a>></td><td class="name" onclick="toggle('hasOperands1')"><a name="hasOperands1Anchor">hasOperands</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> Matcher1, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> Matcher2</td></tr> -<tr><td colspan="4" class="doc" id="hasOperands1"><pre>Matches if both matchers match with opposite sides of the binary operator. +<tr><td colspan="4" class="doc" id="hasOperands1"><pre>Matches if both matchers match with opposite sides of the binary operator +or fold expression. Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1), integerLiteral(equals(2))) @@ -7317,9 +7549,9 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRewrittenBinaryOperator.html">CXXRewrittenBinaryOperator</a>></td><td class="name" onclick="toggle('hasEitherOperand2')"><a name="hasEitherOperand2Anchor">hasEitherOperand</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="hasEitherOperand2"><pre>Matches if either the left hand side or the right hand side of a -binary operator matches. +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRewrittenBinaryOperator.html">CXXRewrittenBinaryOperator</a>></td><td class="name" onclick="toggle('hasEitherOperand3')"><a name="hasEitherOperand3Anchor">hasEitherOperand</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="hasEitherOperand3"><pre>Matches if either the left hand side or the right hand side of a +binary operator or fold expression matches. </pre></td></tr> @@ -7331,8 +7563,9 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRewrittenBinaryOperator.html">CXXRewrittenBinaryOperator</a>></td><td class="name" onclick="toggle('hasOperands2')"><a name="hasOperands2Anchor">hasOperands</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> Matcher1, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> Matcher2</td></tr> -<tr><td colspan="4" class="doc" id="hasOperands2"><pre>Matches if both matchers match with opposite sides of the binary operator. +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRewrittenBinaryOperator.html">CXXRewrittenBinaryOperator</a>></td><td class="name" onclick="toggle('hasOperands3')"><a name="hasOperands3Anchor">hasOperands</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> Matcher1, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> Matcher2</td></tr> +<tr><td colspan="4" class="doc" id="hasOperands3"><pre>Matches if both matchers match with opposite sides of the binary operator +or fold expression. Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1), integerLiteral(equals(2))) @@ -7436,8 +7669,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 +7691,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 +7701,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 +9335,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 c2440bc4651819b..6e31849ce16dd40 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -1123,6 +1123,9 @@ AST Matchers - Add ``convertVectorExpr``. - Add ``dependentSizedExtVectorType``. - Add ``macroQualifiedType``. +- Add ``CXXFoldExpr`` related matchers: ``cxxFoldExpr``, ``callee``, + ``hasInit``, ``hasPattern``, ``isRightFold``, ``isLeftFold``, + ``isUnaryFold``, ``isBinaryFold``, ``hasOperator``, ``hasLHS``, ``hasRHS``, ``hasEitherOperand``. clang-format ------------ diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 82a26356c58f556..65196c52a3e293e 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,121 @@ 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) { + const Expr *const Pattern = Node.getPattern(); + return Pattern && InnerMacher.matches(*Pattern, 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 n'th item of an initializer list expression. /// /// Example matches y. @@ -5709,17 +5855,27 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(equals, .matchesNode(Node); } -/// Matches the operator Name of operator expressions (binary or -/// unary). +/// Matches the operator Name of operator expressions and fold expressions +/// (binary or unary). /// /// Example matches a || b (matcher = binaryOperator(hasOperatorName("||"))) /// \code /// !(a || b) /// \endcode +/// +/// Example matches `(0 + ... + args)` +/// (matcher = cxxFoldExpr(hasOperatorName("+"))) +/// \code +/// template <typename... Args> +/// auto sum(Args... args) { +/// return (0 + ... + args); +/// } +/// \endcode AST_POLYMORPHIC_MATCHER_P( hasOperatorName, AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, CXXOperatorCallExpr, - CXXRewrittenBinaryOperator, UnaryOperator), + CXXRewrittenBinaryOperator, CXXFoldExpr, + UnaryOperator), std::string, Name) { if (std::optional<StringRef> OpName = internal::getOpName(Node)) return *OpName == Name; @@ -5789,11 +5945,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,29 +5962,31 @@ 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)); } /// Matches if either the left hand side or the right hand side of a -/// binary operator matches. +/// binary operator or fold expression matches. AST_POLYMORPHIC_MATCHER_P( hasEitherOperand, AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, CXXOperatorCallExpr, - CXXRewrittenBinaryOperator), + CXXFoldExpr, CXXRewrittenBinaryOperator), internal::Matcher<Expr>, InnerMatcher) { return internal::VariadicDynCastAllOfMatcher<Stmt, NodeType>()( anyOf(hasLHS(InnerMatcher), hasRHS(InnerMatcher))) .matches(Node, Finder, Builder); } -/// Matches if both matchers match with opposite sides of the binary operator. +/// Matches if both matchers match with opposite sides of the binary operator +/// or fold expression. /// /// Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1), /// integerLiteral(equals(2))) @@ -5840,7 +5999,7 @@ AST_POLYMORPHIC_MATCHER_P( AST_POLYMORPHIC_MATCHER_P2( hasOperands, AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, CXXOperatorCallExpr, - CXXRewrittenBinaryOperator), + CXXFoldExpr, CXXRewrittenBinaryOperator), internal::Matcher<Expr>, Matcher1, internal::Matcher<Expr>, Matcher2) { return internal::VariadicDynCastAllOfMatcher<Stmt, NodeType>()( anyOf(allOf(hasLHS(Matcher1), hasRHS(Matcher2)), diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h index 7136d0d2fe0845a..47d912c73dd7eb4 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -2195,6 +2195,9 @@ inline std::optional<StringRef> getOpName(const CXXOperatorCallExpr &Node) { } return BinaryOperator::getOpcodeStr(*optBinaryOpcode); } +inline StringRef getOpName(const CXXFoldExpr &Node) { + return BinaryOperator::getOpcodeStr(Node.getOperator()); +} /// Matches overloaded operators with a specific name. /// diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index 8ed213ca2ce0965..bf87b1aa0992a5e 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..15dad022df5fe09 100644 --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -198,6 +198,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(cxxDependentScopeMemberExpr); REGISTER_MATCHER(cxxDestructorDecl); REGISTER_MATCHER(cxxDynamicCastExpr); + REGISTER_MATCHER(cxxFoldExpr); REGISTER_MATCHER(cxxForRangeStmt); REGISTER_MATCHER(cxxFunctionalCastExpr); REGISTER_MATCHER(cxxMemberCallExpr); @@ -319,6 +320,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasExplicitSpecifier); REGISTER_MATCHER(hasExternalFormalLinkage); REGISTER_MATCHER(hasFalseExpression); + REGISTER_MATCHER(hasFoldInit); REGISTER_MATCHER(hasGlobalStorage); REGISTER_MATCHER(hasImplicitDestinationType); REGISTER_MATCHER(hasInClassInitializer); @@ -344,6 +346,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasOverloadedOperatorName); REGISTER_MATCHER(hasParameter); REGISTER_MATCHER(hasParent); + REGISTER_MATCHER(hasPattern); REGISTER_MATCHER(hasPointeeLoc); REGISTER_MATCHER(hasQualifier); REGISTER_MATCHER(hasRHS); @@ -404,6 +407,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(isAssignmentOperator); REGISTER_MATCHER(isAtPosition); REGISTER_MATCHER(isBaseInitializer); + REGISTER_MATCHER(isBinaryFold); REGISTER_MATCHER(isBitField); REGISTER_MATCHER(isCatchAll); REGISTER_MATCHER(isClass); @@ -447,6 +451,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(isInteger); REGISTER_MATCHER(isIntegral); REGISTER_MATCHER(isLambda); + REGISTER_MATCHER(isLeftFold); REGISTER_MATCHER(isListInitialization); REGISTER_MATCHER(isMain); REGISTER_MATCHER(isMemberInitializer); @@ -460,6 +465,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(isProtected); REGISTER_MATCHER(isPublic); REGISTER_MATCHER(isPure); + REGISTER_MATCHER(isRightFold); REGISTER_MATCHER(isScoped); REGISTER_MATCHER(isSharedKind); REGISTER_MATCHER(isSignedInteger); @@ -469,6 +475,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(isStruct); REGISTER_MATCHER(isTemplateInstantiation); REGISTER_MATCHER(isTypeDependent); + REGISTER_MATCHER(isUnaryFold); REGISTER_MATCHER(isUnion); REGISTER_MATCHER(isUnsignedInteger); REGISTER_MATCHER(isUserProvided); diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp index 3d1f4c85c90ad56..e3f3a1bef656b2d 100644 --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -816,22 +816,15 @@ 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()); - auto Match3 = - cxxFoldExpr(hasOperator(BO_Mul), isRightFold(), unless(hasInit())); - auto Match4 = cxxFoldExpr(hasOperator(BO_Div), isRightFold(), hasInit()); + auto Match1 = cxxFoldExpr(hasOperatorName("+"), isLeftFold(), + unless(hasFoldInit(expr()))); + auto Match2 = + cxxFoldExpr(hasOperatorName("-"), isLeftFold(), hasFoldInit(expr())); + auto Match3 = cxxFoldExpr(hasOperatorName("*"), isRightFold(), + unless(hasFoldInit(expr()))); + auto Match4 = + cxxFoldExpr(hasOperatorName("/"), isRightFold(), hasFoldInit(expr())); MatchVerifier<Decl> Verifier; testImport("template <typename... Ts>" @@ -1717,7 +1710,7 @@ TEST_P(ASTImporterOptionSpecificTestBase, R"s( struct declToImport { int a = d; - union { + union { int b; int c; }; @@ -4012,7 +4005,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..edcdae4559d970b 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(hasOperatorName("+")))); + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(hasOperatorName("+")))); + + EXPECT_FALSE( + matches("template <typename... Args> auto multiply(Args... args) { " + "return (0 * ... * args); }", + cxxFoldExpr(hasOperatorName("+")))); + EXPECT_FALSE( + matches("template <typename... Args> auto multiply(Args... args) { " + "return (... * args); };", + cxxFoldExpr(hasOperatorName("+")))); } 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..6911d7600a71889 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -658,27 +658,27 @@ void check_match_co_return() { co_return 1; } )cpp"; - EXPECT_TRUE(matchesConditionally(CoReturnCode, - coreturnStmt(isExpansionInMainFile()), - true, {"-std=c++20", "-I/"}, M)); + EXPECT_TRUE(matchesConditionally(CoReturnCode, + coreturnStmt(isExpansionInMainFile()), true, + {"-std=c++20", "-I/"}, M)); StringRef CoAwaitCode = R"cpp( #include <coro_header> void check_match_co_await() { co_await a; } )cpp"; - EXPECT_TRUE(matchesConditionally(CoAwaitCode, - coawaitExpr(isExpansionInMainFile()), - true, {"-std=c++20", "-I/"}, M)); + EXPECT_TRUE(matchesConditionally(CoAwaitCode, + coawaitExpr(isExpansionInMainFile()), true, + {"-std=c++20", "-I/"}, M)); StringRef CoYieldCode = R"cpp( #include <coro_header> void check_match_co_yield() { co_yield 1.0; } )cpp"; - EXPECT_TRUE(matchesConditionally(CoYieldCode, - coyieldExpr(isExpansionInMainFile()), - true, {"-std=c++20", "-I/"}, M)); + EXPECT_TRUE(matchesConditionally(CoYieldCode, + coyieldExpr(isExpansionInMainFile()), true, + {"-std=c++20", "-I/"}, M)); StringRef NonCoroCode = R"cpp( #include <coro_header> @@ -2000,6 +2000,146 @@ 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, HasEitherOperandAndHasOperands) { + if (!GetParam().isCXX17OrLater()) { + return; + } + + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(hasEitherOperand(integerLiteral())))); + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(hasEitherOperand(integerLiteral())))); + + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(hasEitherOperand( + declRefExpr(to(namedDecl(hasName("args")))))))); + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(hasEitherOperand( + declRefExpr(to(namedDecl(hasName("args")))))))); + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(hasEitherOperand( + declRefExpr(to(namedDecl(hasName("args")))))))); + EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { " + "return (args + ...); };", + cxxFoldExpr(hasEitherOperand( + declRefExpr(to(namedDecl(hasName("args")))))))); + + EXPECT_TRUE(matches( + "template <typename... Args> auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(hasOperands(declRefExpr(to(namedDecl(hasName("args")))), + integerLiteral())))); + EXPECT_TRUE(matches( + "template <typename... Args> auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(hasOperands(declRefExpr(to(namedDecl(hasName("args")))), + integerLiteral())))); + EXPECT_FALSE(matches( + "template <typename... Args> auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(hasOperands(declRefExpr(to(namedDecl(hasName("args")))), + integerLiteral())))); + EXPECT_FALSE(matches( + "template <typename... Args> auto sum(Args... args) { " + "return (args + ...); };", + cxxFoldExpr(hasOperands(declRefExpr(to(namedDecl(hasName("args")))), + integerLiteral())))); +} + +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