https://github.com/HazardyKnusperkeks updated 
https://github.com/llvm/llvm-project/pull/164286

From b013c91606aa3620caecbd4b6f6fca9d4efbeb7e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn=20Sch=C3=A4pers?= <[email protected]>
Date: Mon, 20 Oct 2025 01:31:04 +0200
Subject: [PATCH] [clang-format] Add xxxMaxDigitsRemove to
 IntegerLiteralSeparator

This basically adds a Leave option for a specific range of literals.
---
 clang/docs/ClangFormatStyleOptions.rst        | 47 +++++++++++-
 clang/docs/ReleaseNotes.rst                   |  3 +
 clang/include/clang/Format/Format.h           | 75 ++++++++++++++++---
 clang/lib/Format/Format.cpp                   | 21 ++++--
 .../Format/IntegerLiteralSeparatorFixer.cpp   | 42 ++++++++---
 clang/unittests/Format/ConfigParseTest.cpp    | 30 ++++++++
 .../Format/IntegerLiteralSeparatorTest.cpp    | 26 +++++--
 7 files changed, 208 insertions(+), 36 deletions(-)

diff --git a/clang/docs/ClangFormatStyleOptions.rst 
b/clang/docs/ClangFormatStyleOptions.rst
index 94d6f0d27619f..eb586752a99e5 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -4767,7 +4767,12 @@ the configuration (without a prefix: ``Auto``).
 
   You can also specify a minimum number of digits (``BinaryMinDigits``,
   ``DecimalMinDigits``, and ``HexMinDigits``) the integer literal must
-  have in order for the separators to be inserted.
+  have in order for the separators to be inserted, and a maximum number of
+  digits (``BinaryMaxDigitsNoSeparator``, ``DecimalMaxDigitsNoSeparator``,
+  and ``HexMaxDigitsNoSeparator``) until the separators are removed. This
+  divides the literals in 3 regions, always without separator (up until
+  including ``xxxMaxDigitsNoSeparator``), maybe with, or without separators
+  (up until excluding ``xxxMinDigits``), and finally always with separators.
 
   * ``int8_t Binary`` Format separators in binary literals.
 
@@ -4787,6 +4792,19 @@ the configuration (without a prefix: ``Auto``).
       b1 = 0b101101;
       b2 = 0b1'101'101;
 
+  * ``int8_t BinaryMaxDigitsNoSeparator`` Remove separators in binary literals 
with a maximum number of digits.
+
+    .. code-block:: text
+
+      // Binary: 3
+      // BinaryMinDigits: 7
+      // BinaryMaxDigitsNoSeparator: 4
+      b0 = 0b1011; // Always removed.
+      b1 = 0b101101; // Not added.
+      b2 = 0b101'101; // Not removed.
+      b3 = 0b1'101'101; // Always added.
+      b4 = 0b10'1101; // Corrected to 0b101'101.
+
   * ``int8_t Decimal`` Format separators in decimal literals.
 
     .. code-block:: text
@@ -4804,6 +4822,19 @@ the configuration (without a prefix: ``Auto``).
       d1 = 2023;
       d2 = 10'000;
 
+  * ``int8_t DecimalMaxDigitsNoSeparator`` Remove separators in decimal 
literals with a maximum number of digits.
+
+    .. code-block:: text
+
+      // Decimal: 3
+      // DecimalMinDigits: 7
+      // DecimalMaxDigitsNoSeparator: 4
+      d0 = 2023; // Always removed.
+      d1 = 123456; // Not added.
+      d2 = 123'456; // Not removed.
+      d3 = 5'000'000; // Always added.
+      d4 = 1'23'45; // Corrected to 12'345.
+
   * ``int8_t Hex`` Format separators in hexadecimal literals.
 
     .. code-block:: text
@@ -4822,6 +4853,20 @@ the configuration (without a prefix: ``Auto``).
       h1 = 0xABCDE;
       h2 = 0xAB'CD'EF;
 
+  * ``int8_t HexMaxDigitsNoSeparator`` Remove separators in hexadecimal 
literals with a maximum number of
+    digits.
+
+    .. code-block:: text
+
+      // Hex: 2
+      // HexMinDigits: 6
+      // HexMaxDigitsNoSeparator: 4
+      h0 = 0xAFFE; // Always removed.
+      h1 = 0xABCDE; // Not added.
+      h2 = 0xA'BC'DE; // Not removed.
+      h3 = 0xAB'CD'EF; // Always added.
+      h4 = 0xABCD'E; // Corrected to 0xA'BC'DE.
+
 
 .. _JavaImportGroups:
 
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index f8a8fc3c0f450..17c633a9a481c 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -687,6 +687,9 @@ clang-format
   ``AlignAfterOpenBracket`` option, and make ``AlignAfterOpenBracket`` a
   ``bool`` type.
 - Add ``AlignPPAndNotPP`` suboption to ``AlignTrailingComments``.
+- Rename ``(Binary|Decimal|Hex)MinDigits`` to ``...MinDigitsInsert`` and  add
+  ``(Binary|Decimal|Hex)MaxDigitsSeparator`` suboptions to
+  ``IntegerLiteralSeparator``.
 
 libclang
 --------
diff --git a/clang/include/clang/Format/Format.h 
b/clang/include/clang/Format/Format.h
index b6f124f948b59..45584a0da90dc 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -3275,9 +3275,15 @@ struct FormatStyle {
   ///     Hex: -1
   /// \endcode
   ///
-  /// You can also specify a minimum number of digits (``BinaryMinDigits``,
-  /// ``DecimalMinDigits``, and ``HexMinDigits``) the integer literal must
-  /// have in order for the separators to be inserted.
+  /// You can also specify a minimum number of digits
+  /// (``BinaryMinDigitsInsert``, ``DecimalMinDigitsInsert``, and
+  /// ``HexMinDigitsInsert``) the integer literal must have in order for the
+  /// separators to be inserted, and a maximum number of digits
+  /// (``BinaryMaxDigitsRemove``, ``DecimalMaxDigitsRemove``, and
+  /// ``HexMaxDigitsRemove``) until the separators are removed. This divides 
the
+  /// literals in 3 regions, always without separator (up until including
+  /// ``xxxMaxDigitsRemove``), maybe with, or without separators (up until
+  /// excluding ``xxxMinDigitsInsert``), and finally always with separators.
   struct IntegerLiteralSeparatorStyle {
     /// Format separators in binary literals.
     /// \code{.text}
@@ -3290,11 +3296,23 @@ struct FormatStyle {
     /// Format separators in binary literals with a minimum number of digits.
     /// \code{.text}
     ///   // Binary: 3
-    ///   // BinaryMinDigits: 7
+    ///   // BinaryMinDigitsInsert: 7
     ///   b1 = 0b101101;
     ///   b2 = 0b1'101'101;
     /// \endcode
-    int8_t BinaryMinDigits;
+    int8_t BinaryMinDigitsInsert;
+    /// Remove separators in binary literals with a maximum number of digits.
+    /// \code{.text}
+    ///   // Binary: 3
+    ///   // BinaryMinDigitsInsert: 7
+    ///   // BinaryMaxDigitsRemove: 4
+    ///   b0 = 0b1011; // Always removed.
+    ///   b1 = 0b101101; // Not added.
+    ///   b2 = 0b1'01'101; // Not removed, not corrected.
+    ///   b3 = 0b1'101'101; // Always added.
+    ///   b4 = 0b10'1101; // Corrected to 0b101'101.
+    /// \endcode
+    int8_t BinaryMaxDigitsRemove;
     /// Format separators in decimal literals.
     /// \code{.text}
     ///   /* -1: */ d = 18446744073709550592ull;
@@ -3305,11 +3323,23 @@ struct FormatStyle {
     /// Format separators in decimal literals with a minimum number of digits.
     /// \code{.text}
     ///   // Decimal: 3
-    ///   // DecimalMinDigits: 5
+    ///   // DecimalMinDigitsInsert: 5
     ///   d1 = 2023;
     ///   d2 = 10'000;
     /// \endcode
-    int8_t DecimalMinDigits;
+    int8_t DecimalMinDigitsInsert;
+    /// Remove separators in decimal literals with a maximum number of digits.
+    /// \code{.text}
+    ///   // Decimal: 3
+    ///   // DecimalMinDigitsInsert: 7
+    ///   // DecimalMaxDigitsRemove: 4
+    ///   d0 = 2023; // Always removed.
+    ///   d1 = 123456; // Not added.
+    ///   d2 = 1'23'456; // Not removed, not corrected.
+    ///   d3 = 5'000'000; // Always added.
+    ///   d4 = 1'23'45; // Corrected to 12'345.
+    /// \endcode
+    int8_t DecimalMaxDigitsRemove;
     /// Format separators in hexadecimal literals.
     /// \code{.text}
     ///   /* -1: */ h = 0xDEADBEEFDEADBEEFuz;
@@ -3321,15 +3351,36 @@ struct FormatStyle {
     /// digits.
     /// \code{.text}
     ///   // Hex: 2
-    ///   // HexMinDigits: 6
+    ///   // HexMinDigitsInsert: 6
     ///   h1 = 0xABCDE;
     ///   h2 = 0xAB'CD'EF;
     /// \endcode
-    int8_t HexMinDigits;
+    int8_t HexMinDigitsInsert;
+    /// Remove separators in hexadecimal literals with a maximum number of
+    /// digits.
+    /// \code{.text}
+    ///   // Hex: 2
+    ///   // HexMinDigitsInsert: 6
+    ///   // HexMaxDigitsRemove: 4
+    ///   h0 = 0xAFFE; // Always removed.
+    ///   h1 = 0xABCDE; // Not added.
+    ///   h2 = 0xABC'DE; // Not removed, not corrected.
+    ///   h3 = 0xAB'CD'EF; // Always added.
+    ///   h4 = 0xABCD'E; // Corrected to 0xA'BC'DE.
+    /// \endcode
+    int8_t HexMaxDigitsRemove;
     bool operator==(const IntegerLiteralSeparatorStyle &R) const {
-      return Binary == R.Binary && BinaryMinDigits == R.BinaryMinDigits &&
-             Decimal == R.Decimal && DecimalMinDigits == R.DecimalMinDigits &&
-             Hex == R.Hex && HexMinDigits == R.HexMinDigits;
+      return Binary == R.Binary &&
+             BinaryMinDigitsInsert == R.BinaryMinDigitsInsert &&
+             BinaryMaxDigitsRemove == R.BinaryMaxDigitsRemove &&
+             Decimal == R.Decimal &&
+             DecimalMinDigitsInsert == R.DecimalMinDigitsInsert &&
+             DecimalMaxDigitsRemove == R.DecimalMaxDigitsRemove &&
+             Hex == R.Hex && HexMinDigitsInsert == R.HexMinDigitsInsert &&
+             HexMaxDigitsRemove == R.HexMaxDigitsRemove;
+    }
+    bool operator!=(const IntegerLiteralSeparatorStyle &R) const {
+      return !operator==(R);
     }
   };
 
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 9bbb33cb14502..f0e9aff2fd21a 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -405,11 +405,19 @@ struct 
ScalarEnumerationTraits<FormatStyle::IndentExternBlockStyle> {
 template <> struct MappingTraits<FormatStyle::IntegerLiteralSeparatorStyle> {
   static void mapping(IO &IO, FormatStyle::IntegerLiteralSeparatorStyle &Base) 
{
     IO.mapOptional("Binary", Base.Binary);
-    IO.mapOptional("BinaryMinDigits", Base.BinaryMinDigits);
+    IO.mapOptional("BinaryMinDigitsInsert", Base.BinaryMinDigitsInsert);
+    IO.mapOptional("BinaryMaxDigitsRemove", Base.BinaryMaxDigitsRemove);
     IO.mapOptional("Decimal", Base.Decimal);
-    IO.mapOptional("DecimalMinDigits", Base.DecimalMinDigits);
+    IO.mapOptional("DecimalMinDigitsInsert", Base.DecimalMinDigitsInsert);
+    IO.mapOptional("DecimalMaxDigitsRemove", Base.DecimalMaxDigitsRemove);
     IO.mapOptional("Hex", Base.Hex);
-    IO.mapOptional("HexMinDigits", Base.HexMinDigits);
+    IO.mapOptional("HexMinDigitsInsert", Base.HexMinDigitsInsert);
+    IO.mapOptional("HexMaxDigitsRemove", Base.HexMaxDigitsRemove);
+
+    // For backward compatibility.
+    IO.mapOptional("BinaryMinDigits", Base.BinaryMinDigitsInsert);
+    IO.mapOptional("DecimalMinDigits", Base.DecimalMinDigitsInsert);
+    IO.mapOptional("HexMinDigits", Base.HexMinDigitsInsert);
   }
 };
 
@@ -1758,10 +1766,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind 
Language) {
   LLVMStyle.InsertBraces = false;
   LLVMStyle.InsertNewlineAtEOF = false;
   LLVMStyle.InsertTrailingCommas = FormatStyle::TCS_None;
-  LLVMStyle.IntegerLiteralSeparator = {
-      /*Binary=*/0,  /*BinaryMinDigits=*/0,
-      /*Decimal=*/0, /*DecimalMinDigits=*/0,
-      /*Hex=*/0,     /*HexMinDigits=*/0};
+  LLVMStyle.IntegerLiteralSeparator = {};
   LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave;
   LLVMStyle.JavaScriptWrapImports = true;
   LLVMStyle.KeepEmptyLines = {
@@ -2183,7 +2188,7 @@ FormatStyle getClangFormatStyle() {
   Style.InsertBraces = true;
   Style.InsertNewlineAtEOF = true;
   Style.IntegerLiteralSeparator.Decimal = 3;
-  Style.IntegerLiteralSeparator.DecimalMinDigits = 5;
+  Style.IntegerLiteralSeparator.DecimalMinDigitsInsert = 5;
   Style.LineEnding = FormatStyle::LE_LF;
   Style.RemoveBracesLLVM = true;
   Style.RemoveEmptyLinesInUnwrappedLines = true;
diff --git a/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp 
b/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp
index b51991bfeff4b..0cc22853ea5db 100644
--- a/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp
+++ b/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp
@@ -72,11 +72,25 @@ IntegerLiteralSeparatorFixer::process(const Environment 
&Env,
   if (SkipBinary && SkipDecimal && SkipHex)
     return {};
 
-  const auto BinaryMinDigits =
-      std::max((int)Option.BinaryMinDigits, Binary + 1);
-  const auto DecimalMinDigits =
-      std::max((int)Option.DecimalMinDigits, Decimal + 1);
-  const auto HexMinDigits = std::max((int)Option.HexMinDigits, Hex + 1);
+  auto CalcMinAndMax = [](int Digits, int MinDigitsInsert,
+                          int MaxDigitsRemove) {
+    std::pair<int, int> Ret;
+    Ret.first = std::max(MinDigitsInsert, Digits + 1);
+    if (Ret.first == 0)
+      Ret.second = 0;
+    else if (MaxDigitsRemove <= 0)
+      Ret.second = Ret.first - 1;
+    else
+      Ret.second = std::min(MaxDigitsRemove, Ret.first - 1);
+    return Ret;
+  };
+
+  const auto [BinaryMinDigitsInsert, BinaryMaxDigitsRemove] = CalcMinAndMax(
+      Binary, Option.BinaryMinDigitsInsert, Option.BinaryMaxDigitsRemove);
+  const auto [DecimalMinDigitsInsert, DecimalMaxDigitsRemove] = CalcMinAndMax(
+      Decimal, Option.DecimalMinDigitsInsert, Option.DecimalMaxDigitsRemove);
+  const auto [HexMinDigitsInsert, HexMaxDigitsRemove] =
+      CalcMinAndMax(Hex, Option.HexMinDigitsInsert, Option.HexMaxDigitsRemove);
 
   const auto &SourceMgr = Env.getSourceManager();
   AffectedRangeManager AffectedRangeMgr(SourceMgr, Env.getCharRanges());
@@ -138,20 +152,28 @@ IntegerLiteralSeparatorFixer::process(const Environment 
&Env,
       Text = Text.substr(Start, Length);
     }
     auto DigitsPerGroup = Decimal;
-    auto MinDigits = DecimalMinDigits;
+    auto MinDigitsInsert = DecimalMinDigitsInsert;
+    auto MaxDigitsRemove = DecimalMaxDigitsRemove;
     if (IsBase2) {
       DigitsPerGroup = Binary;
-      MinDigits = BinaryMinDigits;
+      MinDigitsInsert = BinaryMinDigitsInsert;
+      MaxDigitsRemove = BinaryMaxDigitsRemove;
     } else if (IsBase16) {
       DigitsPerGroup = Hex;
-      MinDigits = HexMinDigits;
+      MinDigitsInsert = HexMinDigitsInsert;
+      MaxDigitsRemove = HexMaxDigitsRemove;
     }
     const auto SeparatorCount = Text.count(Separator);
     const int DigitCount = Length - SeparatorCount;
-    const bool RemoveSeparator = DigitsPerGroup < 0 || DigitCount < MinDigits;
+    const bool RemoveSeparator =
+        DigitsPerGroup < 0 || DigitCount <= MaxDigitsRemove;
+    const bool AddSeparator =
+        DigitsPerGroup > 0 && DigitCount >= MinDigitsInsert;
+    if (!RemoveSeparator && !AddSeparator)
+      continue;
     if (RemoveSeparator && SeparatorCount == 0)
       continue;
-    if (!RemoveSeparator && SeparatorCount > 0 &&
+    if (AddSeparator && SeparatorCount > 0 &&
         checkSeparator(Text, DigitsPerGroup)) {
       continue;
     }
diff --git a/clang/unittests/Format/ConfigParseTest.cpp 
b/clang/unittests/Format/ConfigParseTest.cpp
index d578fa7a1a1e8..fec1c48c448d2 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -1164,6 +1164,36 @@ TEST(ConfigParseTest, ParsesConfiguration) {
               FormatStyle::BLS_Block);
   CHECK_PARSE("Cpp11BracedListStyle: true", Cpp11BracedListStyle,
               FormatStyle::BLS_AlignFirstComment);
+
+  constexpr FormatStyle::IntegerLiteralSeparatorStyle
+      ExpectedIntegerLiteralSeparatorStyle{/*Binary=*/2,
+                                           /*BinaryMinDigitInsert=*/5,
+                                           /*BinaryMaxDigitRemove=*/2,
+                                           /*Decimal=*/6,
+                                           /*DecimalMinDigitInsert=*/6,
+                                           /*DecimalMaxDigitRemove=*/3,
+                                           /*Hex=*/4,
+                                           /*HexMinDigitInsert=*/2,
+                                           /*HexMaxDigitRemove=*/1};
+  CHECK_PARSE("IntegerLiteralSeparator:\n"
+              "  Binary: 2\n"
+              "  BinaryMinDigitsInsert: 5\n"
+              "  BinaryMaxDigitsRemove: 2\n"
+              "  Decimal: 6\n"
+              "  DecimalMinDigitsInsert: 6\n"
+              "  DecimalMaxDigitsRemove: 3\n"
+              "  Hex: 4\n"
+              "  HexMinDigitsInsert: 2\n"
+              "  HexMaxDigitsRemove: 1",
+              IntegerLiteralSeparator, ExpectedIntegerLiteralSeparatorStyle);
+
+  // Backward compatibility:
+  CHECK_PARSE_NESTED_VALUE("BinaryMinDigits: 6", IntegerLiteralSeparator,
+                           BinaryMinDigitsInsert, 6);
+  CHECK_PARSE_NESTED_VALUE("DecimalMinDigits: 5", IntegerLiteralSeparator,
+                           DecimalMinDigitsInsert, 5);
+  CHECK_PARSE_NESTED_VALUE("HexMinDigits: 5", IntegerLiteralSeparator,
+                           HexMinDigitsInsert, 5);
 }
 
 TEST(ConfigParseTest, ParsesConfigurationWithLanguages) {
diff --git a/clang/unittests/Format/IntegerLiteralSeparatorTest.cpp 
b/clang/unittests/Format/IntegerLiteralSeparatorTest.cpp
index 53b6dd8efadff..fdcdda909b8da 100644
--- a/clang/unittests/Format/IntegerLiteralSeparatorTest.cpp
+++ b/clang/unittests/Format/IntegerLiteralSeparatorTest.cpp
@@ -137,34 +137,34 @@ TEST_F(IntegerLiteralSeparatorTest, 
UnderscoreAsSeparator) {
   verifyFormat("o = 0o400000000000000003n;", Style);
 }
 
-TEST_F(IntegerLiteralSeparatorTest, MinDigits) {
+TEST_F(IntegerLiteralSeparatorTest, MinDigitsInsert) {
   FormatStyle Style = getLLVMStyle();
   Style.IntegerLiteralSeparator.Binary = 3;
   Style.IntegerLiteralSeparator.Decimal = 3;
   Style.IntegerLiteralSeparator.Hex = 2;
 
-  Style.IntegerLiteralSeparator.BinaryMinDigits = 7;
+  Style.IntegerLiteralSeparator.BinaryMinDigitsInsert = 7;
   verifyFormat("b1 = 0b101101;\n"
                "b2 = 0b1'101'101;",
                "b1 = 0b101'101;\n"
                "b2 = 0b1101101;",
                Style);
 
-  Style.IntegerLiteralSeparator.DecimalMinDigits = 5;
+  Style.IntegerLiteralSeparator.DecimalMinDigitsInsert = 5;
   verifyFormat("d1 = 2023;\n"
                "d2 = 10'000;",
                "d1 = 2'023;\n"
                "d2 = 100'00;",
                Style);
 
-  Style.IntegerLiteralSeparator.DecimalMinDigits = 3;
+  Style.IntegerLiteralSeparator.DecimalMinDigitsInsert = 3;
   verifyFormat("d1 = 123;\n"
                "d2 = 1'234;",
                "d1 = 12'3;\n"
                "d2 = 12'34;",
                Style);
 
-  Style.IntegerLiteralSeparator.HexMinDigits = 6;
+  Style.IntegerLiteralSeparator.HexMinDigitsInsert = 6;
   verifyFormat("h1 = 0xABCDE;\n"
                "h2 = 0xAB'CD'EF;",
                "h1 = 0xA'BC'DE;\n"
@@ -243,6 +243,22 @@ TEST_F(IntegerLiteralSeparatorTest, FloatingPoint) {
                Style);
 }
 
+TEST_F(IntegerLiteralSeparatorTest, MaxDigitsRemove) {
+  auto Style = getLLVMStyle();
+  Style.IntegerLiteralSeparator.Decimal = 3;
+  Style.IntegerLiteralSeparator.DecimalMaxDigitsRemove = 4;
+  Style.IntegerLiteralSeparator.DecimalMinDigitsInsert = 7;
+  verifyFormat("d0 = 2023;\n"
+               "d1 = 123456;\n"
+               "d2 = 1234'56;\n"
+               "d3 = 5'000'000;",
+               "d0 = 20'2'3;\n"
+               "d1 = 123456;\n"
+               "d2 = 1234'56;\n"
+               "d3 = 5000000;",
+               Style);
+}
+
 } // namespace
 } // namespace test
 } // namespace format

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to