[clang] 253985d - [clang-format] Add MinDigits suboptions to IntegerLiteralSeparator

Owen Pan via cfe-commits cfe-commits at lists.llvm.org
Fri Mar 31 17:15:22 PDT 2023


Author: Owen Pan
Date: 2023-03-31T17:14:33-07:00
New Revision: 253985d58caf95db8a84632d5a761b96fb7cd7d6

URL: https://github.com/llvm/llvm-project/commit/253985d58caf95db8a84632d5a761b96fb7cd7d6
DIFF: https://github.com/llvm/llvm-project/commit/253985d58caf95db8a84632d5a761b96fb7cd7d6.diff

LOG: [clang-format] Add MinDigits suboptions to IntegerLiteralSeparator

Closes #61209.

Differential Revision: https://reviews.llvm.org/D147111

Added: 
    

Modified: 
    clang/docs/ClangFormatStyleOptions.rst
    clang/include/clang/Format/Format.h
    clang/lib/Format/Format.cpp
    clang/lib/Format/IntegerLiteralSeparatorFixer.cpp
    clang/lib/Format/IntegerLiteralSeparatorFixer.h
    clang/unittests/Format/IntegerLiteralSeparatorTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index d706a0494f0f5..4078019f82bad 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -3375,6 +3375,10 @@ the configuration (without a prefix: ``Auto``).
       Decimal: 3
       Hex: -1
 
+  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.
+
   * ``int8_t Binary`` Format separators in binary literals.
 
     .. code-block:: text
@@ -3384,6 +3388,15 @@ the configuration (without a prefix: ``Auto``).
       /*  3: */ b = 0b100'111'101'101;
       /*  4: */ b = 0b1001'1110'1101;
 
+  * ``int8_t BinaryMinDigits`` Format separators in binary literals with a minimum number of digits.
+
+    .. code-block:: text
+
+      // Binary: 3
+      // BinaryMinDigits: 7
+      b1 = 0b101101;
+      b2 = 0b1'101'101;
+
   * ``int8_t Decimal`` Format separators in decimal literals.
 
     .. code-block:: text
@@ -3392,6 +3405,15 @@ the configuration (without a prefix: ``Auto``).
       /*  0: */ d = 184467'440737'0'95505'92ull;
       /*  3: */ d = 18'446'744'073'709'550'592ull;
 
+  * ``int8_t DecimalMinDigits`` Format separators in decimal literals with a minimum number of digits.
+
+    .. code-block:: text
+
+      // Decimal: 3
+      // DecimalMinDigits: 5
+      d1 = 2023;
+      d2 = 10'000;
+
   * ``int8_t Hex`` Format separators in hexadecimal literals.
 
     .. code-block:: text
@@ -3400,6 +3422,16 @@ the configuration (without a prefix: ``Auto``).
       /*  0: */ h = 0xDEAD'BEEF'DE'AD'BEE'Fuz;
       /*  2: */ h = 0xDE'AD'BE'EF'DE'AD'BE'EFuz;
 
+  * ``int8_t HexMinDigits`` Format separators in hexadecimal literals with a minimum number of
+    digits.
+
+    .. code-block:: text
+
+      // Hex: 2
+      // HexMinDigits: 6
+      h1 = 0xABCDE;
+      h2 = 0xAB'CD'EF;
+
 
 .. _JavaImportGroups:
 

diff  --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index cc2b34a20e895..85daa50b5bac8 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -2500,6 +2500,10 @@ struct FormatStyle {
   ///     Decimal: 3
   ///     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.
   struct IntegerLiteralSeparatorStyle {
     /// Format separators in binary literals.
     /// \code{.text}
@@ -2509,6 +2513,14 @@ struct FormatStyle {
     ///   /*  4: */ b = 0b1001'1110'1101;
     /// \endcode
     int8_t Binary;
+    /// Format separators in binary literals with a minimum number of digits.
+    /// \code{.text}
+    ///   // Binary: 3
+    ///   // BinaryMinDigits: 7
+    ///   b1 = 0b101101;
+    ///   b2 = 0b1'101'101;
+    /// \endcode
+    int8_t BinaryMinDigits;
     /// Format separators in decimal literals.
     /// \code{.text}
     ///   /* -1: */ d = 18446744073709550592ull;
@@ -2516,6 +2528,14 @@ struct FormatStyle {
     ///   /*  3: */ d = 18'446'744'073'709'550'592ull;
     /// \endcode
     int8_t Decimal;
+    /// Format separators in decimal literals with a minimum number of digits.
+    /// \code{.text}
+    ///   // Decimal: 3
+    ///   // DecimalMinDigits: 5
+    ///   d1 = 2023;
+    ///   d2 = 10'000;
+    /// \endcode
+    int8_t DecimalMinDigits;
     /// Format separators in hexadecimal literals.
     /// \code{.text}
     ///   /* -1: */ h = 0xDEADBEEFDEADBEEFuz;
@@ -2523,6 +2543,20 @@ struct FormatStyle {
     ///   /*  2: */ h = 0xDE'AD'BE'EF'DE'AD'BE'EFuz;
     /// \endcode
     int8_t Hex;
+    /// Format separators in hexadecimal literals with a minimum number of
+    /// digits.
+    /// \code{.text}
+    ///   // Hex: 2
+    ///   // HexMinDigits: 6
+    ///   h1 = 0xABCDE;
+    ///   h2 = 0xAB'CD'EF;
+    /// \endcode
+    int8_t HexMinDigits;
+    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;
+    }
   };
 
   /// Format integer literal separators (``'`` for C++ and ``_`` for C#, Java,
@@ -4277,10 +4311,7 @@ struct FormatStyle {
            IndentWrappedFunctionNames == R.IndentWrappedFunctionNames &&
            InsertBraces == R.InsertBraces &&
            InsertNewlineAtEOF == R.InsertNewlineAtEOF &&
-           IntegerLiteralSeparator.Binary == R.IntegerLiteralSeparator.Binary &&
-           IntegerLiteralSeparator.Decimal ==
-               R.IntegerLiteralSeparator.Decimal &&
-           IntegerLiteralSeparator.Hex == R.IntegerLiteralSeparator.Hex &&
+           IntegerLiteralSeparator == R.IntegerLiteralSeparator &&
            JavaImportGroups == R.JavaImportGroups &&
            JavaScriptQuotes == R.JavaScriptQuotes &&
            JavaScriptWrapImports == R.JavaScriptWrapImports &&

diff  --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 67772467abad4..618cdb68f7c49 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -348,8 +348,11 @@ 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("Decimal", Base.Decimal);
+    IO.mapOptional("DecimalMinDigits", Base.DecimalMinDigits);
     IO.mapOptional("Hex", Base.Hex);
+    IO.mapOptional("HexMinDigits", Base.HexMinDigits);
   }
 };
 
@@ -1395,7 +1398,10 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
   LLVMStyle.InsertBraces = false;
   LLVMStyle.InsertNewlineAtEOF = false;
   LLVMStyle.InsertTrailingCommas = FormatStyle::TCS_None;
-  LLVMStyle.IntegerLiteralSeparator = {/*Binary=*/0, /*Decimal=*/0, /*Hex=*/0};
+  LLVMStyle.IntegerLiteralSeparator = {
+      /*Binary=*/0,  /*BinaryMinDigits=*/0,
+      /*Decimal=*/0, /*DecimalMinDigits=*/0,
+      /*Hex=*/0,     /*HexMinDigits=*/0};
   LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave;
   LLVMStyle.JavaScriptWrapImports = true;
   LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true;

diff  --git a/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp b/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp
index 35a8db0ce76e1..583cc3d682a79 100644
--- a/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp
+++ b/clang/lib/Format/IntegerLiteralSeparatorFixer.cpp
@@ -69,6 +69,12 @@ 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);
+
   const auto &SourceMgr = Env.getSourceManager();
   AffectedRangeManager AffectedRangeMgr(SourceMgr, Env.getCharRanges());
 
@@ -116,11 +122,6 @@ IntegerLiteralSeparatorFixer::process(const Environment &Env,
         (IsBase16 && Text.find_last_of(".pP") != StringRef::npos)) {
       continue;
     }
-    if (((IsBase2 && Binary < 0) || (IsBase10 && Decimal < 0) ||
-         (IsBase16 && Hex < 0)) &&
-        Text.find(Separator) == StringRef::npos) {
-      continue;
-    }
     const auto Start = Text[0] == '0' ? 2 : 0;
     auto End = Text.find_first_of("uUlLzZn", Start);
     if (End == StringRef::npos)
@@ -130,13 +131,25 @@ IntegerLiteralSeparatorFixer::process(const Environment &Env,
       Text = Text.substr(Start, Length);
     }
     auto DigitsPerGroup = Decimal;
-    if (IsBase2)
+    auto MinDigits = DecimalMinDigits;
+    if (IsBase2) {
       DigitsPerGroup = Binary;
-    else if (IsBase16)
+      MinDigits = BinaryMinDigits;
+    } else if (IsBase16) {
       DigitsPerGroup = Hex;
-    if (DigitsPerGroup > 0 && checkSeparator(Text, DigitsPerGroup))
+      MinDigits = HexMinDigits;
+    }
+    const auto SeparatorCount = Text.count(Separator);
+    const int DigitCount = Length - SeparatorCount;
+    const bool RemoveSeparator = DigitsPerGroup < 0 || DigitCount < MinDigits;
+    if (RemoveSeparator && SeparatorCount == 0)
       continue;
-    const auto &Formatted = format(Text, DigitsPerGroup);
+    if (!RemoveSeparator && SeparatorCount > 0 &&
+        checkSeparator(Text, DigitsPerGroup)) {
+      continue;
+    }
+    const auto &Formatted =
+        format(Text, DigitsPerGroup, DigitCount, RemoveSeparator);
     assert(Formatted != Text);
     if (Start > 0)
       Location = Location.getLocWithOffset(Start);
@@ -168,23 +181,20 @@ bool IntegerLiteralSeparatorFixer::checkSeparator(
 }
 
 std::string IntegerLiteralSeparatorFixer::format(const StringRef IntegerLiteral,
-                                                 int DigitsPerGroup) const {
+                                                 int DigitsPerGroup,
+                                                 int DigitCount,
+                                                 bool RemoveSeparator) const {
   assert(DigitsPerGroup != 0);
 
   std::string Formatted;
 
-  if (DigitsPerGroup < 0) {
+  if (RemoveSeparator) {
     for (auto C : IntegerLiteral)
       if (C != Separator)
         Formatted.push_back(C);
     return Formatted;
   }
 
-  int DigitCount = 0;
-  for (auto C : IntegerLiteral)
-    if (C != Separator)
-      ++DigitCount;
-
   int Remainder = DigitCount % DigitsPerGroup;
 
   int I = 0;

diff  --git a/clang/lib/Format/IntegerLiteralSeparatorFixer.h b/clang/lib/Format/IntegerLiteralSeparatorFixer.h
index 156bf5c14fca1..2c158e4473bfe 100644
--- a/clang/lib/Format/IntegerLiteralSeparatorFixer.h
+++ b/clang/lib/Format/IntegerLiteralSeparatorFixer.h
@@ -27,7 +27,8 @@ class IntegerLiteralSeparatorFixer {
 
 private:
   bool checkSeparator(const StringRef IntegerLiteral, int DigitsPerGroup) const;
-  std::string format(const StringRef IntegerLiteral, int DigitsPerGroup) const;
+  std::string format(const StringRef IntegerLiteral, int DigitsPerGroup,
+                     int DigitCount, bool RemoveSeparator) const;
 
   char Separator;
 };

diff  --git a/clang/unittests/Format/IntegerLiteralSeparatorTest.cpp b/clang/unittests/Format/IntegerLiteralSeparatorTest.cpp
index eb0ca7e21ee5a..27fc6d76f3c49 100644
--- a/clang/unittests/Format/IntegerLiteralSeparatorTest.cpp
+++ b/clang/unittests/Format/IntegerLiteralSeparatorTest.cpp
@@ -116,6 +116,41 @@ TEST_F(IntegerLiteralSeparatorTest, UnderscoreAsSeparator) {
   verifyFormat("o = 0o400000000000000003n;", Style);
 }
 
+TEST_F(IntegerLiteralSeparatorTest, MinDigits) {
+  FormatStyle Style = getLLVMStyle();
+  Style.IntegerLiteralSeparator.Binary = 3;
+  Style.IntegerLiteralSeparator.Decimal = 3;
+  Style.IntegerLiteralSeparator.Hex = 2;
+
+  Style.IntegerLiteralSeparator.BinaryMinDigits = 7;
+  verifyFormat("b1 = 0b101101;\n"
+               "b2 = 0b1'101'101;",
+               "b1 = 0b101'101;\n"
+               "b2 = 0b1101101;",
+               Style);
+
+  Style.IntegerLiteralSeparator.DecimalMinDigits = 5;
+  verifyFormat("d1 = 2023;\n"
+               "d2 = 10'000;",
+               "d1 = 2'023;\n"
+               "d2 = 100'00;",
+               Style);
+
+  Style.IntegerLiteralSeparator.DecimalMinDigits = 3;
+  verifyFormat("d1 = 123;\n"
+               "d2 = 1'234;",
+               "d1 = 12'3;\n"
+               "d2 = 12'34;",
+               Style);
+
+  Style.IntegerLiteralSeparator.HexMinDigits = 6;
+  verifyFormat("h1 = 0xABCDE;\n"
+               "h2 = 0xAB'CD'EF;",
+               "h1 = 0xA'BC'DE;\n"
+               "h2 = 0xABC'DEF;",
+               Style);
+}
+
 TEST_F(IntegerLiteralSeparatorTest, FixRanges) {
   FormatStyle Style = getLLVMStyle();
   Style.IntegerLiteralSeparator.Decimal = 3;


        


More information about the cfe-commits mailing list