https://github.com/hjanuschka updated 
https://github.com/llvm/llvm-project/pull/182065

>From 8d328d49e8a2cc08b7f390d39cdaab481aff5dae Mon Sep 17 00:00:00 2001
From: Helmut Januschka <[email protected]>
Date: Wed, 18 Feb 2026 18:03:47 +0100
Subject: [PATCH] [clang-tidy] Add none_of suggestion to
 readability-use-anyofallof

---
 .../readability/UseAnyOfAllOfCheck.cpp        | 29 +++++++++++++++++--
 clang-tools-extra/docs/ReleaseNotes.rst       |  4 +++
 .../checks/readability/use-anyofallof.rst     |  5 ++--
 .../checkers/readability/use-anyofallof.cpp   | 11 ++++++-
 4 files changed, 44 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp 
b/clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp
index 63649150b17e3..7d5f3f547e610 100644
--- a/clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/UseAnyOfAllOfCheck.cpp
@@ -84,6 +84,26 @@ static bool isViableLoop(const CXXForRangeStmt &S, 
ASTContext &Context) {
   });
 }
 
+/// For the all_of_loop pattern (returns false inside, true after), check
+/// whether the if-condition is negated. If it is, the loop is an all_of;
+/// otherwise it is a none_of.
+static bool isNoneOfPattern(const CXXForRangeStmt &Loop) {
+  const Stmt *Body = Loop.getBody();
+  const IfStmt *If = nullptr;
+  if (const auto *Compound = dyn_cast<CompoundStmt>(Body)) {
+    if (Compound->size() == 1)
+      If = dyn_cast<IfStmt>(Compound->body_front());
+  } else {
+    If = dyn_cast<IfStmt>(Body);
+  }
+  if (!If)
+    return false;
+  // If the condition is not negated (no leading !), it's a none_of pattern.
+  const Expr *Cond = If->getCond()->IgnoreParenImpCasts();
+  const auto *UO = dyn_cast<UnaryOperator>(Cond);
+  return !UO || UO->getOpcode() != UO_LNot;
+}
+
 void UseAnyOfAllOfCheck::check(const MatchFinder::MatchResult &Result) {
   if (const auto *S = Result.Nodes.getNodeAs<CXXForRangeStmt>("any_of_loop")) {
     if (!isViableLoop(*S, *Result.Context))
@@ -96,8 +116,13 @@ void UseAnyOfAllOfCheck::check(const 
MatchFinder::MatchResult &Result) {
     if (!isViableLoop(*S, *Result.Context))
       return;
 
-    diag(S->getForLoc(), "replace loop by 'std%select{|::ranges}0::all_of()'")
-        << getLangOpts().CPlusPlus20;
+    if (isNoneOfPattern(*S))
+      diag(S->getForLoc(),
+           "replace loop by 'std%select{|::ranges}0::none_of()'")
+          << getLangOpts().CPlusPlus20;
+    else
+      diag(S->getForLoc(), "replace loop by 
'std%select{|::ranges}0::all_of()'")
+          << getLangOpts().CPlusPlus20;
   }
 }
 
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 68bab88146241..35423b88aeb8f 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -242,6 +242,10 @@ Changes in existing checks
   now uses separate note diagnostics for each uninitialized enumerator, making
   it easier to see which specific enumerators need explicit initialization.
 
+- Improved :doc:`readability-use-anyofallof
+  <clang-tidy/checks/readability/use-anyofallof>` check by adding support for
+  ``std::none_of`` suggestions when the loop condition is not negated.
+
 - Improved :doc:`readability-non-const-parameter
   <clang-tidy/checks/readability/non-const-parameter>` check by avoiding false
   positives on parameters used in dependent expressions (e.g. inside generic
diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/readability/use-anyofallof.rst 
b/clang-tools-extra/docs/clang-tidy/checks/readability/use-anyofallof.rst
index cfbc551bf07c0..e93620e74074a 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/use-anyofallof.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/use-anyofallof.rst
@@ -4,8 +4,9 @@ readability-use-anyofallof
 ==========================
 
 Finds range-based for loops that can be replaced by a call to
-``std::any_of`` or ``std::all_of``. In C++20 mode, suggests
-``std::ranges::any_of`` or ``std::ranges::all_of``.
+``std::any_of``, ``std::all_of``, or ``std::none_of``. In C++20 mode, suggests
+``std::ranges::any_of``, ``std::ranges::all_of``, or
+``std::ranges::none_of``.
 
 Example:
 
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof.cpp
index 7f8f16488d37a..3fa1512ae65be 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/use-anyofallof.cpp
@@ -174,11 +174,20 @@ bool bad_any_of7() {
   return false;
 }
 
+bool good_none_of() {
+  int v[] = {1, 2, 3};
+  // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: replace loop by 'std::none_of()' 
[readability-use-anyofallof]
+  for (int i : v)
+    if (i)
+      return false;
+  return true;
+}
+
 bool good_all_of() {
   int v[] = {1, 2, 3};
   // CHECK-MESSAGES: :[[@LINE+1]]:3: warning: replace loop by 'std::all_of()' 
[readability-use-anyofallof]
   for (int i : v)
-    if (i)
+    if (!cond(i))
       return false;
   return true;
 }

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to