[clang-tools-extra] c0199b2 - [clang-tidy] Use new mapping matchers

Stephen Kelly via cfe-commits cfe-commits at lists.llvm.org
Wed Feb 3 15:21:35 PST 2021


Author: Stephen Kelly
Date: 2021-02-03T23:21:17Z
New Revision: c0199b2a21705747c999a59bfa77d7fc6e4500a5

URL: https://github.com/llvm/llvm-project/commit/c0199b2a21705747c999a59bfa77d7fc6e4500a5
DIFF: https://github.com/llvm/llvm-project/commit/c0199b2a21705747c999a59bfa77d7fc6e4500a5.diff

LOG: [clang-tidy] Use new mapping matchers

Use mapAnyOf() and matchers based on it.

Use of binaryOperation() means that modernize-loop-convert and
readability-container-size-empty can now be used with rewritten binary
operators.

Differential Revision: https://reviews.llvm.org/D94131

Added: 
    clang-tools-extra/test/clang-tidy/checkers/modernize-loop-convert-rewritten-binop.cpp
    clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty-cxx20.cpp

Modified: 
    clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
    clang-tools-extra/clang-tidy/bugprone/SpuriouslyWakeUpFunctionsCheck.cpp
    clang-tools-extra/clang-tidy/bugprone/SuspiciousStringCompareCheck.cpp
    clang-tools-extra/clang-tidy/bugprone/UnhandledSelfAssignmentCheck.cpp
    clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
    clang-tools-extra/clang-tidy/cert/MutatingCopyCheck.cpp
    clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidGotoCheck.cpp
    clang-tools-extra/clang-tidy/llvm/PreferIsaOrDynCastInConditionalsCheck.cpp
    clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
    clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp
    clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.cpp
    clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
    clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
    clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
index bf1b51049c2c..777d309b5ccb 100644
--- a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
@@ -21,9 +21,9 @@ namespace bugprone {
 
 static internal::Matcher<Stmt>
 loopEndingStmt(internal::Matcher<Stmt> Internal) {
-  return stmt(anyOf(breakStmt(Internal), returnStmt(Internal),
-                    gotoStmt(Internal), cxxThrowExpr(Internal),
-                    callExpr(Internal, callee(functionDecl(isNoReturn())))));
+  return stmt(anyOf(
+      mapAnyOf(breakStmt, returnStmt, gotoStmt, cxxThrowExpr).with(Internal),
+      callExpr(Internal, callee(functionDecl(isNoReturn())))));
 }
 
 /// Return whether `Var` was changed in `LoopStmt`.
@@ -122,8 +122,8 @@ void InfiniteLoopCheck::registerMatchers(MatchFinder *Finder) {
       unless(hasBody(hasDescendant(
           loopEndingStmt(forFunction(equalsBoundNode("func")))))));
 
-  Finder->addMatcher(stmt(anyOf(whileStmt(LoopCondition), doStmt(LoopCondition),
-                                forStmt(LoopCondition)))
+  Finder->addMatcher(mapAnyOf(whileStmt, doStmt, forStmt)
+                         .with(LoopCondition)
                          .bind("loop-stmt"),
                      this);
 }

diff  --git a/clang-tools-extra/clang-tidy/bugprone/SpuriouslyWakeUpFunctionsCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SpuriouslyWakeUpFunctionsCheck.cpp
index 1a9bea6a5fc8..ee45461ed8f2 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SpuriouslyWakeUpFunctionsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SpuriouslyWakeUpFunctionsCheck.cpp
@@ -59,34 +59,20 @@ void SpuriouslyWakeUpFunctionsCheck::registerMatchers(MatchFinder *Finder) {
   if (getLangOpts().CPlusPlus) {
     // Check for `CON54-CPP`
     Finder->addMatcher(
-        ifStmt(
-            allOf(HasWaitDescendantCpp,
-                  unless(anyOf(hasDescendant(ifStmt(HasWaitDescendantCpp)),
-                               hasDescendant(whileStmt(HasWaitDescendantCpp)),
-                               hasDescendant(forStmt(HasWaitDescendantCpp)),
-                               hasDescendant(doStmt(HasWaitDescendantCpp)))))
-
-                ),
+        ifStmt(HasWaitDescendantCpp,
+               unless(hasDescendant(mapAnyOf(ifStmt, whileStmt, forStmt, doStmt)
+                                        .with(HasWaitDescendantCpp)))),
         this);
   } else {
     // Check for `CON36-C`
     Finder->addMatcher(
-        ifStmt(
-            allOf(HasWaitDescendantC,
-                  unless(anyOf(hasDescendant(ifStmt(HasWaitDescendantC)),
-                               hasDescendant(whileStmt(HasWaitDescendantC)),
-                               hasDescendant(forStmt(HasWaitDescendantC)),
-                               hasDescendant(doStmt(HasWaitDescendantC)),
-                               hasParent(whileStmt()),
-                               hasParent(compoundStmt(hasParent(whileStmt()))),
-                               hasParent(forStmt()),
-                               hasParent(compoundStmt(hasParent(forStmt()))),
-                               hasParent(doStmt()),
-                               hasParent(compoundStmt(hasParent(doStmt())))))
-
-                      ))
-
-            ,
+        ifStmt(HasWaitDescendantC,
+               unless(anyOf(
+                   hasDescendant(mapAnyOf(ifStmt, whileStmt, forStmt, doStmt)
+                                     .with(HasWaitDescendantC)),
+                   hasParent(mapAnyOf(whileStmt, forStmt, doStmt)),
+                   hasParent(compoundStmt(
+                       hasParent(mapAnyOf(whileStmt, forStmt, doStmt))))))),
         this);
   }
 }

diff  --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousStringCompareCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SuspiciousStringCompareCheck.cpp
index b234c3d128ed..a99492d29d5f 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousStringCompareCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousStringCompareCheck.cpp
@@ -113,10 +113,8 @@ void SuspiciousStringCompareCheck::registerMatchers(MatchFinder *Finder) {
     // Detect suspicious calls to string compare:
     //     'if (strcmp())'  ->  'if (strcmp() != 0)'
     Finder->addMatcher(
-        stmt(anyOf(ifStmt(hasCondition(StringCompareCallExpr)),
-                   whileStmt(hasCondition(StringCompareCallExpr)),
-                   doStmt(hasCondition(StringCompareCallExpr)),
-                   forStmt(hasCondition(StringCompareCallExpr)),
+        stmt(anyOf(mapAnyOf(ifStmt, whileStmt, doStmt, forStmt)
+                       .with(hasCondition(StringCompareCallExpr)),
                    binaryOperator(hasAnyOperatorName("&&", "||"),
                                   hasEitherOperand(StringCompareCallExpr))))
             .bind("missing-comparison"),

diff  --git a/clang-tools-extra/clang-tidy/bugprone/UnhandledSelfAssignmentCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnhandledSelfAssignmentCheck.cpp
index 7539b51ebd12..bf4bb750da02 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UnhandledSelfAssignmentCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UnhandledSelfAssignmentCheck.cpp
@@ -40,12 +40,9 @@ void UnhandledSelfAssignmentCheck::registerMatchers(MatchFinder *Finder) {
 
   // Self-check: Code compares something with 'this' pointer. We don't check
   // whether it is actually the parameter what we compare.
-  const auto HasNoSelfCheck = cxxMethodDecl(unless(anyOf(
-      hasDescendant(binaryOperator(hasAnyOperatorName("==", "!="),
-                                   has(ignoringParenCasts(cxxThisExpr())))),
-      hasDescendant(cxxOperatorCallExpr(
-          hasAnyOverloadedOperatorName("==", "!="), argumentCountIs(2),
-          has(ignoringParenCasts(cxxThisExpr())))))));
+  const auto HasNoSelfCheck = cxxMethodDecl(unless(hasDescendant(
+      binaryOperation(hasAnyOperatorName("==", "!="),
+                      hasEitherOperand(ignoringParenCasts(cxxThisExpr()))))));
 
   // Both copy-and-swap and copy-and-move method creates a copy first and
   // assign it to 'this' with swap or move.

diff  --git a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
index 6c8a9742c9a5..028fefa9b99e 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp
@@ -310,9 +310,7 @@ void UseAfterMoveFinder::getReinits(
                // Assignment. In addition to the overloaded assignment operator,
                // test for built-in assignment as well, since template functions
                // may be instantiated to use std::move() on built-in types.
-               binaryOperator(hasOperatorName("="), hasLHS(DeclRefMatcher)),
-               cxxOperatorCallExpr(hasOverloadedOperatorName("="),
-                                   hasArgument(0, DeclRefMatcher)),
+               binaryOperation(hasOperatorName("="), hasLHS(DeclRefMatcher)),
                // Declaration. We treat this as a type of reinitialization too,
                // so we don't need to treat it separately.
                declStmt(hasDescendant(equalsNode(MovedVariable))),

diff  --git a/clang-tools-extra/clang-tidy/cert/MutatingCopyCheck.cpp b/clang-tools-extra/clang-tidy/cert/MutatingCopyCheck.cpp
index fa6e82c1c12b..d4ce995d61b6 100644
--- a/clang-tools-extra/clang-tidy/cert/MutatingCopyCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cert/MutatingCopyCheck.cpp
@@ -30,12 +30,8 @@ void MutatingCopyCheck::registerMatchers(MatchFinder *Finder) {
             MemberExprOrSourceObject);
 
   const auto IsSourceMutatingAssignment = traverse(
-      TK_AsIs,
-      expr(anyOf(binaryOperator(isAssignmentOperator(), hasLHS(IsPartOfSource))
-                     .bind(MutatingOperatorName),
-                 cxxOperatorCallExpr(isAssignmentOperator(),
-                                     hasArgument(0, IsPartOfSource))
-                     .bind(MutatingOperatorName))));
+      TK_AsIs, binaryOperation(hasOperatorName("="), hasLHS(IsPartOfSource))
+                   .bind(MutatingOperatorName));
 
   const auto MemberExprOrSelf = anyOf(memberExpr(), cxxThisExpr());
 
@@ -43,9 +39,7 @@ void MutatingCopyCheck::registerMatchers(MatchFinder *Finder) {
       unless(hasDescendant(expr(unless(MemberExprOrSelf)))), MemberExprOrSelf);
 
   const auto IsSelfMutatingAssignment =
-      expr(anyOf(binaryOperator(isAssignmentOperator(), hasLHS(IsPartOfSelf)),
-                 cxxOperatorCallExpr(isAssignmentOperator(),
-                                     hasArgument(0, IsPartOfSelf))));
+      binaryOperation(isAssignmentOperator(), hasLHS(IsPartOfSelf));
 
   const auto IsSelfMutatingMemberFunction =
       functionDecl(hasBody(hasDescendant(IsSelfMutatingAssignment)));

diff  --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidGotoCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidGotoCheck.cpp
index cf3a16a4dd7d..bd0d1ac32313 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidGotoCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/AvoidGotoCheck.cpp
@@ -29,10 +29,8 @@ void AvoidGotoCheck::registerMatchers(MatchFinder *Finder) {
 
   // Check if the 'goto' is used for control flow other than jumping
   // out of a nested loop.
-  auto Loop = stmt(anyOf(forStmt(), cxxForRangeStmt(), whileStmt(), doStmt()));
-  auto NestedLoop =
-      stmt(anyOf(forStmt(hasAncestor(Loop)), cxxForRangeStmt(hasAncestor(Loop)),
-                 whileStmt(hasAncestor(Loop)), doStmt(hasAncestor(Loop))));
+  auto Loop = mapAnyOf(forStmt, cxxForRangeStmt, whileStmt, doStmt);
+  auto NestedLoop = Loop.with(hasAncestor(Loop));
 
   Finder->addMatcher(gotoStmt(anyOf(unless(hasAncestor(NestedLoop)),
                                     unless(isForwardJumping())))

diff  --git a/clang-tools-extra/clang-tidy/llvm/PreferIsaOrDynCastInConditionalsCheck.cpp b/clang-tools-extra/clang-tidy/llvm/PreferIsaOrDynCastInConditionalsCheck.cpp
index 132178f892ea..201c8d23dd4d 100644
--- a/clang-tools-extra/clang-tidy/llvm/PreferIsaOrDynCastInConditionalsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/llvm/PreferIsaOrDynCastInConditionalsCheck.cpp
@@ -47,8 +47,9 @@ void PreferIsaOrDynCastInConditionalsCheck::registerMatchers(
               allOf(callee(namedDecl(hasAnyName("isa", "cast", "cast_or_null",
                                                 "dyn_cast", "dyn_cast_or_null"))
                                .bind("func")),
-                    hasArgument(0, anyOf(declRefExpr().bind("arg"),
-                                         cxxMemberCallExpr().bind("arg"))))))
+                    hasArgument(
+                        0,
+                        mapAnyOf(declRefExpr, cxxMemberCallExpr).bind("arg")))))
           .bind("rhs");
 
   Finder->addMatcher(

diff  --git a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
index c017cac5b4c8..e6b7c1f6025e 100644
--- a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp
@@ -188,11 +188,6 @@ StatementMatcher makeIteratorLoopMatcher(bool IsReverse) {
   StatementMatcher IteratorComparisonMatcher = expr(
       ignoringParenImpCasts(declRefExpr(to(varDecl().bind(ConditionVarName)))));
 
-  auto OverloadedNEQMatcher = ignoringImplicit(
-      cxxOperatorCallExpr(hasOverloadedOperatorName("!="), argumentCountIs(2),
-                          hasArgument(0, IteratorComparisonMatcher),
-                          hasArgument(1, IteratorBoundMatcher)));
-
   // This matcher tests that a declaration is a CXXRecordDecl that has an
   // overloaded operator*(). If the operator*() returns by value instead of by
   // reference then the return type is tagged with DerefByValueResultName.
@@ -216,14 +211,9 @@ StatementMatcher makeIteratorLoopMatcher(bool IsReverse) {
                                         containsDeclaration(0, InitDeclMatcher),
                                         containsDeclaration(1, EndDeclMatcher)),
                                declStmt(hasSingleDecl(InitDeclMatcher)))),
-             hasCondition(
-                 anyOf(binaryOperator(hasOperatorName("!="),
-                                      hasLHS(IteratorComparisonMatcher),
-                                      hasRHS(IteratorBoundMatcher)),
-                       binaryOperator(hasOperatorName("!="),
-                                      hasLHS(IteratorBoundMatcher),
-                                      hasRHS(IteratorComparisonMatcher)),
-                       OverloadedNEQMatcher)),
+             hasCondition(ignoringImplicit(binaryOperation(
+                 hasOperatorName("!="), hasOperands(IteratorComparisonMatcher,
+                                                    IteratorBoundMatcher)))),
              hasIncrement(anyOf(
                  unaryOperator(hasOperatorName("++"),
                                hasUnaryOperand(declRefExpr(

diff  --git a/clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp
index 9b91d181ba01..5c79e860244a 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp
@@ -183,15 +183,10 @@ static bool isCopyAssignmentAndCanBeDefaulted(ASTContext *Context,
     auto LHS = memberExpr(hasObjectExpression(cxxThisExpr()),
                           member(fieldDecl(equalsNode(Field))));
     auto RHS = accessToFieldInVar(Field, Param);
-    if (match(
-            traverse(TK_AsIs,
-                     compoundStmt(has(ignoringParenImpCasts(stmt(anyOf(
-                         binaryOperator(hasOperatorName("="), hasLHS(LHS),
-                                        hasRHS(RHS)),
-                         cxxOperatorCallExpr(
-                             hasOverloadedOperatorName("="), argumentCountIs(2),
-                             hasArgument(0, LHS), hasArgument(1, RHS)))))))),
-            *Compound, *Context)
+    if (match(traverse(TK_AsIs,
+                       compoundStmt(has(ignoringParenImpCasts(binaryOperation(
+                           hasOperatorName("="), hasLHS(LHS), hasRHS(RHS)))))),
+              *Compound, *Context)
             .empty())
       return false;
   }

diff  --git a/clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.cpp b/clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.cpp
index 7ff13fe2823d..e946a1f39fe9 100644
--- a/clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.cpp
+++ b/clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.cpp
@@ -47,13 +47,11 @@ void MoveConstArgCheck::registerMatchers(MatchFinder *Finder) {
 
   Finder->addMatcher(MoveCallMatcher, this);
 
-  auto ConstParamMatcher = forEachArgumentWithParam(
-      MoveCallMatcher, parmVarDecl(hasType(references(isConstQualified()))));
-
-  Finder->addMatcher(callExpr(ConstParamMatcher).bind("receiving-expr"), this);
   Finder->addMatcher(
-      traverse(TK_AsIs,
-               cxxConstructExpr(ConstParamMatcher).bind("receiving-expr")),
+      invocation(forEachArgumentWithParam(
+                     MoveCallMatcher,
+                     parmVarDecl(hasType(references(isConstQualified())))))
+          .bind("receiving-expr"),
       this);
 }
 

diff  --git a/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp b/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
index e7c5f0ab05be..cd5e18913214 100644
--- a/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp
@@ -56,26 +56,23 @@ AST_MATCHER(Expr, usedInBooleanContext) {
   const char *ExprName = "__booleanContextExpr";
   auto Result =
       expr(expr().bind(ExprName),
-           anyOf(hasParent(varDecl(hasType(booleanType()))),
+           anyOf(hasParent(
+                     mapAnyOf(varDecl, fieldDecl).with(hasType(booleanType()))),
                  hasParent(cxxConstructorDecl(
                      hasAnyConstructorInitializer(cxxCtorInitializer(
                          withInitializer(expr(equalsBoundNode(ExprName))),
                          forField(hasType(booleanType())))))),
-                 hasParent(fieldDecl(hasType(booleanType()))),
                  hasParent(stmt(anyOf(
                      explicitCastExpr(hasDestinationType(booleanType())),
-                     ifStmt(hasCondition(expr(equalsBoundNode(ExprName)))),
-                     doStmt(hasCondition(expr(equalsBoundNode(ExprName)))),
-                     whileStmt(hasCondition(expr(equalsBoundNode(ExprName)))),
-                     forStmt(hasCondition(expr(equalsBoundNode(ExprName)))),
-                     conditionalOperator(
-                         hasCondition(expr(equalsBoundNode(ExprName)))),
+                     mapAnyOf(ifStmt, doStmt, whileStmt, forStmt,
+                              conditionalOperator)
+                         .with(hasCondition(expr(equalsBoundNode(ExprName)))),
                      parenListExpr(hasParent(varDecl(hasType(booleanType())))),
                      parenExpr(hasParent(
                          explicitCastExpr(hasDestinationType(booleanType())))),
                      returnStmt(forFunction(returns(booleanType()))),
                      cxxUnresolvedConstructExpr(hasType(booleanType())),
-                     callExpr(hasAnyArgumentWithParam(
+                     invocation(hasAnyArgumentWithParam(
                          expr(equalsBoundNode(ExprName)),
                          parmVarDecl(hasType(booleanType())))),
                      binaryOperator(hasAnyOperatorName("&&", "||")),
@@ -181,21 +178,12 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
                     expr(hasType(pointsTo(ValidContainer))).bind("Pointee"))),
             expr(hasType(ValidContainer)).bind("STLObject"));
   Finder->addMatcher(
-      cxxOperatorCallExpr(
-          unless(isInTemplateInstantiation()),
-          hasAnyOverloadedOperatorName("==", "!="),
-          anyOf(allOf(hasArgument(0, WrongComparend), hasArgument(1, STLArg)),
-                allOf(hasArgument(0, STLArg), hasArgument(1, WrongComparend))),
-          unless(hasAncestor(
-              cxxMethodDecl(ofClass(equalsBoundNode("container"))))))
-          .bind("BinCmp"),
-      this);
-  Finder->addMatcher(
-      binaryOperator(hasAnyOperatorName("==", "!="),
-                     anyOf(allOf(hasLHS(WrongComparend), hasRHS(STLArg)),
-                           allOf(hasLHS(STLArg), hasRHS(WrongComparend))),
-                     unless(hasAncestor(
-                         cxxMethodDecl(ofClass(equalsBoundNode("container"))))))
+      binaryOperation(unless(isInTemplateInstantiation()),
+                      hasAnyOperatorName("==", "!="),
+                      hasOperands(ignoringParenImpCasts(WrongComparend),
+                                  ignoringParenImpCasts(STLArg)),
+                      unless(hasAncestor(cxxMethodDecl(
+                          ofClass(equalsBoundNode("container"))))))
           .bind("BinCmp"),
       this);
 }
@@ -206,6 +194,8 @@ void ContainerSizeEmptyCheck::check(const MatchFinder::MatchResult &Result) {
       Result.Nodes.getNodeAs<Expr>("MemberCallObject");
   const auto *BinCmp = Result.Nodes.getNodeAs<CXXOperatorCallExpr>("BinCmp");
   const auto *BinCmpTempl = Result.Nodes.getNodeAs<BinaryOperator>("BinCmp");
+  const auto *BinCmpRewritten =
+      Result.Nodes.getNodeAs<CXXRewrittenBinaryOperator>("BinCmp");
   const auto *BinaryOp = Result.Nodes.getNodeAs<BinaryOperator>("SizeBinaryOp");
   const auto *Pointee = Result.Nodes.getNodeAs<Expr>("Pointee");
   const auto *E =
@@ -236,6 +226,12 @@ void ContainerSizeEmptyCheck::check(const MatchFinder::MatchResult &Result) {
     }
     Hint = FixItHint::CreateReplacement(BinCmpTempl->getSourceRange(),
                                         ReplacementText);
+  } else if (BinCmpRewritten) {
+    if (BinCmpRewritten->getOpcode() == BinaryOperatorKind::BO_NE) {
+      ReplacementText = "!" + ReplacementText;
+    }
+    Hint = FixItHint::CreateReplacement(BinCmpRewritten->getSourceRange(),
+                                        ReplacementText);
   } else if (BinaryOp) { // Determine the correct transformation.
     bool Negation = false;
     const bool ContainerIsLHS =
@@ -313,8 +309,11 @@ void ContainerSizeEmptyCheck::check(const MatchFinder::MatchResult &Result) {
                   "for emptiness instead of 'size'")
         << Hint;
   } else {
-    WarnLoc = BinCmpTempl ? BinCmpTempl->getBeginLoc()
-                          : (BinCmp ? BinCmp->getBeginLoc() : SourceLocation{});
+    WarnLoc = BinCmpTempl
+                  ? BinCmpTempl->getBeginLoc()
+                  : (BinCmp ? BinCmp->getBeginLoc()
+                            : (BinCmpRewritten ? BinCmpRewritten->getBeginLoc()
+                                               : SourceLocation{}));
     diag(WarnLoc, "the 'empty' method should be used to check "
                   "for emptiness instead of comparing to an empty object")
         << Hint;

diff  --git a/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
index bd1d8c30bc90..9e336cb4cf15 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantControlFlowCheck.cpp
@@ -37,11 +37,10 @@ void RedundantControlFlowCheck::registerMatchers(MatchFinder *Finder) {
           has(compoundStmt(hasAnySubstatement(returnStmt(unless(has(expr())))))
                   .bind("return"))),
       this);
-  auto CompoundContinue =
-      has(compoundStmt(hasAnySubstatement(continueStmt())).bind("continue"));
   Finder->addMatcher(
-      stmt(anyOf(forStmt(), cxxForRangeStmt(), whileStmt(), doStmt()),
-           CompoundContinue),
+      mapAnyOf(forStmt, cxxForRangeStmt, whileStmt, doStmt)
+          .with(hasBody(compoundStmt(hasAnySubstatement(continueStmt()))
+                            .bind("continue"))),
       this);
 }
 

diff  --git a/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp b/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
index 10d2b24a9677..38122d5420ac 100644
--- a/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
+++ b/clang-tools-extra/clang-tidy/utils/DeclRefExprUtils.cpp
@@ -66,10 +66,7 @@ constReferenceDeclRefExprs(const VarDecl &VarDecl, const Stmt &Stmt,
       substTemplateTypeParmType(hasReplacementType(ConstReferenceOrValue))));
   auto UsedAsConstRefOrValueArg = forEachArgumentWithParam(
       DeclRefToVar, parmVarDecl(hasType(ConstReferenceOrValueOrReplaced)));
-  Matches = match(findAll(callExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
-  extractNodesByIdTo(Matches, "declRef", DeclRefs);
-  Matches =
-      match(findAll(cxxConstructExpr(UsedAsConstRefOrValueArg)), Stmt, Context);
+  Matches = match(findAll(invocation(UsedAsConstRefOrValueArg)), Stmt, Context);
   extractNodesByIdTo(Matches, "declRef", DeclRefs);
   // References and pointers to const assignments.
   Matches =

diff  --git a/clang-tools-extra/test/clang-tidy/checkers/modernize-loop-convert-rewritten-binop.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize-loop-convert-rewritten-binop.cpp
new file mode 100644
index 000000000000..d19d53a03538
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize-loop-convert-rewritten-binop.cpp
@@ -0,0 +1,60 @@
+// RUN: %check_clang_tidy -std=c++20 %s modernize-loop-convert %t -- -- -I %S/Inputs/modernize-loop-convert
+
+namespace std {
+struct strong_ordering {
+  int n;
+  constexpr operator int() const { return n; }
+  static const strong_ordering equal, greater, less;
+};
+constexpr strong_ordering strong_ordering::equal = {0};
+constexpr strong_ordering strong_ordering::greater = {1};
+constexpr strong_ordering strong_ordering::less = {-1};
+} // namespace std
+
+struct HasSpaceshipMem {
+  typedef int value_type;
+
+  struct iterator {
+    value_type &operator*();
+    const value_type &operator*() const;
+    iterator &operator++();
+    void insert(value_type);
+    value_type X;
+    constexpr auto operator<=>(const HasSpaceshipMem::iterator &) const = default;
+  };
+
+  iterator begin();
+  iterator end();
+};
+
+struct OpEqOnly {
+  typedef int value_type;
+  struct iterator {
+    value_type &operator*();
+    const value_type &operator*() const;
+    iterator &operator++();
+    bool operator==(const iterator &other) const;
+    void insert(value_type);
+    value_type X;
+  };
+  iterator begin();
+  iterator end();
+};
+
+void rewritten() {
+  OpEqOnly Oeo;
+  for (OpEqOnly::iterator It = Oeo.begin(), E = Oeo.end(); It != E; ++It) {
+    (void)*It;
+  }
+  // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+  // CHECK-FIXES: for (int & It : Oeo)
+  // CHECK-FIXES-NEXT: (void)It;
+
+  HasSpaceshipMem Hsm;
+  for (HasSpaceshipMem::iterator It = Hsm.begin(), E = Hsm.end(); It != E; ++It) {
+    (void)*It;
+  }
+  // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use range-based for loop instead
+  // CHECK-FIXES: for (int & It : Hsm)
+  // CHECK-FIXES-NEXT: (void)It;
+}

diff  --git a/clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty-cxx20.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty-cxx20.cpp
new file mode 100644
index 000000000000..40717dec8fa9
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability-container-size-empty-cxx20.cpp
@@ -0,0 +1,44 @@
+// RUN: %check_clang_tidy -std=c++20 %s readability-container-size-empty %t -- -- -fno-delayed-template-parsing
+
+namespace std {
+struct strong_ordering {
+  int n;
+  constexpr operator int() const { return n; }
+  static const strong_ordering equal, greater, less;
+};
+constexpr strong_ordering strong_ordering::equal = {0};
+constexpr strong_ordering strong_ordering::greater = {1};
+constexpr strong_ordering strong_ordering::less = {-1};
+} // namespace std
+
+template <typename T>
+struct OpEqOnly {
+  OpEqOnly();
+  bool operator==(const OpEqOnly<T> &other) const;
+  unsigned long size() const;
+  bool empty() const;
+};
+
+template <typename T>
+struct HasSpaceshipMem {
+  HasSpaceshipMem();
+  bool operator<=>(const HasSpaceshipMem<T> &other) const = default;
+  unsigned long size() const;
+  bool empty() const;
+};
+
+void returnsVoid() {
+  OpEqOnly<int> OEO;
+  HasSpaceshipMem<int> HSM;
+
+  if (OEO != OpEqOnly<int>())
+    ;
+  // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used to check for emptiness
+  // CHECK-FIXES: {{^  }}if (!OEO.empty()){{$}}
+  // CHECK-MESSAGES: :19:8: note: method 'OpEqOnly'::empty() defined here
+  if (HSM != HasSpaceshipMem<int>())
+    ;
+  // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: the 'empty' method should be used to check for emptiness
+  // CHECK-FIXES: {{^  }}if (!HSM.empty()){{$}}
+  // CHECK-MESSAGES: :27:8: note: method 'HasSpaceshipMem'::empty() defined here
+}


        


More information about the cfe-commits mailing list