[clang] [clang][ASTMatcher] Add matchers for CXXFoldExpr (PR #71245)
Julian Schmidt via cfe-commits
cfe-commits at lists.llvm.org
Sun Jan 14 12:56:42 PST 2024
https://github.com/5chmidti updated https://github.com/llvm/llvm-project/pull/71245
>From 3979b64361ee286fd71d0aba816047dc3dea319d Mon Sep 17 00:00:00 2001
From: Julian Schmidt <44101708+5chmidti at users.noreply.github.com>
Date: Fri, 3 Nov 2023 21:51:57 +0100
Subject: [PATCH 1/5] [clang][ASTMatcher] Add matchers for CXXFoldExpr
---
clang/docs/LibASTMatchersReference.html | 209 +++++++++++++++++-
clang/docs/ReleaseNotes.rst | 3 +
clang/include/clang/ASTMatchers/ASTMatchers.h | 194 ++++++++++++++--
clang/lib/ASTMatchers/ASTMatchersInternal.cpp | 1 +
clang/lib/ASTMatchers/Dynamic/Registry.cpp | 1 +
clang/unittests/AST/ASTImporterTest.cpp | 27 +--
.../ASTMatchers/ASTMatchersNarrowingTest.cpp | 99 ++++++++-
.../ASTMatchers/ASTMatchersNodeTest.cpp | 13 ++
.../ASTMatchers/ASTMatchersTraversalTest.cpp | 89 ++++++++
9 files changed, 594 insertions(+), 42 deletions(-)
diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html
index fcd3114bb52310..39d1ffe3d2dee3 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 dc8a6fe506bce6..968fed5725d6de 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1122,6 +1122,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 82a26356c58f55..2cd50dbf3a55d8 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.
@@ -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 8ed213ca2ce096..bf87b1aa0992a5 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 2e43dec331b75f..8ce9e27aa36d69 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 37cf14bdff6b33..f5f58de1914747 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(hasOperator(BO_Add), isLeftFold(),
+ unless(hasFoldInit(expr())));
+ auto Match2 =
+ cxxFoldExpr(hasOperator(BO_Sub), isLeftFold(), hasFoldInit(expr()));
+ auto Match3 = cxxFoldExpr(hasOperator(BO_Mul), isRightFold(),
+ unless(hasFoldInit(expr())));
+ auto Match4 =
+ cxxFoldExpr(hasOperator(BO_Div), 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 d78676fd289d5e..ff107995715c74 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 8f0dd5602307c5..ae30c03126d768 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 d4a695b974bf0e..0e7a4b4657ed43 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; }",
>From 995cf295b9d5d98010d80d696535753f600e57e8 Mon Sep 17 00:00:00 2001
From: Julian Schmidt <44101708+5chmidti at users.noreply.github.com>
Date: Fri, 24 Nov 2023 23:22:45 +0100
Subject: [PATCH 2/5] add missing support for `hasEitherOperand` and
`hasOperands`
---
clang/docs/LibASTMatchersReference.html | 40 ++++++++---
clang/docs/ReleaseNotes.rst | 2 +-
clang/include/clang/ASTMatchers/ASTMatchers.h | 9 +--
.../ASTMatchers/ASTMatchersTraversalTest.cpp | 69 ++++++++++++++++---
4 files changed, 97 insertions(+), 23 deletions(-)
diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html
index 39d1ffe3d2dee3..7d72e4eb70943f 100644
--- a/clang/docs/LibASTMatchersReference.html
+++ b/clang/docs/LibASTMatchersReference.html
@@ -6550,7 +6550,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>
@@ -6563,7 +6563,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)))
@@ -7015,6 +7016,12 @@ <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('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.
@@ -7042,6 +7049,19 @@ <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('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.
@@ -7363,7 +7383,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>
@@ -7376,7 +7396,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)))
@@ -7501,9 +7522,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>
@@ -7515,8 +7536,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)))
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 968fed5725d6de..666b311f62d2d9 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1124,7 +1124,7 @@ AST Matchers
- Add ``macroQualifiedType``.
- Add ``CXXFoldExpr`` related matchers: ``cxxFoldExpr``, ``callee``,
``hasInit``, ``hasPattern``, ``isRightFold``, ``isLeftFold``,
- ``isUnaryFold``, ``isBinaryFold``, ``hasOperator``, ``hasLHS``, ``hasRHS``.
+ ``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 2cd50dbf3a55d8..07d7254404d95b 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -5982,18 +5982,19 @@ AST_POLYMORPHIC_MATCHER_P(
}
/// 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)))
@@ -6006,7 +6007,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/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
index 0e7a4b4657ed43..6911d7600a7188 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>
@@ -2075,6 +2075,57 @@ TEST_P(ASTMatchersTest, HasLHSAndHasRHS) {
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;
>From 0578a3e7fd3e97acd6cf2dff9091c2dd7465f322 Mon Sep 17 00:00:00 2001
From: Julian Schmidt <44101708+5chmidti at users.noreply.github.com>
Date: Fri, 24 Nov 2023 23:25:49 +0100
Subject: [PATCH 3/5] check if the pattern is not null in `hasPattern`
---
clang/include/clang/ASTMatchers/ASTMatchers.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 07d7254404d95b..ccd72f73480017 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -4605,7 +4605,8 @@ AST_MATCHER_P(CXXFoldExpr, hasFoldInit, ast_matchers::internal::Matcher<Expr>,
/// \endcode
AST_MATCHER_P(CXXFoldExpr, hasPattern, ast_matchers::internal::Matcher<Expr>,
InnerMacher) {
- return InnerMacher.matches(*Node.getPattern(), Finder, Builder);
+ const Expr *const Pattern = Node.getPattern();
+ return Pattern && InnerMacher.matches(*Pattern, Finder, Builder);
}
/// Matches right-folding fold expressions.
>From 6f65607c905148bd949bd03e2e816206e07b07e1 Mon Sep 17 00:00:00 2001
From: Julian Schmidt <44101708+5chmidti at users.noreply.github.com>
Date: Fri, 24 Nov 2023 23:30:14 +0100
Subject: [PATCH 4/5] register all added matchers in the registry
---
clang/lib/ASTMatchers/Dynamic/Registry.cpp | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index 8ce9e27aa36d69..a37f02056feb29 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);
@@ -341,10 +342,12 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasNullSelector);
REGISTER_MATCHER(hasObjectExpression);
REGISTER_MATCHER(hasOperands);
+ REGISTER_MATCHER(hasOperator);
REGISTER_MATCHER(hasOperatorName);
REGISTER_MATCHER(hasOverloadedOperatorName);
REGISTER_MATCHER(hasParameter);
REGISTER_MATCHER(hasParent);
+ REGISTER_MATCHER(hasPattern);
REGISTER_MATCHER(hasPointeeLoc);
REGISTER_MATCHER(hasQualifier);
REGISTER_MATCHER(hasRHS);
@@ -405,6 +408,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isAssignmentOperator);
REGISTER_MATCHER(isAtPosition);
REGISTER_MATCHER(isBaseInitializer);
+ REGISTER_MATCHER(isBinaryFold);
REGISTER_MATCHER(isBitField);
REGISTER_MATCHER(isCatchAll);
REGISTER_MATCHER(isClass);
@@ -448,6 +452,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isInteger);
REGISTER_MATCHER(isIntegral);
REGISTER_MATCHER(isLambda);
+ REGISTER_MATCHER(isLeftFold);
REGISTER_MATCHER(isListInitialization);
REGISTER_MATCHER(isMain);
REGISTER_MATCHER(isMemberInitializer);
@@ -461,6 +466,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isProtected);
REGISTER_MATCHER(isPublic);
REGISTER_MATCHER(isPure);
+ REGISTER_MATCHER(isRightFold);
REGISTER_MATCHER(isScoped);
REGISTER_MATCHER(isSharedKind);
REGISTER_MATCHER(isSignedInteger);
@@ -470,6 +476,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isStruct);
REGISTER_MATCHER(isTemplateInstantiation);
REGISTER_MATCHER(isTypeDependent);
+ REGISTER_MATCHER(isUnaryFold);
REGISTER_MATCHER(isUnion);
REGISTER_MATCHER(isUnsignedInteger);
REGISTER_MATCHER(isUserProvided);
>From 18fd8952a4eee8776bcc8d4e514f3d297e34441d Mon Sep 17 00:00:00 2001
From: Julian Schmidt <44101708+5chmidti at users.noreply.github.com>
Date: Fri, 24 Nov 2023 23:49:05 +0100
Subject: [PATCH 5/5] extend `hasOperatorName` instead of adding `hasOperator`
---
clang/docs/LibASTMatchersReference.html | 61 +++++++++++++------
clang/include/clang/ASTMatchers/ASTMatchers.h | 35 ++++-------
.../clang/ASTMatchers/ASTMatchersInternal.h | 3 +
clang/lib/ASTMatchers/Dynamic/Registry.cpp | 1 -
clang/unittests/AST/ASTImporterTest.cpp | 8 +--
.../ASTMatchers/ASTMatchersNarrowingTest.cpp | 8 +--
6 files changed, 68 insertions(+), 48 deletions(-)
diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html
index 7d72e4eb70943f..c40d679e383bb2 100644
--- a/clang/docs/LibASTMatchersReference.html
+++ b/clang/docs/LibASTMatchersReference.html
@@ -2976,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>
@@ -3441,20 +3448,19 @@ <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.
+<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(hasOperator(BO_Add)))
+ (matcher = cxxFoldExpr(hasOperatorName("+")))
template <typename... Args>
auto sum(Args... args) {
return (0 + ... + args);
}
-
- template <typename... Args>
- auto multiply(Args... args) {
- return (args * ... * 1);
- }
</pre></td></tr>
@@ -3696,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>
@@ -3854,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>
@@ -5808,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>
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index ccd72f73480017..65196c52a3e293 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -4678,25 +4678,6 @@ AST_MATCHER(CXXFoldExpr, isUnaryFold) { return Node.getInit() == nullptr; }
/// \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.
@@ -5874,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;
diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
index 7136d0d2fe0845..47d912c73dd7eb 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/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index a37f02056feb29..15dad022df5fe0 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -342,7 +342,6 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasNullSelector);
REGISTER_MATCHER(hasObjectExpression);
REGISTER_MATCHER(hasOperands);
- REGISTER_MATCHER(hasOperator);
REGISTER_MATCHER(hasOperatorName);
REGISTER_MATCHER(hasOverloadedOperatorName);
REGISTER_MATCHER(hasParameter);
diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp
index f5f58de1914747..26095403c5a1a8 100644
--- a/clang/unittests/AST/ASTImporterTest.cpp
+++ b/clang/unittests/AST/ASTImporterTest.cpp
@@ -817,14 +817,14 @@ TEST_P(ImportExpr, ImportSizeOfPackExpr) {
}
TEST_P(ImportExpr, ImportCXXFoldExpr) {
- auto Match1 = cxxFoldExpr(hasOperator(BO_Add), isLeftFold(),
+ auto Match1 = cxxFoldExpr(hasOperatorName("+"), isLeftFold(),
unless(hasFoldInit(expr())));
auto Match2 =
- cxxFoldExpr(hasOperator(BO_Sub), isLeftFold(), hasFoldInit(expr()));
- auto Match3 = cxxFoldExpr(hasOperator(BO_Mul), isRightFold(),
+ cxxFoldExpr(hasOperatorName("-"), isLeftFold(), hasFoldInit(expr()));
+ auto Match3 = cxxFoldExpr(hasOperatorName("*"), isRightFold(),
unless(hasFoldInit(expr())));
auto Match4 =
- cxxFoldExpr(hasOperator(BO_Div), isRightFold(), hasFoldInit(expr()));
+ cxxFoldExpr(hasOperatorName("/"), isRightFold(), hasFoldInit(expr()));
MatchVerifier<Decl> Verifier;
testImport("template <typename... Ts>"
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
index ff107995715c74..edcdae4559d970 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -4186,19 +4186,19 @@ TEST_P(ASTMatchersTest, hasOperator) {
EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { "
"return (0 + ... + args); }",
- cxxFoldExpr(hasOperator(BO_Add))));
+ cxxFoldExpr(hasOperatorName("+"))));
EXPECT_TRUE(matches("template <typename... Args> auto sum(Args... args) { "
"return (... + args); };",
- cxxFoldExpr(hasOperator(BO_Add))));
+ cxxFoldExpr(hasOperatorName("+"))));
EXPECT_FALSE(
matches("template <typename... Args> auto multiply(Args... args) { "
"return (0 * ... * args); }",
- cxxFoldExpr(hasOperator(BO_Add))));
+ cxxFoldExpr(hasOperatorName("+"))));
EXPECT_FALSE(
matches("template <typename... Args> auto multiply(Args... args) { "
"return (... * args); };",
- cxxFoldExpr(hasOperator(BO_Add))));
+ cxxFoldExpr(hasOperatorName("+"))));
}
TEST_P(ASTMatchersTest, IsMain) {
More information about the cfe-commits
mailing list