https://github.com/NyuB updated https://github.com/llvm/llvm-project/pull/181502
>From aef707048db7392f0dc4006d85fd9cc5e5031ef1 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 | 45 +++++++++++++--- .../readability/IdentifierNamingCheck.h | 23 +++++--- clang-tools-extra/docs/ReleaseNotes.rst | 5 ++ .../checks/readability/identifier-naming.rst | 54 +++++++++++++++++++ .../readability/identifier-naming-trim.cpp | 54 +++++++++++++++++++ 5 files changed, 166 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 17fbfcf1fb181..b7d43e731dfcd 100644 --- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp @@ -290,8 +290,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( @@ -858,6 +860,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( @@ -1083,11 +1087,33 @@ bool IdentifierNamingCheck::isParamInMainLikeFunction( return Matcher.match(FDecl->getName()); } +static void trimPrefixesAndSuffixes( + StringRef &Mid, + ArrayRef<std::optional<IdentifierNamingCheck::NamingStyle>> NamingStyles, + bool TrimPrefixes, bool TrimSuffixes) { + bool Changed = true; + while (Changed) { + Changed = false; + for (const auto &OtherStyle : NamingStyles) { + if (OtherStyle) { + while (TrimPrefixes && !OtherStyle->Prefix.empty() && + Mid.consume_front(OtherStyle->Prefix)) + Changed = true; + + while (TrimSuffixes && !OtherStyle->Suffix.empty() && + Mid.consume_back(OtherStyle->Suffix)) + Changed = 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( @@ -1107,6 +1133,7 @@ std::string IdentifierNamingCheck::fixupWithStyle( } } StringRef Mid = StringRef(Fixed).trim("_"); + trimPrefixesAndSuffixes(Mid, NamingStyles, TrimPrefixes, TrimSuffixes); if (Mid.empty()) Mid = "_"; @@ -1336,7 +1363,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; @@ -1358,7 +1386,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); @@ -1389,7 +1418,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> @@ -1407,7 +1437,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 0afc7e2246816..ba1ccd6be99e3 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 c9a170a9e8660..6b7d007d7262e 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -363,6 +363,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-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. + - Improved :doc:`readability-implicit-bool-conversion <clang-tidy/checks/readability/implicit-bool-conversion>` check by fixing a false positive where `AllowPointerConditions` and `AllowIntegerConditions` 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..fa6df081e7613 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. Default + is `false`. + +For example using values of: + + - ParameterPrefix of ``p_`` + - MemberPrefix of ``m_`` + - TrimPrefixes 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. Default + is `false`. + +For example using values of: + + - ParameterSuffix of ``_p`` + - MemberSuffix of ``_m`` + - TrimSuffixes 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..7f0e5656653ee --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming-trim.cpp @@ -0,0 +1,54 @@ +// RUN: %check_clang_tidy %s readability-identifier-naming %t -- \ +// RUN: -config='{CheckOptions: { \ +// RUN: readability-identifier-naming.GlobalVariablePrefix: 'g_', \ +// RUN: readability-identifier-naming.MacroDefinitionPrefix: 'M_', \ +// RUN: readability-identifier-naming.MemberPrefix: 'm_', \ +// RUN: readability-identifier-naming.MemberSuffix: '_', \ +// RUN: readability-identifier-naming.ParameterPrefix: 'p_', \ +// RUN: readability-identifier-naming.TemplateParameterPrefix: t_, \ +// 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 + +#include <system-header.h> + +#define m_MACRO(arg) void f(int arg) {} +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for macro definition 'm_MACRO' +// CHECK-FIXES: #define M_MACRO(arg) void f(int arg) {} + +m_MACRO(m_wrong); +// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: invalid case style for parameter 'm_wrong' +// CHECK-FIXES: M_MACRO(p_wrong); + +SYSTEM_MACRO(m_wrong); +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: invalid case style for global variable 'm_wrong' +// CHECK-FIXES: SYSTEM_MACRO(g_wrong); + +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) {} + +template<typename p_t> +// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: invalid case style for template parameter 'p_t' +// CHECK-FIXES: template<typename t_t> +void f(p_t p_arg) {} +// CHECK-FIXES: void f(t_t p_arg) {} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
