[clang-tools-extra] [clang-tidy] Improve readability-use-anyofallof with Fix-Its and none_of (PR #182065)
Helmut Januschka via cfe-commits
cfe-commits at lists.llvm.org
Sat Feb 28 07:23:30 PST 2026
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 <helmut at januschka.com>
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;
}
More information about the cfe-commits
mailing list