https://github.com/NyuB updated https://github.com/llvm/llvm-project/pull/181502
>From 0068bdef22ae89a81631a2a60ce339a96252ce38 Mon Sep 17 00:00:00 2001 From: Brice Decaestecker <[email protected]> Date: Sat, 21 Feb 2026 14:29:27 +0100 Subject: [PATCH] Avoid identifier-naming concatenating multiple (pre/su)ffixes, introducing options to strip out any other known (pre/su)ffix before renaming --- .../readability/IdentifierNamingCheck.cpp | 46 +++++++++++++--- .../readability/IdentifierNamingCheck.h | 23 +++++--- clang-tools-extra/docs/ReleaseNotes.rst | 5 ++ .../checks/readability/identifier-naming.rst | 54 +++++++++++++++++++ .../readability/identifier-naming-trim.cpp | 33 ++++++++++++ 5 files changed, 146 insertions(+), 15 deletions(-) create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-trim.cpp diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp index 83fc3727cb5c8..f425148aac40a 100644 --- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp @@ -291,8 +291,10 @@ IdentifierNamingCheck::FileStyle IdentifierNamingCheck::getFileStyleFromOptions( const bool IgnoreMainLike = Options.get("IgnoreMainLikeFunctions", false); const bool CheckAnonFieldInParent = Options.get("CheckAnonFieldInParent", false); - return {std::move(Styles), std::move(HNOption), IgnoreMainLike, - CheckAnonFieldInParent}; + const bool TrimPrefixes = Options.get("TrimPrefixes", false); + const bool TrimSuffixes = Options.get("TrimSuffixes", false); + return {std::move(Styles), std::move(HNOption), IgnoreMainLike, + CheckAnonFieldInParent, TrimPrefixes, TrimSuffixes}; } std::string IdentifierNamingCheck::HungarianNotation::getDeclTypeName( @@ -859,6 +861,8 @@ void IdentifierNamingCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { MainFileStyle->isIgnoringMainLikeFunction()); Options.store(Opts, "CheckAnonFieldInParent", MainFileStyle->isCheckingAnonFieldInParentScope()); + Options.store(Opts, "TrimPrefixes", MainFileStyle->isTrimmingPrefixes()); + Options.store(Opts, "TrimSuffixes", MainFileStyle->isTrimmingSuffixes()); } bool IdentifierNamingCheck::matchesStyle( @@ -1084,11 +1088,34 @@ bool IdentifierNamingCheck::isParamInMainLikeFunction( return Matcher.match(FDecl->getName()); } +static void trimPrefixesAndSuffixes( + StringRef &Mid, + ArrayRef<std::optional<IdentifierNamingCheck::NamingStyle>> NamingStyles, + bool TrimPrefixes, bool TrimSuffixes) { + bool LoopWhileToRemove = true; + while (LoopWhileToRemove) { + LoopWhileToRemove = false; + for (unsigned I = 0; I < SK_Count; ++I) { + if (const std::optional<IdentifierNamingCheck::NamingStyle> &OtherStyle = + NamingStyles[I]) { + while (TrimPrefixes && !OtherStyle->Prefix.empty() && + Mid.consume_front(OtherStyle->Prefix)) + LoopWhileToRemove = true; + + while (TrimSuffixes && !OtherStyle->Suffix.empty() && + Mid.consume_back(OtherStyle->Suffix)) + LoopWhileToRemove = true; + } + } + } +} + std::string IdentifierNamingCheck::fixupWithStyle( StringRef Type, StringRef Name, const IdentifierNamingCheck::NamingStyle &Style, + ArrayRef<std::optional<IdentifierNamingCheck::NamingStyle>> NamingStyles, const IdentifierNamingCheck::HungarianNotationOption &HNOption, - const Decl *D) const { + bool TrimPrefixes, bool TrimSuffixes, const Decl *D) const { Name.consume_front(Style.Prefix); Name.consume_back(Style.Suffix); std::string Fixed = fixupWithCase( @@ -1108,6 +1135,7 @@ std::string IdentifierNamingCheck::fixupWithStyle( } } StringRef Mid = StringRef(Fixed).trim("_"); + trimPrefixesAndSuffixes(Mid, NamingStyles, TrimPrefixes, TrimSuffixes); if (Mid.empty()) Mid = "_"; @@ -1337,7 +1365,8 @@ IdentifierNamingCheck::getFailureInfo( SourceLocation Location, ArrayRef<std::optional<IdentifierNamingCheck::NamingStyle>> NamingStyles, const IdentifierNamingCheck::HungarianNotationOption &HNOption, - StyleKind SK, const SourceManager &SM, bool IgnoreFailedSplit) const { + StyleKind SK, const SourceManager &SM, bool IgnoreFailedSplit, + bool TrimPrefixes, bool TrimSuffixes) const { if (SK == SK_Invalid) return std::nullopt; @@ -1359,7 +1388,8 @@ IdentifierNamingCheck::getFailureInfo( IdentifierNamingCheck::CT_LowerCase); llvm::replace(KindName, '_', ' '); - std::string Fixup = fixupWithStyle(Type, Name, Style, HNOption, ND); + std::string Fixup = fixupWithStyle(Type, Name, Style, NamingStyles, HNOption, + TrimPrefixes, TrimSuffixes, ND); if (StringRef(Fixup) == Name) { if (!IgnoreFailedSplit) { LLVM_DEBUG(Location.print(llvm::dbgs(), SM); @@ -1390,7 +1420,8 @@ IdentifierNamingCheck::getDeclFailureInfo(const NamedDecl *Decl, findStyleKind(Decl, FileStyle.getStyles(), FileStyle.isIgnoringMainLikeFunction(), FileStyle.isCheckingAnonFieldInParentScope()), - SM, IgnoreFailedSplit); + SM, IgnoreFailedSplit, FileStyle.isTrimmingPrefixes(), + FileStyle.isTrimmingSuffixes()); } std::optional<RenamerClangTidyCheck::FailureInfo> @@ -1408,7 +1439,8 @@ IdentifierNamingCheck::getMacroFailureInfo(const Token &MacroNameTok, return getFailureInfo("", MacroNameTok.getIdentifierInfo()->getName(), nullptr, Loc, Style.getStyles(), Style.getHNOption(), - UsedKind, SM, IgnoreFailedSplit); + UsedKind, SM, IgnoreFailedSplit, + Style.isTrimmingPrefixes(), Style.isTrimmingSuffixes()); } RenamerClangTidyCheck::DiagInfo diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h index b016556cc2ab8..aa746228b62c7 100644 --- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h +++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.h @@ -128,10 +128,11 @@ class IdentifierNamingCheck final : public RenamerClangTidyCheck { FileStyle() : IsActive(false), IgnoreMainLikeFunctions(false) {} FileStyle(SmallVectorImpl<std::optional<NamingStyle>> &&Styles, HungarianNotationOption HNOption, bool IgnoreMainLike, - bool CheckAnonFieldInParent) + bool CheckAnonFieldInParent, bool TrimPrefixes, bool TrimSuffixes) : Styles(std::move(Styles)), HNOption(std::move(HNOption)), IsActive(true), IgnoreMainLikeFunctions(IgnoreMainLike), - CheckAnonFieldInParentScope(CheckAnonFieldInParent) {} + CheckAnonFieldInParentScope(CheckAnonFieldInParent), + TrimPrefixes(TrimPrefixes), TrimSuffixes(TrimSuffixes) {} ArrayRef<std::optional<NamingStyle>> getStyles() const { assert(IsActive); @@ -149,6 +150,8 @@ class IdentifierNamingCheck final : public RenamerClangTidyCheck { bool isCheckingAnonFieldInParentScope() const { return CheckAnonFieldInParentScope; } + bool isTrimmingPrefixes() const { return TrimPrefixes; } + bool isTrimmingSuffixes() const { return TrimSuffixes; } private: SmallVector<std::optional<NamingStyle>, 0> Styles; @@ -156,6 +159,8 @@ class IdentifierNamingCheck final : public RenamerClangTidyCheck { bool IsActive; bool IgnoreMainLikeFunctions; bool CheckAnonFieldInParentScope; + bool TrimPrefixes; + bool TrimSuffixes; }; IdentifierNamingCheck::FileStyle @@ -173,11 +178,12 @@ class IdentifierNamingCheck final : public RenamerClangTidyCheck { const IdentifierNamingCheck::HungarianNotationOption &HNOption, IdentifierNamingCheck::CaseType Case) const; - std::string - fixupWithStyle(StringRef Type, StringRef Name, - const IdentifierNamingCheck::NamingStyle &Style, - const IdentifierNamingCheck::HungarianNotationOption &HNOption, - const Decl *D) const; + std::string fixupWithStyle( + StringRef Type, StringRef Name, + const IdentifierNamingCheck::NamingStyle &Style, + ArrayRef<std::optional<IdentifierNamingCheck::NamingStyle>> NamingStyles, + const IdentifierNamingCheck::HungarianNotationOption &HNOption, + bool TrimPrefixes, bool TrimSuffixes, const Decl *D) const; StyleKind findStyleKind( const NamedDecl *D, @@ -189,7 +195,8 @@ class IdentifierNamingCheck final : public RenamerClangTidyCheck { SourceLocation Location, ArrayRef<std::optional<IdentifierNamingCheck::NamingStyle>> NamingStyles, const IdentifierNamingCheck::HungarianNotationOption &HNOption, - StyleKind SK, const SourceManager &SM, bool IgnoreFailedSplit) const; + StyleKind SK, const SourceManager &SM, bool IgnoreFailedSplit, + bool TrimPrefixes, bool TrimSuffixes) const; bool isParamInMainLikeFunction(const ParmVarDecl &ParmDecl, bool IncludeMainLike) const; diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 77be492d4093e..40b69eff9e629 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -261,6 +261,11 @@ Changes in existing checks <clang-tidy/checks/readability/suspicious-call-argument>` check by avoiding a crash from invalid ``Abbreviations`` option. +- Improved :doc:`readability-identifier-naming + <clang-tidy/checks/readability/identifier-naming>` check by adding the + `TrimPrefixes` and `TrimSuffixes` options, to trim all known other prefixes + and suffixes when fixing an identifier + Removed checks ^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-naming.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-naming.rst index c8f87dcba8c0a..8642869719533 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-naming.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/identifier-naming.rst @@ -85,6 +85,8 @@ The available options are summarized below: - :option:`CheckAnonFieldInParent` - :option:`GetConfigPerFile` - :option:`IgnoreMainLikeFunctions` + - :option:`TrimPrefixes` + - :option:`TrimSuffixes` **Specific options** @@ -2652,6 +2654,58 @@ After: template <template <typename> class pre_tpl_parameter_post, int COUNT_params, typename... TYPE_parameters> +.. option:: TrimPrefixes + + When set to `true`, the suggested fix for identifiers that have the wrong + prefix will be trimmed of all known prefixes from other options. + Defaults to `false`. + +For example using values of: + + - ParameterPrefix of ``p_`` + - MemberPrefix of ``m_`` + - TrimPrefix of ``true`` + +Identifies and/or transforms function parameter names as follows: + +Before: + +.. code-block:: c++ + + void f(int m_n) {} + +After: + +.. code-block:: c++ + + void f(int p_n) {} + +.. option:: TrimSuffixes + + When set to `true`, the suggested fix for identifiers that have the wrong + suffix will be trimmed of all known suffixes from other options. + Defaults to `false`. + +For example using values of: + + - ParameterSuffix of ``_p`` + - MemberSuffix of ``_m`` + - TrimSuffix of ``true`` + +Identifies and/or transforms function parameter names as follows: + +Before: + +.. code-block:: c++ + + void f(int n_m) {} + +After: + +.. code-block:: c++ + + void f(int n_p) {} + .. option:: TypeAliasCase When defined, the check will ensure type alias names conform to the diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-trim.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-trim.cpp new file mode 100644 index 0000000000000..1f88f446a9453 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-trim.cpp @@ -0,0 +1,33 @@ +// RUN: %check_clang_tidy -std=c++20 %s readability-identifier-naming %t -- \ +// RUN: -config='{CheckOptions: { \ +// RUN: readability-identifier-naming.MemberPrefix: 'm_', \ +// RUN: readability-identifier-naming.MemberSuffix: '_', \ +// RUN: readability-identifier-naming.ParameterPrefix: 'p_', \ +// RUN: readability-identifier-naming.TrimPrefixes: 1, \ +// RUN: readability-identifier-naming.TrimSuffixes: 1, \ +// RUN: }}' \ +// RUN: -header-filter='' \ +// RUN: -- -fno-delayed-template-parsing -Dbad_macro \ +// RUN: -I%S/Inputs/identifier-naming \ +// RUN: -isystem %S/Inputs/identifier-naming/system + +// clang-format off + +struct Triple { + Triple(int m_wrong_, int missing, int p_ok): p_wrong_(m_wrong_), missing(missing), m_ok_(p_ok) {} + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: invalid case style for parameter 'm_wrong_' + // CHECK-MESSAGES: :[[@LINE-2]]:30: warning: invalid case style for parameter 'missing' + // CHECK-FIXES: Triple(int p_wrong, int p_missing, int p_ok): m_wrong_(p_wrong), m_missing_(p_missing), m_ok_(p_ok) {} + int p_wrong_; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for member 'p_wrong_' + // CHECK-FIXES: int m_wrong_; + int missing; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for member 'missing' + // CHECK-FIXES: int m_missing_; + int m_ok_; +}; + +void multipleWrong(int m_m_wrong1, int wrong2__) {} +// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: invalid case style for parameter 'm_m_wrong1' +// CHECK-MESSAGES: :[[@LINE-2]]:40: warning: invalid case style for parameter 'wrong2__' +// CHECK-FIXES: void multipleWrong(int p_wrong1, int p_wrong2) {} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
