diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index fcd3114bb5231..c40d679e383bb 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -1629,6 +1629,17 @@
Matches C++17 fold expressions. + +Example matches `(0 + ... + args)`: + template <typename... Args> + auto sum(Args... args) { + return (0 + ... + args); + } +
Matches range-based for statements. @@ -2965,11 +2976,18 @@Narrowing Matchers
- Matcher<BinaryOperator> hasOperatorName std::string Name + Matches the operator Name of operator expressions (binary or -unary). +@@ -3430,6 +3448,91 @@ 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); + }Narrowing Matchers
+ Matcher<CXXFoldExpr> hasOperatorName std::string Name + + + 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); + } ++ Matcher<CXXFoldExpr> isBinaryFold + + + 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 * ...); + } ++ Matcher<CXXFoldExpr> isLeftFold + + + 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); + } ++ Matcher<CXXFoldExpr> isRightFold + + + 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); + } ++ Matcher<CXXFoldExpr> isUnaryFold + + 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 * ...); + } +Matcher<CXXMethodDecl> isConst Matches if the given method declaration is const. @@ -3599,11 +3702,18 @@Narrowing Matchers
- Matcher<CXXOperatorCallExpr> hasOperatorName std::string Name Matches the operator Name of operator expressions (binary or -unary). +@@ -3757,11 +3867,18 @@ 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); + }Narrowing Matchers
- Matcher<CXXRewrittenBinaryOperator> hasOperatorName std::string Name - Matches the operator Name of operator expressions (binary or -unary). +@@ -5711,12 +5828,19 @@ 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); + }Narrowing Matchers
- Matcher<UnaryOperator> hasOperatorName std::string Name Matches the operator Name of operator expressions (binary or -unary). ++ Matcher<UnaryOperator> hasOperatorName std::string Name @@ -6453,7 +6577,7 @@ 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); + }AST Traversal Matchers
Matcher<BinaryOperator> hasEitherOperand Matcher<Expr> InnerMatcher @@ -6466,7 +6590,8 @@ Matches if either the left hand side or the right hand side of a -binary operator matches. +binary operator or fold expression matches.AST Traversal Matchers
- Matcher<BinaryOperator> hasOperands Matcher<Expr> Matcher1, Matcher<Expr> Matcher2 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))) @@ -6885,6 +7010,112 @@AST Traversal Matchers
+ Matcher<CXXFoldExpr> callee Matcher<Stmt> InnerMatcher + + + 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<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. ++ Matcher<CXXFoldExpr> hasEitherOperand Matcher<Expr> InnerMatcher + + + Matches if either the left hand side or the right hand side of a +binary operator or fold expression matches. ++ Matcher<CXXFoldExpr> hasFoldInit ast_matchers::Matcher<Expr> InnerMacher + + + 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); + } ++ Matcher<CXXFoldExpr> hasLHS Matcher<Expr> InnerMatcher + + + Matches the left hand side of binary operator expressions. + +Example matches a (matcher = binaryOperator(hasLHS())) + a || b ++ Matcher<CXXFoldExpr> hasOperands Matcher<Expr> Matcher1, Matcher<Expr> Matcher2 + + + 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 ++ Matcher<CXXFoldExpr> hasPattern ast_matchers::Matcher<Expr> InnerMacher + + + 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); + } ++ Matcher<CXXFoldExpr> hasRHS Matcher<Expr> InnerMatcher + + Matches the right hand side of binary operator expressions. + +Example matches b (matcher = binaryOperator(hasRHS())) + a || b +Matcher<CXXForRangeStmt> hasBody Matcher<Stmt> InnerMatcher 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 @@AST Traversal Matchers
Matcher<CXXOperatorCallExpr> hasEitherOperand Matcher<Expr> InnerMatcher @@ -7192,7 +7423,8 @@ Matches if either the left hand side or the right hand side of a -binary operator matches. +binary operator or fold expression matches.AST Traversal Matchers
- Matcher<CXXOperatorCallExpr> hasOperands Matcher<Expr> Matcher1, Matcher<Expr> Matcher2 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))) @@ -7317,9 +7549,9 @@AST Traversal Matchers
- Matcher<CXXRewrittenBinaryOperator> hasEitherOperand Matcher<Expr> InnerMatcher - Matches if either the left hand side or the right hand side of a -binary operator matches. ++ Matcher<CXXRewrittenBinaryOperator> hasEitherOperand Matcher<Expr> InnerMatcher @@ -7331,8 +7563,9 @@ Matches if either the left hand side or the right hand side of a +binary operator or fold expression matches.AST Traversal Matchers
- Matcher<CXXRewrittenBinaryOperator> hasOperands Matcher<Expr> Matcher1, Matcher<Expr> Matcher2 Matches if both matchers match with opposite sides of the binary operator. ++ Matcher<CXXRewrittenBinaryOperator> hasOperands Matcher<Expr> Matcher1, Matcher<Expr> Matcher2 - 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 @@AST Traversal Matchers
- Matcher<CallExpr> callee Matcher<Decl> InnerMatcher Matches 1) if the call expression's callee's declaration matches the ++ Matcher<CallExpr> callee Matcher<Decl> InnerMatcher 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 @@AST Traversal Matchers
- Matcher<CallExpr> callee Matcher<Stmt> InnerMatcher Matches if the call expression's callee expression matches. +- 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 @@AST Traversal Matchers
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<Expr> because this introduces ambiguous overloads with calls to Callee taking a internal::Matcher<Decl>, as the matcher hierarchy is purely @@ -9087,8 +9335,8 @@AST Traversal Matchers
- Matcher<ObjCMessageExpr> callee Matcher<Decl> InnerMatcher Matches 1) if the call expression's callee's declaration matches the ++ Matcher<ObjCMessageExpr> callee Matcher<Decl> InnerMatcher 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 c2440bc465181..6e31849ce16dd 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 82a26356c58f5..65196c52a3e29 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -2062,6 +2062,18 @@ extern const internal::VariadicDynCastAllOfMatcherextern const internal::VariadicDynCastAllOfMatcher cxxOperatorCallExpr; +/// Matches C++17 fold expressions. +/// +/// Example matches `(0 + ... + args)`: +/// \code +/// template +/// auto sum(Args... args) { +/// return (0 + ... + args); +/// } +/// \endcode +extern const internal::VariadicDynCastAllOfMatcher + 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 +/// auto sum(Args... args) { +/// return (0 + ... + args); +/// } +/// +/// template +/// 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 /// because this introduces ambiguous overloads with calls to Callee taking a /// internal::Matcher , as the matcher hierarchy is purely /// implemented in terms of implicit casts. -AST_MATCHER_P(CallExpr, callee, internal::Matcher , - InnerMatcher) { - const Expr *ExprNode = Node.getCallee(); +AST_POLYMORPHIC_MATCHER_P_OVERLOAD(callee, + AST_POLYMORPHIC_SUPPORTED_TYPES(CallExpr, + CXXFoldExpr), + internal::Matcher , 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 +/// auto sum(Args... args) { +/// return (0 + ... + args); +/// } +/// +/// template +/// auto multiply(Args... args) { +/// return (args * ... * 1); +/// } +/// \endcode +AST_MATCHER_P(CXXFoldExpr, hasFoldInit, ast_matchers::internal::Matcher , + 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 +/// auto sum(Args... args) { +/// return (0 + ... + args); +/// } +/// +/// template +/// auto multiply(Args... args) { +/// return (args * ... * 1); +/// } +/// \endcode +AST_MATCHER_P(CXXFoldExpr, hasPattern, ast_matchers::internal::Matcher , + 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 +/// auto sum(Args... args) { +/// return (0 + ... + args); +/// } +/// +/// template +/// 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 +/// auto sum(Args... args) { +/// return (0 + ... + args); +/// } +/// +/// template +/// 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 +/// auto sum(Args... args) { +/// return (0 + ... + args); +/// } +/// +/// template +/// 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 +/// auto sum(Args... args) { +/// return (0 + ... + args); +/// } +/// +/// template +/// 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 +/// 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 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 , InnerMatcher) { +AST_POLYMORPHIC_MATCHER_P( + hasLHS, + AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, CXXOperatorCallExpr, + CXXRewrittenBinaryOperator, + ArraySubscriptExpr, CXXFoldExpr), + internal::Matcher , 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 , InnerMatcher) { +AST_POLYMORPHIC_MATCHER_P( + hasRHS, + AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, CXXOperatorCallExpr, + CXXRewrittenBinaryOperator, + ArraySubscriptExpr, CXXFoldExpr), + internal::Matcher , 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 , InnerMatcher) { return internal::VariadicDynCastAllOfMatcher ()( 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 , Matcher1, internal::Matcher , Matcher2) { return internal::VariadicDynCastAllOfMatcher ()( anyOf(allOf(hasLHS(Matcher1), hasRHS(Matcher2)), diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h index 7136d0d2fe084..47d912c73dd7e 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -2195,6 +2195,9 @@ inline std::optional 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 8ed213ca2ce09..bf87b1aa0992a 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -893,6 +893,7 @@ const internal::VariadicDynCastAllOfMatcher cxxOperatorCallExpr; const internal::VariadicDynCastAllOfMatcher cxxRewrittenBinaryOperator; +const internal::VariadicDynCastAllOfMatcher cxxFoldExpr; const internal::VariadicDynCastAllOfMatcher expr; const internal::VariadicDynCastAllOfMatcher declRefExpr; const internal::VariadicDynCastAllOfMatcher objcIvarRefExpr; diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp index 2e43dec331b75..15dad022df5fe 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 3d1f4c85c90ad..e3f3a1bef656b 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 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 Verifier; testImport("template " @@ -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 d78676fd289d5..edcdae4559d97 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 auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(isRightFold()))); + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(isRightFold()))); + EXPECT_FALSE(matches("template auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(isRightFold()))); + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (args + ...); };", + cxxFoldExpr(isRightFold()))); +} + +TEST_P(ASTMatchersTest, isLeftFold) { + if (!GetParam().isCXX17OrLater()) { + return; + } + + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(isLeftFold()))); + EXPECT_FALSE(matches("template auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(isLeftFold()))); + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(isLeftFold()))); + EXPECT_FALSE(matches("template 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 auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(isUnaryFold()))); + EXPECT_FALSE(matches("template auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(isUnaryFold()))); + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(isUnaryFold()))); + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (args + ...); };", + cxxFoldExpr(isUnaryFold()))); +} + +TEST_P(ASTMatchersTest, isBinaryFold) { + if (!GetParam().isCXX17OrLater()) { + return; + } + + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(isBinaryFold()))); + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(isBinaryFold()))); + EXPECT_FALSE(matches("template auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(isBinaryFold()))); + EXPECT_FALSE(matches("template auto sum(Args... args) { " + "return (args + ...); };", + cxxFoldExpr(isBinaryFold()))); +} + +TEST_P(ASTMatchersTest, hasOperator) { + if (!GetParam().isCXX17OrLater()) { + return; + } + + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(hasOperatorName("+")))); + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(hasOperatorName("+")))); + + EXPECT_FALSE( + matches("template auto multiply(Args... args) { " + "return (0 * ... * args); }", + cxxFoldExpr(hasOperatorName("+")))); + EXPECT_FALSE( + matches("template 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 8f0dd5602307c..ae30c03126d76 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 auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr())); + EXPECT_TRUE(matches("template 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 d4a695b974bf0..6911d7600a718 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 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 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 @@ -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 auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(hasFoldInit(expr())))); + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(hasFoldInit(expr())))); + EXPECT_FALSE(matches("template auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(hasFoldInit(expr())))); +} + +TEST_P(ASTMatchersTest, HasPattern) { + if (!GetParam().isCXX17OrLater()) { + return; + } + + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(hasPattern(expr())))); + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(hasPattern(expr())))); + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(hasPattern(expr())))); +} + +TEST_P(ASTMatchersTest, HasLHSAndHasRHS) { + if (!GetParam().isCXX17OrLater()) { + return; + } + + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(hasLHS(expr())))); + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(hasLHS(expr())))); + EXPECT_FALSE(matches("template auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(hasLHS(expr())))); + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (args + ...); };", + cxxFoldExpr(hasLHS(expr())))); + + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(hasRHS(expr())))); + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(hasRHS(expr())))); + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(hasRHS(expr())))); + EXPECT_FALSE(matches("template auto sum(Args... args) { " + "return (args + ...); };", + cxxFoldExpr(hasRHS(expr())))); +} + +TEST_P(ASTMatchersTest, HasEitherOperandAndHasOperands) { + if (!GetParam().isCXX17OrLater()) { + return; + } + + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(hasEitherOperand(integerLiteral())))); + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(hasEitherOperand(integerLiteral())))); + + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(hasEitherOperand( + declRefExpr(to(namedDecl(hasName("args")))))))); + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(hasEitherOperand( + declRefExpr(to(namedDecl(hasName("args")))))))); + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(hasEitherOperand( + declRefExpr(to(namedDecl(hasName("args")))))))); + EXPECT_TRUE(matches("template auto sum(Args... args) { " + "return (args + ...); };", + cxxFoldExpr(hasEitherOperand( + declRefExpr(to(namedDecl(hasName("args")))))))); + + EXPECT_TRUE(matches( + "template auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(hasOperands(declRefExpr(to(namedDecl(hasName("args")))), + integerLiteral())))); + EXPECT_TRUE(matches( + "template auto sum(Args... args) { " + "return (args + ... + 0); }", + cxxFoldExpr(hasOperands(declRefExpr(to(namedDecl(hasName("args")))), + integerLiteral())))); + EXPECT_FALSE(matches( + "template auto sum(Args... args) { " + "return (... + args); };", + cxxFoldExpr(hasOperands(declRefExpr(to(namedDecl(hasName("args")))), + integerLiteral())))); + EXPECT_FALSE(matches( + "template 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 " + " auto sum(Args... args) { return (0 + ... + args); }", + cxxFoldExpr(callee(expr())))); + EXPECT_FALSE(matches("template auto sum(Args... args) { " + "return (0 + ... + args); }", + cxxFoldExpr(callee(expr())))); +} + TEST(ArraySubscriptMatchers, ArrayIndex) { EXPECT_TRUE(matches( "int i[2]; void f() { i[1] = 1; }",