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 <[email protected]> Date: Sun, 8 Mar 2026 19:47:13 +0100 Subject: [PATCH 01/17] 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 <[email protected]> Date: Sun, 8 Mar 2026 19:49:24 +0100 Subject: [PATCH 02/17] 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 <[email protected]> Date: Sun, 8 Mar 2026 22:53:59 +0100 Subject: [PATCH 03/17] 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 <[email protected]> Date: Mon, 9 Mar 2026 09:16:49 +0100 Subject: [PATCH 04/17] 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 <[email protected]> Date: Mon, 9 Mar 2026 10:06:48 +0100 Subject: [PATCH 05/17] 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 <[email protected]> Date: Mon, 9 Mar 2026 10:10:08 +0100 Subject: [PATCH 06/17] 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 <[email protected]> Date: Tue, 10 Mar 2026 09:08:08 +0100 Subject: [PATCH 07/17] 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 <[email protected]> Date: Sun, 15 Mar 2026 15:44:57 +0100 Subject: [PATCH 08/17] 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 >From d1ca409ccc87ecf6741206e89862c519b8d2f330 Mon Sep 17 00:00:00 2001 From: Alex Dutka <[email protected]> Date: Fri, 10 Apr 2026 14:02:34 +0200 Subject: [PATCH 09/17] move line count test to a dedicated file --- ...identifier-length-line-count-threshold.cpp | 52 +++++++++++++++++++ .../readability/identifier-length.cpp | 33 +++++------- 2 files changed, 64 insertions(+), 21 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/identifier-length-line-count-threshold.cpp diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-length-line-count-threshold.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-length-line-count-threshold.cpp new file mode 100644 index 0000000000000..6848ecc455788 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-length-line-count-threshold.cpp @@ -0,0 +1,52 @@ +// RUN: %check_clang_tidy %s readability-identifier-length %t \ +// RUN: -config='{CheckOptions: \ +// RUN: {readability-identifier-length.LineCountThreshold: 3}}' \ +// RUN: -- -fexceptions + +struct myexcept { + int val; +}; + +template<typename... Ts> +void doIt(Ts...); + +void shouldWarn(int z) +// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: parameter name 'z' is too short, expected at least 3 characters [readability-identifier-length] +{ + int i = 5; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: variable name 'i' is too short, expected at least 3 characters [readability-identifier-length] + + 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(i); + doIt(m); + } + + try { + 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(x); + } +} + +void shouldNotWarn(int m) +{ + doIt(m); + + int v = 5; + doIt(v); + + for (int a = 0; a < 42; ++a) + { + doIt(a); + } + + try { + doIt(); + } catch (const myexcept &x) { + doIt(x); + } +} 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 1972862d05f3e..33b0ac7ce7aa3 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]$", readability-identifier-length.LineCountThreshold: 1}}' \ +// RUN: {readability-identifier-length.IgnoredVariableNames: "^[xy]$"}}' \ // RUN: -- -fexceptions struct myexcept { @@ -11,8 +11,7 @@ struct simpleexcept { int other; }; -template<typename... Ts> -void doIt(Ts...); +void doIt(); void tooShortVariableNames(int z) // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: parameter name 'z' is too short, expected at least 3 characters [readability-identifier-length] @@ -26,47 +25,39 @@ 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(i, jj, m); + doIt(); } try { - doIt(z); + doIt(); } 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(x); + doIt(); } } -void longEnoughVariableNames(int n, int m) // argument 'n' ignored by default configuration, 'm' is only used on this line +void longEnoughVariableNames(int n) // argument 'n' ignored by default configuration { int var = 5; for (int i = 0; i < 42; ++i) // 'i' is default allowed, for historical reasons { - doIt(var, i); - } - - for (int a = 0; a < 42; ++a) // 'a' is only used on this line - { - doIt(); + doIt(); } for (int kk = 0; kk < 42; ++kk) { - doIt(kk); + doIt(); } try { - doIt(n); + doIt(); } catch (const simpleexcept &e) // ignored by default configuration { - doIt(e); + doIt(); } catch (const myexcept &ex) { - doIt(ex); - } catch (const int &d) { doIt(d); } // 'd' is only used on this line + doIt(); + } int x = 5; // ignored by configuration - ++x; - - int b = 0; // 'b' is only used on this line } >From 1541b121699f08d7284fda920bf07c85124b2eb8 Mon Sep 17 00:00:00 2001 From: Alex Dutka <[email protected]> Date: Sat, 11 Apr 2026 17:09:57 +0200 Subject: [PATCH 10/17] fix expected message --- .../readability/identifier-length-line-count-threshold.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-length-line-count-threshold.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-length-line-count-threshold.cpp index 6848ecc455788..fbeed11b4a8cd 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-length-line-count-threshold.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-length-line-count-threshold.cpp @@ -11,7 +11,7 @@ template<typename... Ts> void doIt(Ts...); void shouldWarn(int z) -// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: parameter name 'z' is too short, expected at least 3 characters [readability-identifier-length] +// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: parameter name 'z' is too short, expected at least 3 characters [readability-identifier-length] { int i = 5; // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: variable name 'i' is too short, expected at least 3 characters [readability-identifier-length] >From 46f9690fe47cf96b4671fb18dc7d10cb71ba46e4 Mon Sep 17 00:00:00 2001 From: Alex Dutka <[email protected]> Date: Sat, 11 Apr 2026 18:50:31 +0200 Subject: [PATCH 11/17] rewrite last use line search as allDeclRefExprs + transform_reduce --- .../readability/IdentifierLengthCheck.cpp | 40 +++++++------------ 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp index 9a1e267c9b451..743422d827351 100644 --- a/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp @@ -8,6 +8,7 @@ #include "IdentifierLengthCheck.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "../utils/DeclRefExprUtils.h" using namespace clang::ast_matchers; @@ -92,34 +93,21 @@ void IdentifierLengthCheck::registerMatchers(MatchFinder *Finder) { 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 auto *Use = Result.Nodes.getNodeAs<DeclRefExpr>("varUse"); - if (Use && LastUseLineNumber) { - auto Loc = Use->getLocation(); - const unsigned UseLine = - Result.SourceManager->getSpellingLineNumber(Loc); - *LastUseLineNumber = std::max(*LastUseLineNumber, UseLine); - } - } - }; - - unsigned LastUseLine = DeclLine; - VarUseCallback Callback{&LastUseLine}; + const auto *ParentScope = llvm::dyn_cast<FunctionDecl>(Var->getDeclContext()); + if (ParentScope == nullptr) { + return 1; + } - auto Matcher = declRefExpr(to(varDecl(equalsNode(Var)))).bind("varUse"); + auto AllRefs = + utils::decl_ref_expr::allDeclRefExprs(*Var, *ParentScope, *Ctx); - MatchFinder Finder; - Finder.addMatcher(Matcher, &Callback); - Finder.matchAST(*Ctx); + const unsigned DeclLine = SrcMgr->getSpellingLineNumber(Var->getLocation()); + const unsigned LastUseLine = std::transform_reduce( + AllRefs.begin(), AllRefs.end(), DeclLine, + [](unsigned Lhs, unsigned Rhs) -> unsigned { return std::max(Lhs, Rhs); }, + [&](DeclRefExpr const *RefToVar) -> unsigned { + return SrcMgr->getSpellingLineNumber(RefToVar->getLocation()); + }); return LastUseLine - DeclLine + 1; } >From 2f1c5834f801bae6f5654faec87e00003b73b988 Mon Sep 17 00:00:00 2001 From: Alex Dutka <[email protected]> Date: Sat, 11 Apr 2026 19:27:31 +0200 Subject: [PATCH 12/17] improve documentation --- clang-tools-extra/docs/ReleaseNotes.rst | 10 +++++----- .../checks/readability/identifier-length.rst | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index e33286d5df57a..600f34bd1cafe 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -311,9 +311,9 @@ Changes in existing checks - Improved :doc:`cppcoreguidelines-missing-std-forward <clang-tidy/checks/cppcoreguidelines/missing-std-forward>` check: - + - Fixed false positive for constrained template parameters - + - Fixed false positive with ``std::forward`` in brace-init and paren-init lambda captures such as ``[t{std::forward<T>(t)}]``. @@ -474,15 +474,15 @@ Changes in existing checks - Improved :doc:`readability-identifier-length <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. + option, named `LineCountThreshold`, to silence warnings for short-lived + variables, based on distance between declaration and last use. - Improved :doc:`readability-identifier-naming <clang-tidy/checks/readability/identifier-naming>` check: - Fixed incorrect naming style application to C++17 structured bindings. - - Fixed a false positive where function templates could be diagnosed as generic + - Fixed a false positive where function templates could be diagnosed as generic identifiers when `DefaultCase` was enabled. - Improved :doc:`readability-implicit-bool-conversion 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 ad1450fdb84bb..13168aba07d82 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 @@ -126,7 +126,8 @@ The following options are described below: .. 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. + use for a diagnostic to be issued. The default value for this option is 0, + which corresponds to all variables being flagged. .. code-block:: c++ >From 3a00eff134bfcb9c14fee0e8a7355a316f72a718 Mon Sep 17 00:00:00 2001 From: Alex Dutka <[email protected]> Date: Sat, 11 Apr 2026 19:34:54 +0200 Subject: [PATCH 13/17] add tests with variables with multiple usages --- .../readability/identifier-length-line-count-threshold.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-length-line-count-threshold.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-length-line-count-threshold.cpp index fbeed11b4a8cd..b666dbdbcd7bd 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-length-line-count-threshold.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-length-line-count-threshold.cpp @@ -15,6 +15,7 @@ void shouldWarn(int z) { int i = 5; // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: variable name 'i' is too short, expected at least 3 characters [readability-identifier-length] + ++i; 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] @@ -37,6 +38,7 @@ void shouldNotWarn(int m) doIt(m); int v = 5; + ++v; doIt(v); for (int a = 0; a < 42; ++a) >From 2fe04649fa844bdc4141947e2f0d6aa2fd8806db Mon Sep 17 00:00:00 2001 From: Alex Dutka <[email protected]> Date: Sat, 11 Apr 2026 19:41:42 +0200 Subject: [PATCH 14/17] add tests with macros --- .../identifier-length-line-count-threshold.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-length-line-count-threshold.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-length-line-count-threshold.cpp index b666dbdbcd7bd..c786c90970e8e 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-length-line-count-threshold.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-length-line-count-threshold.cpp @@ -10,6 +10,8 @@ struct myexcept { template<typename... Ts> void doIt(Ts...); +#define MY_MACRO(arg) doIt(arg, arg) + void shouldWarn(int z) // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: parameter name 'z' is too short, expected at least 3 characters [readability-identifier-length] { @@ -31,6 +33,11 @@ void shouldWarn(int z) { doIt(x); } + + int a = 0; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: variable name 'a' is too short, expected at least 3 characters [readability-identifier-length] + ++a; + MY_MACRO(a); } void shouldNotWarn(int m) @@ -51,4 +58,7 @@ void shouldNotWarn(int m) } catch (const myexcept &x) { doIt(x); } + + int a = 0; + MY_MACRO(a); } >From 843a28c6198e8c33e907352e16064bd57efb3cc6 Mon Sep 17 00:00:00 2001 From: Alex Dutka <[email protected]> Date: Sun, 12 Apr 2026 00:01:48 +0200 Subject: [PATCH 15/17] Revert unrelated changes --- clang-tools-extra/docs/ReleaseNotes.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 600f34bd1cafe..8c69960de9018 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -311,9 +311,9 @@ Changes in existing checks - Improved :doc:`cppcoreguidelines-missing-std-forward <clang-tidy/checks/cppcoreguidelines/missing-std-forward>` check: - + - Fixed false positive for constrained template parameters - + - Fixed false positive with ``std::forward`` in brace-init and paren-init lambda captures such as ``[t{std::forward<T>(t)}]``. @@ -482,7 +482,7 @@ Changes in existing checks - Fixed incorrect naming style application to C++17 structured bindings. - - Fixed a false positive where function templates could be diagnosed as generic + - Fixed a false positive where function templates could be diagnosed as generic identifiers when `DefaultCase` was enabled. - Improved :doc:`readability-implicit-bool-conversion >From 9d3b2072784b709defe19167e6fb66ce589f711a Mon Sep 17 00:00:00 2001 From: Alex Dutka <[email protected]> Date: Sun, 12 Apr 2026 00:30:26 +0200 Subject: [PATCH 16/17] format --- .../clang-tidy/readability/IdentifierLengthCheck.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp index 743422d827351..f59c5731e2558 100644 --- a/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp @@ -7,8 +7,8 @@ //===----------------------------------------------------------------------===// #include "IdentifierLengthCheck.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" #include "../utils/DeclRefExprUtils.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" using namespace clang::ast_matchers; @@ -94,9 +94,8 @@ static unsigned countLinesToLastUse(const VarDecl *Var, const SourceManager *SrcMgr, ASTContext *Ctx) { const auto *ParentScope = llvm::dyn_cast<FunctionDecl>(Var->getDeclContext()); - if (ParentScope == nullptr) { + if (ParentScope == nullptr) return 1; - } auto AllRefs = utils::decl_ref_expr::allDeclRefExprs(*Var, *ParentScope, *Ctx); @@ -105,7 +104,7 @@ static unsigned countLinesToLastUse(const VarDecl *Var, const unsigned LastUseLine = std::transform_reduce( AllRefs.begin(), AllRefs.end(), DeclLine, [](unsigned Lhs, unsigned Rhs) -> unsigned { return std::max(Lhs, Rhs); }, - [&](DeclRefExpr const *RefToVar) -> unsigned { + [&](const DeclRefExpr *RefToVar) -> unsigned { return SrcMgr->getSpellingLineNumber(RefToVar->getLocation()); }); >From 5664d6c9116de4b2f15cbf5a8fdb5c47c941435d Mon Sep 17 00:00:00 2001 From: Alex Dutka <[email protected]> Date: Sun, 12 Apr 2026 18:02:24 +0200 Subject: [PATCH 17/17] refactor using std::optional --- .../readability/IdentifierLengthCheck.cpp | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp index f59c5731e2558..7182d424c0273 100644 --- a/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/IdentifierLengthCheck.cpp @@ -90,12 +90,12 @@ void IdentifierLengthCheck::registerMatchers(MatchFinder *Finder) { this); } -static unsigned countLinesToLastUse(const VarDecl *Var, - const SourceManager *SrcMgr, - ASTContext *Ctx) { +static std::optional<unsigned> countLinesToLastUse(const VarDecl *Var, + const SourceManager *SrcMgr, + ASTContext *Ctx) { const auto *ParentScope = llvm::dyn_cast<FunctionDecl>(Var->getDeclContext()); if (ParentScope == nullptr) - return 1; + return std::nullopt; auto AllRefs = utils::decl_ref_expr::allDeclRefExprs(*Var, *ParentScope, *Ctx); @@ -111,6 +111,18 @@ static unsigned countLinesToLastUse(const VarDecl *Var, return LastUseLine - DeclLine + 1; } +static bool isShortLived(const VarDecl *Var, const SourceManager *SrcMgr, + ASTContext *Ctx, unsigned LineCountThreshold) { + if (LineCountThreshold == 0) + return false; + + std::optional<unsigned> LineCount = countLinesToLastUse(Var, SrcMgr, Ctx); + if (LineCount && LineCount.value() <= LineCountThreshold) + return true; + + return false; +} + void IdentifierLengthCheck::check(const MatchFinder::MatchResult &Result) { const auto *StandaloneVar = Result.Nodes.getNodeAs<VarDecl>("standaloneVar"); if (StandaloneVar) { @@ -123,9 +135,8 @@ void IdentifierLengthCheck::check(const MatchFinder::MatchResult &Result) { IgnoredVariableNames.match(VarName)) return; - if (LineCountThreshold > 0 && - countLinesToLastUse(StandaloneVar, Result.SourceManager, - Result.Context) <= LineCountThreshold) + if (isShortLived(StandaloneVar, Result.SourceManager, Result.Context, + LineCountThreshold)) return; diag(StandaloneVar->getLocation(), ErrorMessage) @@ -142,9 +153,8 @@ void IdentifierLengthCheck::check(const MatchFinder::MatchResult &Result) { IgnoredExceptionVariableNames.match(VarName)) return; - if (LineCountThreshold > 0 && - countLinesToLastUse(ExceptionVarName, Result.SourceManager, - Result.Context) <= LineCountThreshold) + if (isShortLived(ExceptionVarName, Result.SourceManager, Result.Context, + LineCountThreshold)) return; diag(ExceptionVarName->getLocation(), ErrorMessage) @@ -162,9 +172,8 @@ void IdentifierLengthCheck::check(const MatchFinder::MatchResult &Result) { IgnoredLoopCounterNames.match(VarName)) return; - if (LineCountThreshold > 0 && - countLinesToLastUse(LoopVar, Result.SourceManager, Result.Context) <= - LineCountThreshold) + if (isShortLived(LoopVar, Result.SourceManager, Result.Context, + LineCountThreshold)) return; diag(LoopVar->getLocation(), ErrorMessage) @@ -182,9 +191,8 @@ void IdentifierLengthCheck::check(const MatchFinder::MatchResult &Result) { IgnoredParameterNames.match(VarName)) return; - if (LineCountThreshold > 0 && - countLinesToLastUse(ParamVar, Result.SourceManager, Result.Context) <= - LineCountThreshold) + if (isShortLived(ParamVar, Result.SourceManager, Result.Context, + LineCountThreshold)) return; diag(ParamVar->getLocation(), ErrorMessage) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
