Skip to content

[clang][ASTMatcher] Add matchers for CXXFoldExpr #71245

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
294 changes: 271 additions & 23 deletions clang/docs/LibASTMatchersReference.html

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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``, ``hasEitherOperand``.

clang-format
------------
Expand Down
201 changes: 180 additions & 21 deletions clang/include/clang/ASTMatchers/ASTMatchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 "<":
Expand Down Expand Up @@ -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
Expand All @@ -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));
}
Expand Down Expand Up @@ -4532,6 +4563,121 @@ AST_POLYMORPHIC_MATCHER_P2(hasArgument,
return InnerMatcher.matches(*Arg->IgnoreParenImpCasts(), Finder, Builder);
}

/// Matches the operand that does not contain the parameter pack.
///
/// Example matches `(0 + ... + args)` and `(args * ... * 1)`
/// (matcher = cxxFoldExpr(hasFoldInit(expr())))
/// with hasFoldInit(...)
/// matching `0` and `1` respectively
/// \code
/// template <typename... Args>
/// auto sum(Args... args) {
/// return (0 + ... + args);
/// }
///
/// template <typename... Args>
/// auto multiply(Args... args) {
/// return (args * ... * 1);
/// }
/// \endcode
AST_MATCHER_P(CXXFoldExpr, hasFoldInit, ast_matchers::internal::Matcher<Expr>,
InnerMacher) {
const auto *const Init = Node.getInit();
return Init && InnerMacher.matches(*Init, Finder, Builder);
}

/// Matches the operand that contains the parameter pack.
///
/// Example matches `(0 + ... + args)`
/// (matcher = cxxFoldExpr(hasPattern(expr())))
/// with hasPattern(...)
/// matching `args`
/// \code
/// template <typename... Args>
/// auto sum(Args... args) {
/// return (0 + ... + args);
/// }
///
/// template <typename... Args>
/// auto multiply(Args... args) {
/// return (args * ... * 1);
/// }
/// \endcode
AST_MATCHER_P(CXXFoldExpr, hasPattern, ast_matchers::internal::Matcher<Expr>,
InnerMacher) {
const Expr *const Pattern = Node.getPattern();
return Pattern && InnerMacher.matches(*Pattern, Finder, Builder);
}

/// Matches right-folding fold expressions.
///
/// Example matches `(args * ... * 1)`
/// (matcher = cxxFoldExpr(isRightFold()))
/// \code
/// template <typename... Args>
/// auto sum(Args... args) {
/// return (0 + ... + args);
/// }
///
/// template <typename... Args>
/// auto multiply(Args... args) {
/// return (args * ... * 1);
/// }
/// \endcode
AST_MATCHER(CXXFoldExpr, isRightFold) { return Node.isRightFold(); }

/// Matches left-folding fold expressions.
///
/// Example matches `(0 + ... + args)`
/// (matcher = cxxFoldExpr(isLeftFold()))
/// \code
/// template <typename... Args>
/// auto sum(Args... args) {
/// return (0 + ... + args);
/// }
///
/// template <typename... Args>
/// auto multiply(Args... args) {
/// return (args * ... * 1);
/// }
/// \endcode
AST_MATCHER(CXXFoldExpr, isLeftFold) { return Node.isLeftFold(); }

/// Matches unary fold expressions, i.e. fold expressions without an
/// initializer.
///
/// Example matches `(args * ...)`
/// (matcher = cxxFoldExpr(isUnaryFold()))
/// \code
/// template <typename... Args>
/// auto sum(Args... args) {
/// return (0 + ... + args);
/// }
///
/// template <typename... Args>
/// auto multiply(Args... args) {
/// return (args * ...);
/// }
/// \endcode
AST_MATCHER(CXXFoldExpr, isUnaryFold) { return Node.getInit() == nullptr; }

/// Matches binary fold expressions, i.e. fold expressions with an initializer.
///
/// Example matches `(0 + ... + args)`
/// (matcher = cxxFoldExpr(isBinaryFold()))
/// \code
/// template <typename... Args>
/// auto sum(Args... args) {
/// return (0 + ... + args);
/// }
///
/// template <typename... Args>
/// auto multiply(Args... args) {
/// return (args * ...);
/// }
/// \endcode
AST_MATCHER(CXXFoldExpr, isBinaryFold) { return Node.getInit() != nullptr; }

/// Matches the n'th item of an initializer list expression.
///
/// Example matches y.
Expand Down Expand Up @@ -5709,17 +5855,27 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(equals,
.matchesNode(Node);
}

/// Matches the operator Name of operator expressions (binary or
/// unary).
/// Matches the operator Name of operator expressions and fold expressions
/// (binary or unary).
///
/// Example matches a || b (matcher = binaryOperator(hasOperatorName("||")))
/// \code
/// !(a || b)
/// \endcode
///
/// Example matches `(0 + ... + args)`
/// (matcher = cxxFoldExpr(hasOperatorName("+")))
/// \code
/// template <typename... Args>
/// auto sum(Args... args) {
/// return (0 + ... + args);
/// }
/// \endcode
AST_POLYMORPHIC_MATCHER_P(
hasOperatorName,
AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, CXXOperatorCallExpr,
CXXRewrittenBinaryOperator, UnaryOperator),
CXXRewrittenBinaryOperator, CXXFoldExpr,
UnaryOperator),
std::string, Name) {
if (std::optional<StringRef> OpName = internal::getOpName(Node))
return *OpName == Name;
Expand Down Expand Up @@ -5789,11 +5945,12 @@ AST_POLYMORPHIC_MATCHER(
/// \code
/// a || b
/// \endcode
AST_POLYMORPHIC_MATCHER_P(hasLHS,
AST_POLYMORPHIC_SUPPORTED_TYPES(
BinaryOperator, CXXOperatorCallExpr,
CXXRewrittenBinaryOperator, ArraySubscriptExpr),
internal::Matcher<Expr>, InnerMatcher) {
AST_POLYMORPHIC_MATCHER_P(
hasLHS,
AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, CXXOperatorCallExpr,
CXXRewrittenBinaryOperator,
ArraySubscriptExpr, CXXFoldExpr),
internal::Matcher<Expr>, InnerMatcher) {
const Expr *LeftHandSide = internal::getLHS(Node);
return (LeftHandSide != nullptr &&
InnerMatcher.matches(*LeftHandSide, Finder, Builder));
Expand All @@ -5805,29 +5962,31 @@ AST_POLYMORPHIC_MATCHER_P(hasLHS,
/// \code
/// a || b
/// \endcode
AST_POLYMORPHIC_MATCHER_P(hasRHS,
AST_POLYMORPHIC_SUPPORTED_TYPES(
BinaryOperator, CXXOperatorCallExpr,
CXXRewrittenBinaryOperator, ArraySubscriptExpr),
internal::Matcher<Expr>, InnerMatcher) {
AST_POLYMORPHIC_MATCHER_P(
hasRHS,
AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, CXXOperatorCallExpr,
CXXRewrittenBinaryOperator,
ArraySubscriptExpr, CXXFoldExpr),
internal::Matcher<Expr>, InnerMatcher) {
const Expr *RightHandSide = internal::getRHS(Node);
return (RightHandSide != nullptr &&
InnerMatcher.matches(*RightHandSide, Finder, Builder));
}

/// Matches if either the left hand side or the right hand side of a
/// binary operator matches.
/// binary operator or fold expression matches.
AST_POLYMORPHIC_MATCHER_P(
hasEitherOperand,
AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, CXXOperatorCallExpr,
CXXRewrittenBinaryOperator),
CXXFoldExpr, CXXRewrittenBinaryOperator),
internal::Matcher<Expr>, InnerMatcher) {
return internal::VariadicDynCastAllOfMatcher<Stmt, NodeType>()(
anyOf(hasLHS(InnerMatcher), hasRHS(InnerMatcher)))
.matches(Node, Finder, Builder);
}

/// Matches if both matchers match with opposite sides of the binary operator.
/// Matches if both matchers match with opposite sides of the binary operator
/// or fold expression.
///
/// Example matcher = binaryOperator(hasOperands(integerLiteral(equals(1),
/// integerLiteral(equals(2)))
Expand All @@ -5840,7 +5999,7 @@ AST_POLYMORPHIC_MATCHER_P(
AST_POLYMORPHIC_MATCHER_P2(
hasOperands,
AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, CXXOperatorCallExpr,
CXXRewrittenBinaryOperator),
CXXFoldExpr, CXXRewrittenBinaryOperator),
internal::Matcher<Expr>, Matcher1, internal::Matcher<Expr>, Matcher2) {
return internal::VariadicDynCastAllOfMatcher<Stmt, NodeType>()(
anyOf(allOf(hasLHS(Matcher1), hasRHS(Matcher2)),
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/ASTMatchers/ASTMatchersInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down
1 change: 1 addition & 0 deletions clang/lib/ASTMatchers/ASTMatchersInternal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/ASTMatchers/Dynamic/Registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand Down
Loading