[clang-tools-extra] [clang-tidy] add check warning on long control flow blocks (PR #219589)
Alex Dutka via cfe-commits
cfe-commits at lists.llvm.org
Sat Aug 29 08:59:07 PDT 2026
https://github.com/dutkalex updated https://github.com/llvm/llvm-project/pull/219589
>From 5a9cd36333b015ec66842d72e184318b7c42bdda Mon Sep 17 00:00:00 2001
From: Alex Dutka <alexandre.dutka at asplus.fr>
Date: Fri, 28 Aug 2026 16:08:46 +0200
Subject: [PATCH 01/11] add if-block-size check
---
.../clang-tidy/readability/CMakeLists.txt | 1 +
.../readability/IfBlockSizeCheck.cpp | 32 ++++++++++++++++++
.../clang-tidy/readability/IfBlockSizeCheck.h | 33 +++++++++++++++++++
.../readability/ReadabilityTidyModule.cpp | 3 ++
.../checkers/readability/if-block-size.cpp | 14 ++++++++
5 files changed, 83 insertions(+)
create mode 100644 clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.cpp
create mode 100644 clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.h
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
index 11cadf9f39879..e7d38f6427a49 100644
--- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
@@ -23,6 +23,7 @@ add_clang_library(clangTidyReadabilityModule STATIC
FunctionSizeCheck.cpp
IdentifierLengthCheck.cpp
IdentifierNamingCheck.cpp
+ IfBlockSizeCheck.cpp
ImplicitBoolConversionCheck.cpp
InconsistentIfElseBracesCheck.cpp
RedundantInlineSpecifierCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.cpp b/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.cpp
new file mode 100644
index 0000000000000..7623838512f87
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.cpp
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "IfBlockSizeCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+void IfBlockSizeCheck::registerMatchers(MatchFinder *Finder) {
+ // FIXME: Add matchers.
+ Finder->addMatcher(functionDecl().bind("x"), this);
+}
+
+void IfBlockSizeCheck::check(const MatchFinder::MatchResult &Result) {
+ // FIXME: Add callback implementation.
+ const auto *MatchedDecl = Result.Nodes.getNodeAs<FunctionDecl>("x");
+ if (!MatchedDecl->getIdentifier() || MatchedDecl->getName().starts_with("awesome_"))
+ return;
+ diag(MatchedDecl->getLocation(), "function %0 is insufficiently awesome")
+ << MatchedDecl
+ << FixItHint::CreateInsertion(MatchedDecl->getLocation(), "awesome_");
+ diag(MatchedDecl->getLocation(), "insert 'awesome'", DiagnosticIDs::Note);
+}
+
+} // namespace clang::tidy::readability
diff --git a/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.h b/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.h
new file mode 100644
index 0000000000000..1a8bfb5efb7ee
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.h
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IFBLOCKSIZECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IFBLOCKSIZECHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::readability {
+
+/// FIXME: Write a short description.
+///
+/// For the user-facing documentation see:
+/// https://clang.llvm.org/extra/clang-tidy/checks/readability/if-block-size.html
+class IfBlockSizeCheck : public ClangTidyCheck {
+public:
+ IfBlockSizeCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus;
+ }
+};
+
+} // namespace clang::tidy::readability
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IFBLOCKSIZECHECK_H
diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
index 0592ae5f1bf60..67091551a4706 100644
--- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -27,6 +27,7 @@
#include "FunctionSizeCheck.h"
#include "IdentifierLengthCheck.h"
#include "IdentifierNamingCheck.h"
+#include "IfBlockSizeCheck.h"
#include "ImplicitBoolConversionCheck.h"
#include "InconsistentDeclarationParameterNameCheck.h"
#include "InconsistentIfElseBracesCheck.h"
@@ -117,6 +118,8 @@ class ReadabilityModule : public ClangTidyModule {
"readability-identifier-length");
CheckFactories.registerCheck<IdentifierNamingCheck>(
"readability-identifier-naming");
+ CheckFactories.registerCheck<IfBlockSizeCheck>(
+ "readability-if-block-size");
CheckFactories.registerCheck<ImplicitBoolConversionCheck>(
"readability-implicit-bool-conversion");
CheckFactories.registerCheck<InconsistentIfElseBracesCheck>(
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp
new file mode 100644
index 0000000000000..17a4fd5c62159
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp
@@ -0,0 +1,14 @@
+// RUN: %check_clang_tidy %s readability-if-block-size %t
+
+// FIXME: Add something that triggers the check here.
+void f();
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'f' is insufficiently awesome [readability-if-block-size]
+
+// FIXME: Verify the applied fix.
+// * Make the CHECK patterns specific enough and try to make verified lines
+// unique to avoid incorrect matches.
+// * Use {{}} for regular expressions.
+// CHECK-FIXES: {{^}}void awesome_f();{{$}}
+
+// FIXME: Add something that doesn't trigger the check here.
+void awesome_f2();
>From 88d286eead3bf24e18aba8b2ccdd12f9590a00f5 Mon Sep 17 00:00:00 2001
From: Alex Dutka <alexandre.dutka at asplus.fr>
Date: Fri, 28 Aug 2026 18:59:31 +0200
Subject: [PATCH 02/11] basic implementation working
---
.../readability/IfBlockSizeCheck.cpp | 28 ++++---
.../clang-tidy/readability/IfBlockSizeCheck.h | 5 +-
.../checkers/readability/if-block-size.cpp | 79 ++++++++++++++++---
3 files changed, 92 insertions(+), 20 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.cpp b/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.cpp
index 7623838512f87..847b588305e57 100644
--- a/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.cpp
@@ -7,26 +7,36 @@
//===----------------------------------------------------------------------===//
#include "IfBlockSizeCheck.h"
+#include "clang/AST/Stmt.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
using namespace clang::ast_matchers;
namespace clang::tidy::readability {
void IfBlockSizeCheck::registerMatchers(MatchFinder *Finder) {
- // FIXME: Add matchers.
- Finder->addMatcher(functionDecl().bind("x"), this);
+ Finder->addMatcher(ifStmt().bind("if"), this);
}
void IfBlockSizeCheck::check(const MatchFinder::MatchResult &Result) {
- // FIXME: Add callback implementation.
- const auto *MatchedDecl = Result.Nodes.getNodeAs<FunctionDecl>("x");
- if (!MatchedDecl->getIdentifier() || MatchedDecl->getName().starts_with("awesome_"))
+ const auto& SrcMgr = Result.SourceManager;
+
+ const auto *IfBlk = Result.Nodes.getNodeAs<IfStmt>("if");
+ const unsigned FirstLine = SrcMgr->getSpellingLineNumber(IfBlk->getBeginLoc());
+ const unsigned LastLine = [&](){
+ if (const auto *ElseBlk = IfBlk->getElse())
+ return SrcMgr->getSpellingLineNumber(ElseBlk->getBeginLoc());
+ return SrcMgr->getSpellingLineNumber(IfBlk->getEndLoc());
+ }();
+ const unsigned LineCount = LastLine - FirstLine + 1;
+
+ if (LineCount <= LineCountThreshold)
return;
- diag(MatchedDecl->getLocation(), "function %0 is insufficiently awesome")
- << MatchedDecl
- << FixItHint::CreateInsertion(MatchedDecl->getLocation(), "awesome_");
- diag(MatchedDecl->getLocation(), "insert 'awesome'", DiagnosticIDs::Note);
+
+ diag(IfBlk->getBeginLoc(), "if block spans %0 lines of code, which exceeds the threshold of %1 lines")
+ << LineCount
+ << LineCountThreshold;
}
} // namespace clang::tidy::readability
diff --git a/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.h b/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.h
index 1a8bfb5efb7ee..3197fe558bfd6 100644
--- a/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.h
@@ -13,7 +13,7 @@
namespace clang::tidy::readability {
-/// FIXME: Write a short description.
+/// Warns about large if blocks
///
/// For the user-facing documentation see:
/// https://clang.llvm.org/extra/clang-tidy/checks/readability/if-block-size.html
@@ -26,6 +26,9 @@ class IfBlockSizeCheck : public ClangTidyCheck {
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
return LangOpts.CPlusPlus;
}
+
+private:
+ const unsigned LineCountThreshold = 20;
};
} // namespace clang::tidy::readability
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp
index 17a4fd5c62159..5005d6da85011 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp
@@ -1,14 +1,73 @@
// RUN: %check_clang_tidy %s readability-if-block-size %t
-// FIXME: Add something that triggers the check here.
-void f();
-// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: function 'f' is insufficiently awesome [readability-if-block-size]
+void should_warn(){
+ if (true){ // 1
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: if block spans 21 lines of code, which exceeds the threshold of 20 lines [readability-if-block-size]
+ int sum = 3
+ + 4
+ + 5
+ + 6
+ + 7
+ + 8
+ + 9
+ + 10
+ + 11
+ + 12
+ + 13
+ + 14
+ + 15
+ + 16
+ + 17
+ + 18
+ + 19
+ + 20;
+ } // 21
+}
-// FIXME: Verify the applied fix.
-// * Make the CHECK patterns specific enough and try to make verified lines
-// unique to avoid incorrect matches.
-// * Use {{}} for regular expressions.
-// CHECK-FIXES: {{^}}void awesome_f();{{$}}
+void should_not_warn(){
+ if (true){ // 1
+ int sum = 2
+ + 3
+ + 4
+ + 5
+ + 6
+ + 7
+ + 8
+ + 9
+ + 10
+ + 11
+ + 12
+ + 13
+ + 14
+ + 15
+ + 16
+ + 17
+ + 18
+ + 19;
+ } // 20
-// FIXME: Add something that doesn't trigger the check here.
-void awesome_f2();
+ bool a = true;
+ bool b = false;
+ if (a && b){
+ int sum = 2
+ + 3
+ + 4
+ + 5
+ + 6;
+ } else if (a || b) {
+ int sum = 8
+ + 9
+ + 10
+ + 11
+ + 12
+ + 13
+ + 14
+ + 15;
+ } else {
+ int sum = 17
+ + 18
+ + 19
+ + 20
+ + 21;
+ }
+}
>From 4a637df8dbbbdcb95fffcfa4a57d8d918627d0f0 Mon Sep 17 00:00:00 2001
From: Alex Dutka <alexandre.dutka at asplus.fr>
Date: Fri, 28 Aug 2026 21:30:56 +0200
Subject: [PATCH 03/11] add else block logic
---
.../readability/IfBlockSizeCheck.cpp | 37 +++++++++++++------
clang-tools-extra/docs/ReleaseNotes.md | 5 +++
.../docs/clang-tidy/checks/list.md | 1 +
.../checks/readability/if-block-size.md | 6 +++
.../checkers/readability/if-block-size.cpp | 25 +++++++++++++
5 files changed, 62 insertions(+), 12 deletions(-)
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/readability/if-block-size.md
diff --git a/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.cpp b/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.cpp
index 847b588305e57..0c31cc3f7c532 100644
--- a/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.cpp
@@ -20,23 +20,36 @@ void IfBlockSizeCheck::registerMatchers(MatchFinder *Finder) {
}
void IfBlockSizeCheck::check(const MatchFinder::MatchResult &Result) {
- const auto& SrcMgr = Result.SourceManager;
+ const auto &SrcMgr = Result.SourceManager;
const auto *IfBlk = Result.Nodes.getNodeAs<IfStmt>("if");
- const unsigned FirstLine = SrcMgr->getSpellingLineNumber(IfBlk->getBeginLoc());
- const unsigned LastLine = [&](){
- if (const auto *ElseBlk = IfBlk->getElse())
+ const auto *ElseBlk = IfBlk->getElse();
+
+ const unsigned FirstLine =
+ SrcMgr->getSpellingLineNumber(IfBlk->getBeginLoc());
+ const unsigned LastLine = [&]() {
+ if (ElseBlk != nullptr)
return SrcMgr->getSpellingLineNumber(ElseBlk->getBeginLoc());
return SrcMgr->getSpellingLineNumber(IfBlk->getEndLoc());
}();
- const unsigned LineCount = LastLine - FirstLine + 1;
-
- if (LineCount <= LineCountThreshold)
- return;
-
- diag(IfBlk->getBeginLoc(), "if block spans %0 lines of code, which exceeds the threshold of %1 lines")
- << LineCount
- << LineCountThreshold;
+ const unsigned LineCount = LastLine - FirstLine + 1;
+
+ if (LineCount > LineCountThreshold)
+ diag(IfBlk->getBeginLoc(), "if block spans %0 lines of code, which exceeds "
+ "the threshold of %1 lines")
+ << LineCount << LineCountThreshold;
+
+ if (ElseBlk != nullptr && isa<CompoundStmt>(ElseBlk)) { // i.e. is not an else if
+ const unsigned ElseLastLine =
+ SrcMgr->getSpellingLineNumber(IfBlk->getEndLoc());
+ const unsigned ElseLineCount = ElseLastLine - LastLine + 1;
+
+ if (ElseLineCount > LineCountThreshold)
+ diag(ElseBlk->getBeginLoc(),
+ "else block spans %0 lines of code, which exceeds "
+ "the threshold of %1 lines")
+ << ElseLineCount << LineCountThreshold;
+ }
}
} // namespace clang::tidy::readability
diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md
index 420b7ddce20e6..134660e3fd7db 100644
--- a/clang-tools-extra/docs/ReleaseNotes.md
+++ b/clang-tools-extra/docs/ReleaseNotes.md
@@ -119,6 +119,11 @@ infrastructure are described first, followed by tool-specific sections.
Finds uses of `#pragma comment` and, for `lib` or `linker` comments, suggests
using the build system for improved portability.
+- New {doc}`readability-if-block-size
+ <clang-tidy/checks/readability/if-block-size>` check.
+
+ FIXME: Write a short description.
+
- New {doc}`readability-redundant-zero-initializer
<clang-tidy/checks/readability/redundant-zero-initializer>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.md b/clang-tools-extra/docs/clang-tidy/checks/list.md
index 5a220b13eb599..7d824b1b5392b 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.md
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.md
@@ -399,6 +399,7 @@ readability/*
| {doc}`readability-function-size <readability/function-size>` | |
| {doc}`readability-identifier-length <readability/identifier-length>` | |
| {doc}`readability-identifier-naming <readability/identifier-naming>` | Yes |
+| {doc}`readability-if-block-size <readability/if-block-size>` | Yes |
| {doc}`readability-implicit-bool-conversion <readability/implicit-bool-conversion>` | Yes |
| {doc}`readability-inconsistent-declaration-parameter-name <readability/inconsistent-declaration-parameter-name>` | Yes |
| {doc}`readability-inconsistent-ifelse-braces <readability/inconsistent-ifelse-braces>` | Yes |
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/if-block-size.md b/clang-tools-extra/docs/clang-tidy/checks/readability/if-block-size.md
new file mode 100644
index 0000000000000..0289f5c11ce76
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/if-block-size.md
@@ -0,0 +1,6 @@
+```{title} clang-tidy - readability-if-block-size
+```
+
+# readability-if-block-size
+
+FIXME: Describe what patterns does the check detect and why. Give examples.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp
index 5005d6da85011..679f601846390 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp
@@ -22,6 +22,31 @@ void should_warn(){
+ 19
+ 20;
} // 21
+
+
+ if (true){ // 1
+ int sum = 2;
+ } else { // 3 1
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: else block spans 21 lines of code, which exceeds the threshold of 20 lines [readability-if-block-size]
+ int sum = 5 // 3
+ + 6 // 4
+ + 7 // 5
+ + 8 // 6
+ + 9 // 7
+ + 10 // 8
+ + 11 // 9
+ + 12 // 10
+ + 13 // 11
+ + 14 // 12
+ + 15 // 13
+ + 16 // 14
+ + 17 // 15
+ + 18 // 16
+ + 19 // 17
+ + 20 // 18
+ + 21 // 19
+ + 22; // 20
+ } // 23 21
}
void should_not_warn(){
>From 41f9b89fbcf3354d9ae300a87bc6149a1b8f0776 Mon Sep 17 00:00:00 2001
From: Alex Dutka <alexandre.dutka at asplus.fr>
Date: Fri, 28 Aug 2026 21:37:35 +0200
Subject: [PATCH 04/11] add else if test
---
.../checkers/readability/if-block-size.cpp | 27 +++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp
index 679f601846390..f3f49acf9288e 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp
@@ -47,6 +47,33 @@ void should_warn(){
+ 21 // 19
+ 22; // 20
} // 23 21
+
+
+ if (true){ // 1
+ int sum = 2;
+ } else if (true){ // 1
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: if block spans 21 lines of code, which exceeds the threshold of 20 lines [readability-if-block-size]
+ int sum = 5 // 3
+ + 6 // 4
+ + 7 // 5
+ + 8 // 6
+ + 9 // 7
+ + 10 // 8
+ + 11 // 9
+ + 12 // 10
+ + 13 // 11
+ + 14 // 12
+ + 15 // 13
+ + 16 // 14
+ + 17 // 15
+ + 18 // 16
+ + 19 // 17
+ + 20 // 18
+ + 21 // 19
+ + 22; // 20
+ } else { // 23 21
+ int sum = 24;
+ } // 25
}
void should_not_warn(){
>From d1d134a2c1e7815f96c421240b5b4ffbdedde3a0 Mon Sep 17 00:00:00 2001
From: Alex Dutka <alexandre.dutka at asplus.fr>
Date: Fri, 28 Aug 2026 22:00:23 +0200
Subject: [PATCH 05/11] extend scope to for and while loops
---
.../readability/IfBlockSizeCheck.cpp | 91 +++++++++++++------
.../checkers/readability/if-block-size.cpp | 88 ++++++++++++++++++
2 files changed, 153 insertions(+), 26 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.cpp b/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.cpp
index 0c31cc3f7c532..2c83433d589c8 100644
--- a/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.cpp
@@ -17,38 +17,77 @@ namespace clang::tidy::readability {
void IfBlockSizeCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(ifStmt().bind("if"), this);
+ Finder->addMatcher(forStmt().bind("for"), this);
+ Finder->addMatcher(whileStmt().bind("while"), this);
}
void IfBlockSizeCheck::check(const MatchFinder::MatchResult &Result) {
const auto &SrcMgr = Result.SourceManager;
- const auto *IfBlk = Result.Nodes.getNodeAs<IfStmt>("if");
- const auto *ElseBlk = IfBlk->getElse();
-
- const unsigned FirstLine =
- SrcMgr->getSpellingLineNumber(IfBlk->getBeginLoc());
- const unsigned LastLine = [&]() {
- if (ElseBlk != nullptr)
- return SrcMgr->getSpellingLineNumber(ElseBlk->getBeginLoc());
- return SrcMgr->getSpellingLineNumber(IfBlk->getEndLoc());
- }();
- const unsigned LineCount = LastLine - FirstLine + 1;
-
- if (LineCount > LineCountThreshold)
- diag(IfBlk->getBeginLoc(), "if block spans %0 lines of code, which exceeds "
- "the threshold of %1 lines")
- << LineCount << LineCountThreshold;
-
- if (ElseBlk != nullptr && isa<CompoundStmt>(ElseBlk)) { // i.e. is not an else if
- const unsigned ElseLastLine =
- SrcMgr->getSpellingLineNumber(IfBlk->getEndLoc());
- const unsigned ElseLineCount = ElseLastLine - LastLine + 1;
-
- if (ElseLineCount > LineCountThreshold)
- diag(ElseBlk->getBeginLoc(),
- "else block spans %0 lines of code, which exceeds "
+ if (const auto *IfBlk = Result.Nodes.getNodeAs<IfStmt>("if")) {
+ const auto *ElseBlk = IfBlk->getElse();
+
+ const unsigned FirstLine =
+ SrcMgr->getSpellingLineNumber(IfBlk->getBeginLoc());
+ const unsigned LastLine = [&]() {
+ if (ElseBlk != nullptr)
+ return SrcMgr->getSpellingLineNumber(ElseBlk->getBeginLoc());
+ return SrcMgr->getSpellingLineNumber(IfBlk->getEndLoc());
+ }();
+ const unsigned LineCount = LastLine - FirstLine + 1;
+
+ if (LineCount > LineCountThreshold)
+ diag(IfBlk->getBeginLoc(),
+ "if block spans %0 lines of code, which exceeds "
"the threshold of %1 lines")
- << ElseLineCount << LineCountThreshold;
+ << LineCount << LineCountThreshold;
+
+ if (ElseBlk != nullptr &&
+ isa<CompoundStmt>(ElseBlk)) { // i.e. is not an else if
+ const unsigned ElseLastLine =
+ SrcMgr->getSpellingLineNumber(IfBlk->getEndLoc());
+ const unsigned ElseLineCount = ElseLastLine - LastLine + 1;
+
+ if (ElseLineCount > LineCountThreshold)
+ diag(ElseBlk->getBeginLoc(),
+ "else block spans %0 lines of code, which exceeds "
+ "the threshold of %1 lines")
+ << ElseLineCount << LineCountThreshold;
+ }
+
+ return;
+ }
+
+ if (const auto *ForLoop = Result.Nodes.getNodeAs<ForStmt>("for")) {
+ const unsigned FirstLine =
+ SrcMgr->getSpellingLineNumber(ForLoop->getBeginLoc());
+ const unsigned LastLine =
+ SrcMgr->getSpellingLineNumber(ForLoop->getEndLoc());
+ const unsigned LineCount = LastLine - FirstLine + 1;
+
+ if (LineCount > LineCountThreshold) {
+ diag(ForLoop->getBeginLoc(), "for loop spans %0 lines of code, which "
+ "exceeds the threshold of %1 lines")
+ << LineCount << LineCountThreshold;
+ }
+
+ return;
+ }
+
+ if (const auto *WhileLoop = Result.Nodes.getNodeAs<WhileStmt>("while")) {
+ const unsigned FirstLine =
+ SrcMgr->getSpellingLineNumber(WhileLoop->getBeginLoc());
+ const unsigned LastLine =
+ SrcMgr->getSpellingLineNumber(WhileLoop->getEndLoc());
+ const unsigned LineCount = LastLine - FirstLine + 1;
+
+ if (LineCount > LineCountThreshold) {
+ diag(WhileLoop->getBeginLoc(), "while loop spans %0 lines of code, which "
+ "exceeds the threshold of %1 lines")
+ << LineCount << LineCountThreshold;
+ }
+
+ return;
}
}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp
index f3f49acf9288e..232b9dc021643 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp
@@ -74,6 +74,51 @@ void should_warn(){
} else { // 23 21
int sum = 24;
} // 25
+
+
+ for (int i = 0; i < 10; ++i) {
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: for loop spans 21 lines of code, which exceeds the threshold of 20 lines [readability-if-block-size]
+ int sum = 3
+ + 4
+ + 5
+ + 6
+ + 7
+ + 8
+ + 9
+ + 10
+ + 11
+ + 12
+ + 13
+ + 14
+ + 15
+ + 16
+ + 17
+ + 18
+ + 19
+ + 20;
+ }
+
+ while (true) {
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: while loop spans 21 lines of code, which exceeds the threshold of 20 lines [readability-if-block-size]
+ int sum = 3
+ + 4
+ + 5
+ + 6
+ + 7
+ + 8
+ + 9
+ + 10
+ + 11
+ + 12
+ + 13
+ + 14
+ + 15
+ + 16
+ + 17
+ + 18
+ + 19
+ + 20;
+ }
}
void should_not_warn(){
@@ -122,4 +167,47 @@ void should_not_warn(){
+ 20
+ 21;
}
+
+
+ for (int i = 0; i < 10; ++i) {
+ int sum = 2
+ + 3
+ + 4
+ + 5
+ + 6
+ + 7
+ + 8
+ + 9
+ + 10
+ + 11
+ + 12
+ + 13
+ + 14
+ + 15
+ + 16
+ + 17
+ + 18
+ + 19;
+ }
+
+ while (true) {
+ int sum = 2
+ + 3
+ + 4
+ + 5
+ + 6
+ + 7
+ + 8
+ + 9
+ + 10
+ + 11
+ + 12
+ + 13
+ + 14
+ + 15
+ + 16
+ + 17
+ + 18
+ + 19;
+ }
}
>From e478064072ff2b5caf5e7f9f0d0032d1876191dd Mon Sep 17 00:00:00 2001
From: Alex Dutka <alexandre.dutka at asplus.fr>
Date: Fri, 28 Aug 2026 22:12:37 +0200
Subject: [PATCH 06/11] rename check to readability-block-size
---
.../{IfBlockSizeCheck.cpp => BlockSizeCheck.cpp} | 6 +++---
.../{IfBlockSizeCheck.h => BlockSizeCheck.h} | 12 ++++++------
.../clang-tidy/readability/CMakeLists.txt | 2 +-
.../clang-tidy/readability/ReadabilityTidyModule.cpp | 6 +++---
clang-tools-extra/docs/ReleaseNotes.md | 4 ++--
clang-tools-extra/docs/clang-tidy/checks/list.md | 2 +-
.../readability/{if-block-size.md => block-size.md} | 4 ++--
.../{if-block-size.cpp => block-size.cpp} | 12 ++++++------
8 files changed, 24 insertions(+), 24 deletions(-)
rename clang-tools-extra/clang-tidy/readability/{IfBlockSizeCheck.cpp => BlockSizeCheck.cpp} (95%)
rename clang-tools-extra/clang-tidy/readability/{IfBlockSizeCheck.h => BlockSizeCheck.h} (69%)
rename clang-tools-extra/docs/clang-tidy/checks/readability/{if-block-size.md => block-size.md} (51%)
rename clang-tools-extra/test/clang-tidy/checkers/readability/{if-block-size.cpp => block-size.cpp} (97%)
diff --git a/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.cpp b/clang-tools-extra/clang-tidy/readability/BlockSizeCheck.cpp
similarity index 95%
rename from clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.cpp
rename to clang-tools-extra/clang-tidy/readability/BlockSizeCheck.cpp
index 2c83433d589c8..5335c8c30b55d 100644
--- a/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/BlockSizeCheck.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-#include "IfBlockSizeCheck.h"
+#include "BlockSizeCheck.h"
#include "clang/AST/Stmt.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
@@ -15,13 +15,13 @@ using namespace clang::ast_matchers;
namespace clang::tidy::readability {
-void IfBlockSizeCheck::registerMatchers(MatchFinder *Finder) {
+void BlockSizeCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(ifStmt().bind("if"), this);
Finder->addMatcher(forStmt().bind("for"), this);
Finder->addMatcher(whileStmt().bind("while"), this);
}
-void IfBlockSizeCheck::check(const MatchFinder::MatchResult &Result) {
+void BlockSizeCheck::check(const MatchFinder::MatchResult &Result) {
const auto &SrcMgr = Result.SourceManager;
if (const auto *IfBlk = Result.Nodes.getNodeAs<IfStmt>("if")) {
diff --git a/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.h b/clang-tools-extra/clang-tidy/readability/BlockSizeCheck.h
similarity index 69%
rename from clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.h
rename to clang-tools-extra/clang-tidy/readability/BlockSizeCheck.h
index 3197fe558bfd6..acf4ffe7f8692 100644
--- a/clang-tools-extra/clang-tidy/readability/IfBlockSizeCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/BlockSizeCheck.h
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IFBLOCKSIZECHECK_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IFBLOCKSIZECHECK_H
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_BLOCKSIZECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_BLOCKSIZECHECK_H
#include "../ClangTidyCheck.h"
@@ -16,10 +16,10 @@ namespace clang::tidy::readability {
/// Warns about large if blocks
///
/// For the user-facing documentation see:
-/// https://clang.llvm.org/extra/clang-tidy/checks/readability/if-block-size.html
-class IfBlockSizeCheck : public ClangTidyCheck {
+/// https://clang.llvm.org/extra/clang-tidy/checks/readability/block-size.html
+class BlockSizeCheck : public ClangTidyCheck {
public:
- IfBlockSizeCheck(StringRef Name, ClangTidyContext *Context)
+ BlockSizeCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
@@ -33,4 +33,4 @@ class IfBlockSizeCheck : public ClangTidyCheck {
} // namespace clang::tidy::readability
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_IFBLOCKSIZECHECK_H
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_BLOCKSIZECHECK_H
diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
index e7d38f6427a49..b326c733f4588 100644
--- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
@@ -23,7 +23,7 @@ add_clang_library(clangTidyReadabilityModule STATIC
FunctionSizeCheck.cpp
IdentifierLengthCheck.cpp
IdentifierNamingCheck.cpp
- IfBlockSizeCheck.cpp
+ BlockSizeCheck.cpp
ImplicitBoolConversionCheck.cpp
InconsistentIfElseBracesCheck.cpp
RedundantInlineSpecifierCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
index 67091551a4706..c1a06f1601dcc 100644
--- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -27,7 +27,7 @@
#include "FunctionSizeCheck.h"
#include "IdentifierLengthCheck.h"
#include "IdentifierNamingCheck.h"
-#include "IfBlockSizeCheck.h"
+#include "BlockSizeCheck.h"
#include "ImplicitBoolConversionCheck.h"
#include "InconsistentDeclarationParameterNameCheck.h"
#include "InconsistentIfElseBracesCheck.h"
@@ -118,8 +118,8 @@ class ReadabilityModule : public ClangTidyModule {
"readability-identifier-length");
CheckFactories.registerCheck<IdentifierNamingCheck>(
"readability-identifier-naming");
- CheckFactories.registerCheck<IfBlockSizeCheck>(
- "readability-if-block-size");
+ CheckFactories.registerCheck<BlockSizeCheck>(
+ "readability-block-size");
CheckFactories.registerCheck<ImplicitBoolConversionCheck>(
"readability-implicit-bool-conversion");
CheckFactories.registerCheck<InconsistentIfElseBracesCheck>(
diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md
index 134660e3fd7db..503782883a72d 100644
--- a/clang-tools-extra/docs/ReleaseNotes.md
+++ b/clang-tools-extra/docs/ReleaseNotes.md
@@ -119,8 +119,8 @@ infrastructure are described first, followed by tool-specific sections.
Finds uses of `#pragma comment` and, for `lib` or `linker` comments, suggests
using the build system for improved portability.
-- New {doc}`readability-if-block-size
- <clang-tidy/checks/readability/if-block-size>` check.
+- New {doc}`readability-block-size
+ <clang-tidy/checks/readability/block-size>` check.
FIXME: Write a short description.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.md b/clang-tools-extra/docs/clang-tidy/checks/list.md
index 7d824b1b5392b..a1028efbacfec 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.md
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.md
@@ -385,6 +385,7 @@ readability/*
| {doc}`readability-avoid-nested-conditional-operator <readability/avoid-nested-conditional-operator>` | |
| {doc}`readability-avoid-return-with-void-value <readability/avoid-return-with-void-value>` | Yes |
| {doc}`readability-avoid-unconditional-preprocessor-if <readability/avoid-unconditional-preprocessor-if>` | |
+| {doc}`readability-block-size <readability/block-size>` | |
| {doc}`readability-braces-around-statements <readability/braces-around-statements>` | Yes |
| {doc}`readability-const-return-type <readability/const-return-type>` | Yes |
| {doc}`readability-container-contains <readability/container-contains>` | Yes |
@@ -399,7 +400,6 @@ readability/*
| {doc}`readability-function-size <readability/function-size>` | |
| {doc}`readability-identifier-length <readability/identifier-length>` | |
| {doc}`readability-identifier-naming <readability/identifier-naming>` | Yes |
-| {doc}`readability-if-block-size <readability/if-block-size>` | Yes |
| {doc}`readability-implicit-bool-conversion <readability/implicit-bool-conversion>` | Yes |
| {doc}`readability-inconsistent-declaration-parameter-name <readability/inconsistent-declaration-parameter-name>` | Yes |
| {doc}`readability-inconsistent-ifelse-braces <readability/inconsistent-ifelse-braces>` | Yes |
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/if-block-size.md b/clang-tools-extra/docs/clang-tidy/checks/readability/block-size.md
similarity index 51%
rename from clang-tools-extra/docs/clang-tidy/checks/readability/if-block-size.md
rename to clang-tools-extra/docs/clang-tidy/checks/readability/block-size.md
index 0289f5c11ce76..949ca40ebb010 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/if-block-size.md
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/block-size.md
@@ -1,6 +1,6 @@
-```{title} clang-tidy - readability-if-block-size
+```{title} clang-tidy - readability-block-size
```
-# readability-if-block-size
+# readability-block-size
FIXME: Describe what patterns does the check detect and why. Give examples.
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/block-size.cpp
similarity index 97%
rename from clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp
rename to clang-tools-extra/test/clang-tidy/checkers/readability/block-size.cpp
index 232b9dc021643..2345afcb56017 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/if-block-size.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/block-size.cpp
@@ -1,8 +1,8 @@
-// RUN: %check_clang_tidy %s readability-if-block-size %t
+// RUN: %check_clang_tidy %s readability-block-size %t
void should_warn(){
if (true){ // 1
-// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: if block spans 21 lines of code, which exceeds the threshold of 20 lines [readability-if-block-size]
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: if block spans 21 lines of code, which exceeds the threshold of 20 lines [readability-block-size]
int sum = 3
+ 4
+ 5
@@ -27,7 +27,7 @@ void should_warn(){
if (true){ // 1
int sum = 2;
} else { // 3 1
-// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: else block spans 21 lines of code, which exceeds the threshold of 20 lines [readability-if-block-size]
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: else block spans 21 lines of code, which exceeds the threshold of 20 lines [readability-block-size]
int sum = 5 // 3
+ 6 // 4
+ 7 // 5
@@ -52,7 +52,7 @@ void should_warn(){
if (true){ // 1
int sum = 2;
} else if (true){ // 1
-// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: if block spans 21 lines of code, which exceeds the threshold of 20 lines [readability-if-block-size]
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: if block spans 21 lines of code, which exceeds the threshold of 20 lines [readability-block-size]
int sum = 5 // 3
+ 6 // 4
+ 7 // 5
@@ -77,7 +77,7 @@ void should_warn(){
for (int i = 0; i < 10; ++i) {
-// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: for loop spans 21 lines of code, which exceeds the threshold of 20 lines [readability-if-block-size]
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: for loop spans 21 lines of code, which exceeds the threshold of 20 lines [readability-block-size]
int sum = 3
+ 4
+ 5
@@ -99,7 +99,7 @@ void should_warn(){
}
while (true) {
-// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: while loop spans 21 lines of code, which exceeds the threshold of 20 lines [readability-if-block-size]
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: while loop spans 21 lines of code, which exceeds the threshold of 20 lines [readability-block-size]
int sum = 3
+ 4
+ 5
>From 87dfe4ca1de9814b74d0e6bbfa8fbace7301bc4f Mon Sep 17 00:00:00 2001
From: Alex Dutka <alexandre.dutka at asplus.fr>
Date: Fri, 28 Aug 2026 23:30:43 +0200
Subject: [PATCH 07/11] replace the unique hardcoded threshold with proper
options
---
.../clang-tidy/readability/BlockSizeCheck.cpp | 35 +++-
.../clang-tidy/readability/BlockSizeCheck.h | 8 +-
.../checkers/readability/block-size.cpp | 187 ++++--------------
3 files changed, 65 insertions(+), 165 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/BlockSizeCheck.cpp b/clang-tools-extra/clang-tidy/readability/BlockSizeCheck.cpp
index 5335c8c30b55d..971d3aee38b1a 100644
--- a/clang-tools-extra/clang-tidy/readability/BlockSizeCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/BlockSizeCheck.cpp
@@ -15,6 +15,25 @@ using namespace clang::ast_matchers;
namespace clang::tidy::readability {
+const unsigned DefaultIfLineCountThreshold = 20;
+const unsigned DefaultForLineCountThreshold = 30;
+const unsigned DefaultWhileLineCountThreshold = 30;
+
+BlockSizeCheck::BlockSizeCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ IfLineCountThreshold(
+ Options.get("IfLineCountThreshold", DefaultIfLineCountThreshold)),
+ ForLineCountThreshold(
+ Options.get("ForLineCountThreshold", DefaultForLineCountThreshold)),
+ WhileLineCountThreshold(Options.get("WhileLineCountThreshold",
+ DefaultWhileLineCountThreshold)) {}
+
+void BlockSizeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "IfLineCountThreshold", IfLineCountThreshold);
+ Options.store(Opts, "ForLineCountThreshold", ForLineCountThreshold);
+ Options.store(Opts, "WhileLineCountThreshold", WhileLineCountThreshold);
+}
+
void BlockSizeCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(ifStmt().bind("if"), this);
Finder->addMatcher(forStmt().bind("for"), this);
@@ -36,11 +55,11 @@ void BlockSizeCheck::check(const MatchFinder::MatchResult &Result) {
}();
const unsigned LineCount = LastLine - FirstLine + 1;
- if (LineCount > LineCountThreshold)
+ if (LineCount > IfLineCountThreshold)
diag(IfBlk->getBeginLoc(),
"if block spans %0 lines of code, which exceeds "
"the threshold of %1 lines")
- << LineCount << LineCountThreshold;
+ << LineCount << IfLineCountThreshold;
if (ElseBlk != nullptr &&
isa<CompoundStmt>(ElseBlk)) { // i.e. is not an else if
@@ -48,11 +67,11 @@ void BlockSizeCheck::check(const MatchFinder::MatchResult &Result) {
SrcMgr->getSpellingLineNumber(IfBlk->getEndLoc());
const unsigned ElseLineCount = ElseLastLine - LastLine + 1;
- if (ElseLineCount > LineCountThreshold)
+ if (ElseLineCount > IfLineCountThreshold)
diag(ElseBlk->getBeginLoc(),
"else block spans %0 lines of code, which exceeds "
"the threshold of %1 lines")
- << ElseLineCount << LineCountThreshold;
+ << ElseLineCount << IfLineCountThreshold;
}
return;
@@ -65,10 +84,10 @@ void BlockSizeCheck::check(const MatchFinder::MatchResult &Result) {
SrcMgr->getSpellingLineNumber(ForLoop->getEndLoc());
const unsigned LineCount = LastLine - FirstLine + 1;
- if (LineCount > LineCountThreshold) {
+ if (LineCount > ForLineCountThreshold) {
diag(ForLoop->getBeginLoc(), "for loop spans %0 lines of code, which "
"exceeds the threshold of %1 lines")
- << LineCount << LineCountThreshold;
+ << LineCount << ForLineCountThreshold;
}
return;
@@ -81,10 +100,10 @@ void BlockSizeCheck::check(const MatchFinder::MatchResult &Result) {
SrcMgr->getSpellingLineNumber(WhileLoop->getEndLoc());
const unsigned LineCount = LastLine - FirstLine + 1;
- if (LineCount > LineCountThreshold) {
+ if (LineCount > WhileLineCountThreshold) {
diag(WhileLoop->getBeginLoc(), "while loop spans %0 lines of code, which "
"exceeds the threshold of %1 lines")
- << LineCount << LineCountThreshold;
+ << LineCount << WhileLineCountThreshold;
}
return;
diff --git a/clang-tools-extra/clang-tidy/readability/BlockSizeCheck.h b/clang-tools-extra/clang-tidy/readability/BlockSizeCheck.h
index acf4ffe7f8692..b6f1af55e1bfd 100644
--- a/clang-tools-extra/clang-tidy/readability/BlockSizeCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/BlockSizeCheck.h
@@ -19,8 +19,8 @@ namespace clang::tidy::readability {
/// https://clang.llvm.org/extra/clang-tidy/checks/readability/block-size.html
class BlockSizeCheck : public ClangTidyCheck {
public:
- BlockSizeCheck(StringRef Name, ClangTidyContext *Context)
- : ClangTidyCheck(Name, Context) {}
+ BlockSizeCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
@@ -28,7 +28,9 @@ class BlockSizeCheck : public ClangTidyCheck {
}
private:
- const unsigned LineCountThreshold = 20;
+ const unsigned IfLineCountThreshold;
+ const unsigned ForLineCountThreshold;
+ const unsigned WhileLineCountThreshold;
};
} // namespace clang::tidy::readability
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/block-size.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/block-size.cpp
index 2345afcb56017..c26a42c0ee9c2 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/block-size.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/block-size.cpp
@@ -1,123 +1,55 @@
-// RUN: %check_clang_tidy %s readability-block-size %t
+// RUN: %check_clang_tidy %s readability-block-size %t \
+// RUN: -config='{CheckOptions: { \
+// RUN: readability-block-size.IfLineCountThreshold: 5, \
+// RUN: readability-block-size.ForLineCountThreshold: 6, \
+// RUN: readability-block-size.WhileLineCountThreshold: 7 }}'
void should_warn(){
if (true){ // 1
-// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: if block spans 21 lines of code, which exceeds the threshold of 20 lines [readability-block-size]
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: if block spans 6 lines of code, which exceeds the threshold of 5 lines [readability-block-size]
int sum = 3
+ 4
- + 5
- + 6
- + 7
- + 8
- + 9
- + 10
- + 11
- + 12
- + 13
- + 14
- + 15
- + 16
- + 17
- + 18
- + 19
- + 20;
- } // 21
+ + 5;
+ } // 6
if (true){ // 1
int sum = 2;
- } else { // 3 1
-// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: else block spans 21 lines of code, which exceeds the threshold of 20 lines [readability-block-size]
- int sum = 5 // 3
- + 6 // 4
- + 7 // 5
- + 8 // 6
- + 9 // 7
- + 10 // 8
- + 11 // 9
- + 12 // 10
- + 13 // 11
- + 14 // 12
- + 15 // 13
- + 16 // 14
- + 17 // 15
- + 18 // 16
- + 19 // 17
- + 20 // 18
- + 21 // 19
- + 22; // 20
- } // 23 21
+ } else { // 3 1
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: else block spans 6 lines of code, which exceeds the threshold of 5 lines [readability-block-size]
+ int sum = 5 // 3
+ + 6 // 4
+ + 7; // 5
+ } // 8 6
if (true){ // 1
int sum = 2;
} else if (true){ // 1
-// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: if block spans 21 lines of code, which exceeds the threshold of 20 lines [readability-block-size]
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: if block spans 6 lines of code, which exceeds the threshold of 5 lines [readability-block-size]
int sum = 5 // 3
+ 6 // 4
- + 7 // 5
- + 8 // 6
- + 9 // 7
- + 10 // 8
- + 11 // 9
- + 12 // 10
- + 13 // 11
- + 14 // 12
- + 15 // 13
- + 16 // 14
- + 17 // 15
- + 18 // 16
- + 19 // 17
- + 20 // 18
- + 21 // 19
- + 22; // 20
- } else { // 23 21
- int sum = 24;
- } // 25
+ + 7; // 5
+ } else { // 8 6
+ int sum = 9;
+ } // 10
for (int i = 0; i < 10; ++i) {
-// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: for loop spans 21 lines of code, which exceeds the threshold of 20 lines [readability-block-size]
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: for loop spans 7 lines of code, which exceeds the threshold of 6 lines [readability-block-size]
int sum = 3
+ 4
+ 5
- + 6
- + 7
- + 8
- + 9
- + 10
- + 11
- + 12
- + 13
- + 14
- + 15
- + 16
- + 17
- + 18
- + 19
- + 20;
+ + 6;
}
while (true) {
-// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: while loop spans 21 lines of code, which exceeds the threshold of 20 lines [readability-block-size]
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: while loop spans 8 lines of code, which exceeds the threshold of 7 lines [readability-block-size]
int sum = 3
+ 4
+ 5
+ 6
- + 7
- + 8
- + 9
- + 10
- + 11
- + 12
- + 13
- + 14
- + 15
- + 16
- + 17
- + 18
- + 19
- + 20;
+ + 7;
}
}
@@ -125,47 +57,21 @@ void should_not_warn(){
if (true){ // 1
int sum = 2
+ 3
- + 4
- + 5
- + 6
- + 7
- + 8
- + 9
- + 10
- + 11
- + 12
- + 13
- + 14
- + 15
- + 16
- + 17
- + 18
- + 19;
- } // 20
+ + 4;
+ } // 5
bool a = true;
bool b = false;
if (a && b){
int sum = 2
- + 3
- + 4
- + 5
- + 6;
+ + 3;
} else if (a || b) {
- int sum = 8
- + 9
- + 10
- + 11
- + 12
- + 13
- + 14
- + 15;
+ int sum = 5
+ + 6
+ + 7;
} else {
- int sum = 17
- + 18
- + 19
- + 20
- + 21;
+ int sum = 9
+ + 10;
}
@@ -173,21 +79,7 @@ void should_not_warn(){
int sum = 2
+ 3
+ 4
- + 5
- + 6
- + 7
- + 8
- + 9
- + 10
- + 11
- + 12
- + 13
- + 14
- + 15
- + 16
- + 17
- + 18
- + 19;
+ + 5;
}
while (true) {
@@ -195,19 +87,6 @@ void should_not_warn(){
+ 3
+ 4
+ 5
- + 6
- + 7
- + 8
- + 9
- + 10
- + 11
- + 12
- + 13
- + 14
- + 15
- + 16
- + 17
- + 18
- + 19;
+ + 6;
}
}
>From 983a3a1cac7ae9bfb1b36521ce325b82468d0392 Mon Sep 17 00:00:00 2001
From: Alex Dutka <alexandre.dutka at asplus.fr>
Date: Fri, 28 Aug 2026 23:44:20 +0200
Subject: [PATCH 08/11] add documentation
---
clang-tools-extra/docs/ReleaseNotes.md | 3 +-
.../checks/readability/block-size.md | 33 ++++++++++++++++++-
2 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.md b/clang-tools-extra/docs/ReleaseNotes.md
index 503782883a72d..ac2a3a82eff74 100644
--- a/clang-tools-extra/docs/ReleaseNotes.md
+++ b/clang-tools-extra/docs/ReleaseNotes.md
@@ -122,7 +122,8 @@ infrastructure are described first, followed by tool-specific sections.
- New {doc}`readability-block-size
<clang-tidy/checks/readability/block-size>` check.
- FIXME: Write a short description.
+ Warns on `if`, `else`, `for` and `while` blocks which exceed a given number
+ of lines of code.
- New {doc}`readability-redundant-zero-initializer
<clang-tidy/checks/readability/redundant-zero-initializer>` check.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/block-size.md b/clang-tools-extra/docs/clang-tidy/checks/readability/block-size.md
index 949ca40ebb010..6bb230ac7f365 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/block-size.md
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/block-size.md
@@ -3,4 +3,35 @@
# readability-block-size
-FIXME: Describe what patterns does the check detect and why. Give examples.
+This check warns when `if`, `else`, `for` or `while` blocks exceed a given
+number of lines of code, and thus flags control flow structures which are
+likely difficult to reason about due to their size.
+
+```cpp
+// This block will raise a warning if N > IfLineCountThreshold
+if (some_condition()){ // line #1
+ call_some_fn(); // line #2
+ // ...
+ do_something_else(); // line #N-1
+} // line #N
+```
+
+## Options
+
+```{option} IfLineCountThreshold
+
+This option sets the number of lines of code beyond which an `if` (or `else`)
+block will be flagged as too long. The default value is 20.
+```
+
+```{option} ForLineCountThreshold
+
+This option sets the number of lines of code beyond which a `for` loop will be
+flagged as too long. The default value is 30.
+```
+
+```{option} WhileLineCountThreshold
+
+This option sets the number of lines of code beyond which a `while` loop will
+be flagged as too long. The default value is 30.
+```
>From e13530084026160434dfaaec497f27ab6704f105 Mon Sep 17 00:00:00 2001
From: Alex Dutka <alexandre.dutka at asplus.fr>
Date: Sat, 29 Aug 2026 00:32:42 +0200
Subject: [PATCH 09/11] format
---
.../clang-tidy/readability/ReadabilityTidyModule.cpp | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
index c1a06f1601dcc..429a060842cff 100644
--- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -13,6 +13,7 @@
#include "AvoidNestedConditionalOperatorCheck.h"
#include "AvoidReturnWithVoidValueCheck.h"
#include "AvoidUnconditionalPreprocessorIfCheck.h"
+#include "BlockSizeCheck.h"
#include "BracesAroundStatementsCheck.h"
#include "ConstReturnTypeCheck.h"
#include "ContainerContainsCheck.h"
@@ -27,7 +28,6 @@
#include "FunctionSizeCheck.h"
#include "IdentifierLengthCheck.h"
#include "IdentifierNamingCheck.h"
-#include "BlockSizeCheck.h"
#include "ImplicitBoolConversionCheck.h"
#include "InconsistentDeclarationParameterNameCheck.h"
#include "InconsistentIfElseBracesCheck.h"
@@ -118,8 +118,7 @@ class ReadabilityModule : public ClangTidyModule {
"readability-identifier-length");
CheckFactories.registerCheck<IdentifierNamingCheck>(
"readability-identifier-naming");
- CheckFactories.registerCheck<BlockSizeCheck>(
- "readability-block-size");
+ CheckFactories.registerCheck<BlockSizeCheck>("readability-block-size");
CheckFactories.registerCheck<ImplicitBoolConversionCheck>(
"readability-implicit-bool-conversion");
CheckFactories.registerCheck<InconsistentIfElseBracesCheck>(
>From b3c47be200432bdf27574ad91e970eea52ca303f Mon Sep 17 00:00:00 2001
From: Alex Dutka <adutka at cerfacs.fr>
Date: Sat, 29 Aug 2026 17:53:47 +0200
Subject: [PATCH 10/11] Apply batched suggestions from code review
Co-authored-by: EugeneZelenko <eugene.zelenko at gmail.com>
---
.../docs/clang-tidy/checks/readability/block-size.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/block-size.md b/clang-tools-extra/docs/clang-tidy/checks/readability/block-size.md
index 6bb230ac7f365..7f2379bf4decd 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/block-size.md
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/block-size.md
@@ -21,17 +21,17 @@ if (some_condition()){ // line #1
```{option} IfLineCountThreshold
This option sets the number of lines of code beyond which an `if` (or `else`)
-block will be flagged as too long. The default value is 20.
+block will be flagged as too long. The default value is `20`.
```
```{option} ForLineCountThreshold
This option sets the number of lines of code beyond which a `for` loop will be
-flagged as too long. The default value is 30.
+flagged as too long. The default value is `30`.
```
```{option} WhileLineCountThreshold
This option sets the number of lines of code beyond which a `while` loop will
-be flagged as too long. The default value is 30.
+be flagged as too long. The default value is `30`.
```
>From e76c552f489a2aee6afc38928b5fb4b1eaf46b49 Mon Sep 17 00:00:00 2001
From: Alex Dutka <adutka at cerfacs.fr>
Date: Sat, 29 Aug 2026 17:58:53 +0200
Subject: [PATCH 11/11] Remove "this check"
---
.../docs/clang-tidy/checks/readability/block-size.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/block-size.md b/clang-tools-extra/docs/clang-tidy/checks/readability/block-size.md
index 7f2379bf4decd..4eb859cd55924 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/block-size.md
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/block-size.md
@@ -3,9 +3,9 @@
# readability-block-size
-This check warns when `if`, `else`, `for` or `while` blocks exceed a given
-number of lines of code, and thus flags control flow structures which are
-likely difficult to reason about due to their size.
+Warns when `if`, `else`, `for` or `while` blocks exceed a given number of lines
+of code, and thus flags control flow structures which are likely difficult to
+reason about due to their size.
```cpp
// This block will raise a warning if N > IfLineCountThreshold
More information about the cfe-commits
mailing list