[clang-tools-extra] [clang-tidy][readability-identifier-length] Add a line count threshold (PR #185319)
Alex Dutka via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 20 06:48:43 PDT 2026
https://github.com/dutkalex updated https://github.com/llvm/llvm-project/pull/185319
>From 639e834da6e99be43f93f5409669b65b1a326357 Mon Sep 17 00:00:00 2001
From: Alex Dutka <97711898+dutkalex at users.noreply.github.com>
Date: Sun, 8 Mar 2026 19:47:13 +0100
Subject: [PATCH 1/8] Update the readability-identifier-length test file to
account for the LineCountThreshold option
---
.../readability/identifier-length.cpp | 33 ++++++++++++-------
1 file changed, 21 insertions(+), 12 deletions(-)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-length.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-length.cpp
index 33b0ac7ce7aa3..1972862d05f3e 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-length.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-length.cpp
@@ -1,6 +1,6 @@
// RUN: %check_clang_tidy %s readability-identifier-length %t \
// RUN: -config='{CheckOptions: \
-// RUN: {readability-identifier-length.IgnoredVariableNames: "^[xy]$"}}' \
+// RUN: {readability-identifier-length.IgnoredVariableNames: "^[xy]$", readability-identifier-length.LineCountThreshold: 1}}' \
// RUN: -- -fexceptions
struct myexcept {
@@ -11,7 +11,8 @@ struct simpleexcept {
int other;
};
-void doIt();
+template<typename... Ts>
+void doIt(Ts...);
void tooShortVariableNames(int z)
// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: parameter name 'z' is too short, expected at least 3 characters [readability-identifier-length]
@@ -25,39 +26,47 @@ void tooShortVariableNames(int z)
for (int m = 0; m < 5; ++m)
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: loop variable name 'm' is too short, expected at least 2 characters [readability-identifier-length]
{
- doIt();
+ doIt(i, jj, m);
}
try {
- doIt();
+ doIt(z);
} catch (const myexcept &x)
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: exception variable name 'x' is too short, expected at least 2 characters [readability-identifier-length]
{
- doIt();
+ doIt(x);
}
}
-void longEnoughVariableNames(int n) // argument 'n' ignored by default configuration
+void longEnoughVariableNames(int n, int m) // argument 'n' ignored by default configuration, 'm' is only used on this line
{
int var = 5;
for (int i = 0; i < 42; ++i) // 'i' is default allowed, for historical reasons
{
- doIt();
+ doIt(var, i);
+ }
+
+ for (int a = 0; a < 42; ++a) // 'a' is only used on this line
+ {
+ doIt();
}
for (int kk = 0; kk < 42; ++kk) {
- doIt();
+ doIt(kk);
}
try {
- doIt();
+ doIt(n);
} catch (const simpleexcept &e) // ignored by default configuration
{
- doIt();
+ doIt(e);
} catch (const myexcept &ex) {
- doIt();
- }
+ doIt(ex);
+ } catch (const int &d) { doIt(d); } // 'd' is only used on this line
int x = 5; // ignored by configuration
+ ++x;
+
+ int b = 0; // 'b' is only used on this line
}
>From 46030ba3d8b594f3300ff8949283e534b6b24a7c Mon Sep 17 00:00:00 2001
From: Alex Dutka <97711898+dutkalex at users.noreply.github.com>
Date: Sun, 8 Mar 2026 19:49:24 +0100
Subject: [PATCH 2/8] Implement the count of lines until last use to allow for
short identifiers if their scope is limited
---
.../readability/IdentifierLengthCheck.cpp | 49 ++++++++++++++++++-
.../readability/IdentifierLengthCheck.h | 2 +
2 files changed, 50 insertions(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp
index a6204de16224d..4755588b70d18 100644
--- a/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp
@@ -21,6 +21,7 @@ const char DefaultIgnoredLoopCounterNames[] = "^[ijk_]$";
const char DefaultIgnoredVariableNames[] = "";
const char DefaultIgnoredExceptionVariableNames[] = "^[e]$";
const char DefaultIgnoredParameterNames[] = "^[n]$";
+const unsigned DefaultLineCountThreshold = 0;
const char ErrorMessage[] =
"%select{variable|exception variable|loop variable|"
@@ -49,7 +50,8 @@ IdentifierLengthCheck::IdentifierLengthCheck(StringRef Name,
IgnoredExceptionVariableNames(IgnoredExceptionVariableNamesInput),
IgnoredParameterNamesInput(
Options.get("IgnoredParameterNames", DefaultIgnoredParameterNames)),
- IgnoredParameterNames(IgnoredParameterNamesInput) {}
+ IgnoredParameterNames(IgnoredParameterNamesInput),
+ LineCountThreshold(Options.get("LineCountThreshold", DefaultLineCountThreshold)) {}
void IdentifierLengthCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "MinimumVariableNameLength", MinimumVariableNameLength);
@@ -62,6 +64,7 @@ void IdentifierLengthCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "IgnoredExceptionVariableNames",
IgnoredExceptionVariableNamesInput);
Options.store(Opts, "IgnoredParameterNames", IgnoredParameterNamesInput);
+ Options.store(Opts, "LineCountThreshold", LineCountThreshold);
}
void IdentifierLengthCheck::registerMatchers(MatchFinder *Finder) {
@@ -85,6 +88,38 @@ void IdentifierLengthCheck::registerMatchers(MatchFinder *Finder) {
this);
}
+static unsigned countLinesToLastUse(const VarDecl* Var, const SourceManager* SrcMgr, ASTContext* Ctx){
+ const unsigned DeclLine = SrcMgr->getSpellingLineNumber(Var->getLocation());
+
+ class VarUseCallback : public MatchFinder::MatchCallback {
+ private:
+ unsigned* LastUseLineNumber;
+
+ public:
+ explicit VarUseCallback(unsigned* Output): LastUseLineNumber{Output} {}
+
+ void run(const MatchFinder::MatchResult &Result) override {
+ const DeclRefExpr *Use = Result.Nodes.getNodeAs<DeclRefExpr>("varUse");
+ if (Use && LastUseLineNumber) {
+ auto Loc = Use->getLocation();
+ unsigned UseLine = Result.SourceManager->getSpellingLineNumber(Loc);
+ *LastUseLineNumber = std::max(*LastUseLineNumber, UseLine);
+ }
+ }
+ };
+
+ unsigned LastUseLine = DeclLine;
+ VarUseCallback Callback{&LastUseLine};
+
+ auto Matcher = declRefExpr(to(varDecl(equalsNode(Var)))).bind("varUse");
+
+ MatchFinder Finder;
+ Finder.addMatcher(Matcher, &Callback);
+ Finder.matchAST(*Ctx);
+
+ return LastUseLine - DeclLine + 1;
+}
+
void IdentifierLengthCheck::check(const MatchFinder::MatchResult &Result) {
const auto *StandaloneVar = Result.Nodes.getNodeAs<VarDecl>("standaloneVar");
if (StandaloneVar) {
@@ -97,6 +132,9 @@ void IdentifierLengthCheck::check(const MatchFinder::MatchResult &Result) {
IgnoredVariableNames.match(VarName))
return;
+ if (LineCountThreshold > 0 && countLinesToLastUse(StandaloneVar, Result.SourceManager, Result.Context) <= LineCountThreshold)
+ return;
+
diag(StandaloneVar->getLocation(), ErrorMessage)
<< 0 << StandaloneVar << MinimumVariableNameLength;
}
@@ -111,6 +149,9 @@ void IdentifierLengthCheck::check(const MatchFinder::MatchResult &Result) {
IgnoredExceptionVariableNames.match(VarName))
return;
+ if (LineCountThreshold > 0 && countLinesToLastUse(ExceptionVarName, Result.SourceManager, Result.Context) <= LineCountThreshold)
+ return;
+
diag(ExceptionVarName->getLocation(), ErrorMessage)
<< 1 << ExceptionVarName << MinimumExceptionNameLength;
}
@@ -126,6 +167,9 @@ void IdentifierLengthCheck::check(const MatchFinder::MatchResult &Result) {
IgnoredLoopCounterNames.match(VarName))
return;
+ if (LineCountThreshold > 0 && countLinesToLastUse(LoopVar, Result.SourceManager, Result.Context) <= LineCountThreshold)
+ return;
+
diag(LoopVar->getLocation(), ErrorMessage)
<< 2 << LoopVar << MinimumLoopCounterNameLength;
}
@@ -141,6 +185,9 @@ void IdentifierLengthCheck::check(const MatchFinder::MatchResult &Result) {
IgnoredParameterNames.match(VarName))
return;
+ if (LineCountThreshold > 0 && countLinesToLastUse(ParamVar, Result.SourceManager, Result.Context) <= LineCountThreshold)
+ return;
+
diag(ParamVar->getLocation(), ErrorMessage)
<< 3 << ParamVar << MinimumParameterNameLength;
}
diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.h b/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.h
index 3adaf50bc57a1..2a59788260f8c 100644
--- a/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.h
@@ -42,6 +42,8 @@ class IdentifierLengthCheck : public ClangTidyCheck {
std::string IgnoredParameterNamesInput;
llvm::Regex IgnoredParameterNames;
+
+ const unsigned LineCountThreshold;
};
} // namespace clang::tidy::readability
>From ab5af5e216096827158bf36421b60b0cd6927a7b Mon Sep 17 00:00:00 2001
From: Alex Dutka <97711898+dutkalex at users.noreply.github.com>
Date: Sun, 8 Mar 2026 22:53:59 +0100
Subject: [PATCH 3/8] Document the added option
---
.../checks/readability/identifier-length.rst | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-length.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-length.rst
index c4d39a28a4cb8..ad1450fdb84bb 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-length.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-length.rst
@@ -18,6 +18,7 @@ The following options are described below:
- :option:`MinimumLoopCounterNameLength`, :option:`IgnoredLoopCounterNames`
- :option:`MinimumExceptionNameLength`,
:option:`IgnoredExceptionVariableNames`
+ - :option:`LineCountThreshold`
.. option:: MinimumVariableNameLength
@@ -121,3 +122,16 @@ The following options are described below:
catch (const std::exception& e) {
// ...
}
+
+.. option:: LineCountThreshold
+
+ Defines the minimum number of lines required between declaration and last
+ use for a diagnostic to be issued. The default value is 0.
+
+ .. code-block:: c++
+
+ // In this example, a warning will be issued if LineCountThreshold < N
+ int a = 0; // First line (declaration line)
+ a = 1; // Second line
+ // ...
+ last_use_of(a); // N-th line
>From 8d5dcabb0d20f69d0513d4c2790f4bab66080f21 Mon Sep 17 00:00:00 2001
From: Alex Dutka <97711898+dutkalex at users.noreply.github.com>
Date: Mon, 9 Mar 2026 09:16:49 +0100
Subject: [PATCH 4/8] Apply fixes suggested by clang-tidy
---
.../clang-tidy/readability/IdentifierLengthCheck.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp
index 4755588b70d18..fc0d112d53ff1 100644
--- a/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp
@@ -99,10 +99,10 @@ static unsigned countLinesToLastUse(const VarDecl* Var, const SourceManager* Src
explicit VarUseCallback(unsigned* Output): LastUseLineNumber{Output} {}
void run(const MatchFinder::MatchResult &Result) override {
- const DeclRefExpr *Use = Result.Nodes.getNodeAs<DeclRefExpr>("varUse");
+ const auto *Use = Result.Nodes.getNodeAs<DeclRefExpr>("varUse");
if (Use && LastUseLineNumber) {
auto Loc = Use->getLocation();
- unsigned UseLine = Result.SourceManager->getSpellingLineNumber(Loc);
+ const unsigned UseLine = Result.SourceManager->getSpellingLineNumber(Loc);
*LastUseLineNumber = std::max(*LastUseLineNumber, UseLine);
}
}
>From 61bee8adf80e0862f8b2018a9755879bf1fe3cd8 Mon Sep 17 00:00:00 2001
From: Alex Dutka <97711898+dutkalex at users.noreply.github.com>
Date: Mon, 9 Mar 2026 10:06:48 +0100
Subject: [PATCH 5/8] Add a ReleaseNotes entry
---
clang-tools-extra/docs/ReleaseNotes.rst | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 6e1a116a30bf8..767bdf73901d7 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -330,6 +330,11 @@ Changes in existing checks
<clang-tidy/checks/readability/suspicious-call-argument>` check by avoiding a
crash from invalid ``Abbreviations`` option.
+- Improve :doc:`readability-identifier-length
+ <clang-tidy/checks/readability/readability-identifier-length>` check by adding
+ a new option to silence warnings for short-lived variables, based on distance
+ between declaration and last use.
+
Removed checks
^^^^^^^^^^^^^^
>From a0db70839924e091b0422413736362befb464b4f Mon Sep 17 00:00:00 2001
From: Alex Dutka <97711898+dutkalex at users.noreply.github.com>
Date: Mon, 9 Mar 2026 10:10:08 +0100
Subject: [PATCH 6/8] Apply formatting
---
.../readability/IdentifierLengthCheck.cpp | 34 +++++++++++++------
1 file changed, 23 insertions(+), 11 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp
index fc0d112d53ff1..9a1e267c9b451 100644
--- a/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp
@@ -51,7 +51,8 @@ IdentifierLengthCheck::IdentifierLengthCheck(StringRef Name,
IgnoredParameterNamesInput(
Options.get("IgnoredParameterNames", DefaultIgnoredParameterNames)),
IgnoredParameterNames(IgnoredParameterNamesInput),
- LineCountThreshold(Options.get("LineCountThreshold", DefaultLineCountThreshold)) {}
+ LineCountThreshold(
+ Options.get("LineCountThreshold", DefaultLineCountThreshold)) {}
void IdentifierLengthCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "MinimumVariableNameLength", MinimumVariableNameLength);
@@ -88,21 +89,24 @@ void IdentifierLengthCheck::registerMatchers(MatchFinder *Finder) {
this);
}
-static unsigned countLinesToLastUse(const VarDecl* Var, const SourceManager* SrcMgr, ASTContext* Ctx){
+static unsigned countLinesToLastUse(const VarDecl *Var,
+ const SourceManager *SrcMgr,
+ ASTContext *Ctx) {
const unsigned DeclLine = SrcMgr->getSpellingLineNumber(Var->getLocation());
class VarUseCallback : public MatchFinder::MatchCallback {
- private:
- unsigned* LastUseLineNumber;
+ private:
+ unsigned *LastUseLineNumber;
- public:
- explicit VarUseCallback(unsigned* Output): LastUseLineNumber{Output} {}
+ public:
+ explicit VarUseCallback(unsigned *Output) : LastUseLineNumber{Output} {}
void run(const MatchFinder::MatchResult &Result) override {
const auto *Use = Result.Nodes.getNodeAs<DeclRefExpr>("varUse");
if (Use && LastUseLineNumber) {
auto Loc = Use->getLocation();
- const unsigned UseLine = Result.SourceManager->getSpellingLineNumber(Loc);
+ const unsigned UseLine =
+ Result.SourceManager->getSpellingLineNumber(Loc);
*LastUseLineNumber = std::max(*LastUseLineNumber, UseLine);
}
}
@@ -132,7 +136,9 @@ void IdentifierLengthCheck::check(const MatchFinder::MatchResult &Result) {
IgnoredVariableNames.match(VarName))
return;
- if (LineCountThreshold > 0 && countLinesToLastUse(StandaloneVar, Result.SourceManager, Result.Context) <= LineCountThreshold)
+ if (LineCountThreshold > 0 &&
+ countLinesToLastUse(StandaloneVar, Result.SourceManager,
+ Result.Context) <= LineCountThreshold)
return;
diag(StandaloneVar->getLocation(), ErrorMessage)
@@ -149,7 +155,9 @@ void IdentifierLengthCheck::check(const MatchFinder::MatchResult &Result) {
IgnoredExceptionVariableNames.match(VarName))
return;
- if (LineCountThreshold > 0 && countLinesToLastUse(ExceptionVarName, Result.SourceManager, Result.Context) <= LineCountThreshold)
+ if (LineCountThreshold > 0 &&
+ countLinesToLastUse(ExceptionVarName, Result.SourceManager,
+ Result.Context) <= LineCountThreshold)
return;
diag(ExceptionVarName->getLocation(), ErrorMessage)
@@ -167,7 +175,9 @@ void IdentifierLengthCheck::check(const MatchFinder::MatchResult &Result) {
IgnoredLoopCounterNames.match(VarName))
return;
- if (LineCountThreshold > 0 && countLinesToLastUse(LoopVar, Result.SourceManager, Result.Context) <= LineCountThreshold)
+ if (LineCountThreshold > 0 &&
+ countLinesToLastUse(LoopVar, Result.SourceManager, Result.Context) <=
+ LineCountThreshold)
return;
diag(LoopVar->getLocation(), ErrorMessage)
@@ -185,7 +195,9 @@ void IdentifierLengthCheck::check(const MatchFinder::MatchResult &Result) {
IgnoredParameterNames.match(VarName))
return;
- if (LineCountThreshold > 0 && countLinesToLastUse(ParamVar, Result.SourceManager, Result.Context) <= LineCountThreshold)
+ if (LineCountThreshold > 0 &&
+ countLinesToLastUse(ParamVar, Result.SourceManager, Result.Context) <=
+ LineCountThreshold)
return;
diag(ParamVar->getLocation(), ErrorMessage)
>From f80dc4032533328da90c3a26e7c778219dac24cb Mon Sep 17 00:00:00 2001
From: Alex Dutka <97711898+dutkalex at users.noreply.github.com>
Date: Tue, 10 Mar 2026 09:08:08 +0100
Subject: [PATCH 7/8] Fix release note ordering
---
clang-tools-extra/docs/ReleaseNotes.rst | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 767bdf73901d7..5ffbf7d23de0e 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -312,6 +312,11 @@ 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-identifier-length
+ <clang-tidy/checks/readability/readability-identifier-length>` check by adding
+ a new option to silence warnings for short-lived variables, based on distance
+ between declaration and last use.
+
- 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
@@ -330,11 +335,6 @@ Changes in existing checks
<clang-tidy/checks/readability/suspicious-call-argument>` check by avoiding a
crash from invalid ``Abbreviations`` option.
-- Improve :doc:`readability-identifier-length
- <clang-tidy/checks/readability/readability-identifier-length>` check by adding
- a new option to silence warnings for short-lived variables, based on distance
- between declaration and last use.
-
Removed checks
^^^^^^^^^^^^^^
>From 2b57d073ac31a398113185b9c47cea4640a58817 Mon Sep 17 00:00:00 2001
From: Alex Dutka <97711898+dutkalex at users.noreply.github.com>
Date: Sun, 15 Mar 2026 15:44:57 +0100
Subject: [PATCH 8/8] Fix path error in the release notes
---
clang-tools-extra/docs/ReleaseNotes.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 5ffbf7d23de0e..12116b688ff46 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -313,8 +313,8 @@ Changes in existing checks
it easier to see which specific enumerators need explicit initialization.
- Improved :doc:`readability-identifier-length
- <clang-tidy/checks/readability/readability-identifier-length>` check by adding
- a new option to silence warnings for short-lived variables, based on distance
+ <clang-tidy/checks/readability/identifier-length>` check by adding a new
+ option to silence warnings for short-lived variables, based on distance
between declaration and last use.
- Improved :doc:`readability-non-const-parameter
More information about the cfe-commits
mailing list