[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
Sun Mar 8 14:54:41 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/3] 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/3] 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/3] 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
More information about the cfe-commits
mailing list