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

Reply via email to