Skip to content

Commit 356cb7e

Browse files
owencatstellar
authored andcommitted
[clang-format] Add MinDigits suboptions to IntegerLiteralSeparator
Closes #61209. Differential Revision: https://reviews.llvm.org/D147111 (cherry picked from commit 253985d)
1 parent 6bf6630 commit 356cb7e

File tree

6 files changed

+137
-22
lines changed

6 files changed

+137
-22
lines changed

clang/docs/ClangFormatStyleOptions.rst

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3373,6 +3373,10 @@ the configuration (without a prefix: ``Auto``).
33733373
Decimal: 3
33743374
Hex: -1
33753375

3376+
You can also specify a minimum number of digits (``BinaryMinDigits``,
3377+
``DecimalMinDigits``, and ``HexMinDigits``) the integer literal must
3378+
have in order for the separators to be inserted.
3379+
33763380
* ``int8_t Binary`` Format separators in binary literals.
33773381

33783382
.. code-block:: text
@@ -3382,6 +3386,15 @@ the configuration (without a prefix: ``Auto``).
33823386
/* 3: */ b = 0b100'111'101'101;
33833387
/* 4: */ b = 0b1001'1110'1101;
33843388
3389+
* ``int8_t BinaryMinDigits`` Format separators in binary literals with a minimum number of digits.
3390+
3391+
.. code-block:: text
3392+
3393+
// Binary: 3
3394+
// BinaryMinDigits: 7
3395+
b1 = 0b101101;
3396+
b2 = 0b1'101'101;
3397+
33853398
* ``int8_t Decimal`` Format separators in decimal literals.
33863399

33873400
.. code-block:: text
@@ -3390,6 +3403,15 @@ the configuration (without a prefix: ``Auto``).
33903403
/* 0: */ d = 184467'440737'0'95505'92ull;
33913404
/* 3: */ d = 18'446'744'073'709'550'592ull;
33923405
3406+
* ``int8_t DecimalMinDigits`` Format separators in decimal literals with a minimum number of digits.
3407+
3408+
.. code-block:: text
3409+
3410+
// Decimal: 3
3411+
// DecimalMinDigits: 5
3412+
d1 = 2023;
3413+
d2 = 10'000;
3414+
33933415
* ``int8_t Hex`` Format separators in hexadecimal literals.
33943416

33953417
.. code-block:: text
@@ -3398,6 +3420,16 @@ the configuration (without a prefix: ``Auto``).
33983420
/* 0: */ h = 0xDEAD'BEEF'DE'AD'BEE'Fuz;
33993421
/* 2: */ h = 0xDE'AD'BE'EF'DE'AD'BE'EFuz;
34003422
3423+
* ``int8_t HexMinDigits`` Format separators in hexadecimal literals with a minimum number of
3424+
digits.
3425+
3426+
.. code-block:: text
3427+
3428+
// Hex: 2
3429+
// HexMinDigits: 6
3430+
h1 = 0xABCDE;
3431+
h2 = 0xAB'CD'EF;
3432+
34013433
34023434
.. _JavaImportGroups:
34033435

clang/include/clang/Format/Format.h

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2500,6 +2500,10 @@ struct FormatStyle {
25002500
/// Decimal: 3
25012501
/// Hex: -1
25022502
/// \endcode
2503+
///
2504+
/// You can also specify a minimum number of digits (``BinaryMinDigits``,
2505+
/// ``DecimalMinDigits``, and ``HexMinDigits``) the integer literal must
2506+
/// have in order for the separators to be inserted.
25032507
struct IntegerLiteralSeparatorStyle {
25042508
/// Format separators in binary literals.
25052509
/// \code{.text}
@@ -2509,20 +2513,50 @@ struct FormatStyle {
25092513
/// /* 4: */ b = 0b1001'1110'1101;
25102514
/// \endcode
25112515
int8_t Binary;
2516+
/// Format separators in binary literals with a minimum number of digits.
2517+
/// \code{.text}
2518+
/// // Binary: 3
2519+
/// // BinaryMinDigits: 7
2520+
/// b1 = 0b101101;
2521+
/// b2 = 0b1'101'101;
2522+
/// \endcode
2523+
int8_t BinaryMinDigits;
25122524
/// Format separators in decimal literals.
25132525
/// \code{.text}
25142526
/// /* -1: */ d = 18446744073709550592ull;
25152527
/// /* 0: */ d = 184467'440737'0'95505'92ull;
25162528
/// /* 3: */ d = 18'446'744'073'709'550'592ull;
25172529
/// \endcode
25182530
int8_t Decimal;
2531+
/// Format separators in decimal literals with a minimum number of digits.
2532+
/// \code{.text}
2533+
/// // Decimal: 3
2534+
/// // DecimalMinDigits: 5
2535+
/// d1 = 2023;
2536+
/// d2 = 10'000;
2537+
/// \endcode
2538+
int8_t DecimalMinDigits;
25192539
/// Format separators in hexadecimal literals.
25202540
/// \code{.text}
25212541
/// /* -1: */ h = 0xDEADBEEFDEADBEEFuz;
25222542
/// /* 0: */ h = 0xDEAD'BEEF'DE'AD'BEE'Fuz;
25232543
/// /* 2: */ h = 0xDE'AD'BE'EF'DE'AD'BE'EFuz;
25242544
/// \endcode
25252545
int8_t Hex;
2546+
/// Format separators in hexadecimal literals with a minimum number of
2547+
/// digits.
2548+
/// \code{.text}
2549+
/// // Hex: 2
2550+
/// // HexMinDigits: 6
2551+
/// h1 = 0xABCDE;
2552+
/// h2 = 0xAB'CD'EF;
2553+
/// \endcode
2554+
int8_t HexMinDigits;
2555+
bool operator==(const IntegerLiteralSeparatorStyle &R) const {
2556+
return Binary == R.Binary && BinaryMinDigits == R.BinaryMinDigits &&
2557+
Decimal == R.Decimal && DecimalMinDigits == R.DecimalMinDigits &&
2558+
Hex == R.Hex && HexMinDigits == R.HexMinDigits;
2559+
}
25262560
};
25272561

25282562
/// Format integer literal separators (``'`` for C++ and ``_`` for C#, Java,
@@ -4212,10 +4246,7 @@ struct FormatStyle {
42124246
IndentWrappedFunctionNames == R.IndentWrappedFunctionNames &&
42134247
InsertBraces == R.InsertBraces &&
42144248
InsertNewlineAtEOF == R.InsertNewlineAtEOF &&
4215-
IntegerLiteralSeparator.Binary == R.IntegerLiteralSeparator.Binary &&
4216-
IntegerLiteralSeparator.Decimal ==
4217-
R.IntegerLiteralSeparator.Decimal &&
4218-
IntegerLiteralSeparator.Hex == R.IntegerLiteralSeparator.Hex &&
4249+
IntegerLiteralSeparator == R.IntegerLiteralSeparator &&
42194250
JavaImportGroups == R.JavaImportGroups &&
42204251
JavaScriptQuotes == R.JavaScriptQuotes &&
42214252
JavaScriptWrapImports == R.JavaScriptWrapImports &&

clang/lib/Format/Format.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,8 +348,11 @@ struct ScalarEnumerationTraits<FormatStyle::IndentExternBlockStyle> {
348348
template <> struct MappingTraits<FormatStyle::IntegerLiteralSeparatorStyle> {
349349
static void mapping(IO &IO, FormatStyle::IntegerLiteralSeparatorStyle &Base) {
350350
IO.mapOptional("Binary", Base.Binary);
351+
IO.mapOptional("BinaryMinDigits", Base.BinaryMinDigits);
351352
IO.mapOptional("Decimal", Base.Decimal);
353+
IO.mapOptional("DecimalMinDigits", Base.DecimalMinDigits);
352354
IO.mapOptional("Hex", Base.Hex);
355+
IO.mapOptional("HexMinDigits", Base.HexMinDigits);
353356
}
354357
};
355358

@@ -1392,7 +1395,10 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
13921395
LLVMStyle.InsertBraces = false;
13931396
LLVMStyle.InsertNewlineAtEOF = false;
13941397
LLVMStyle.InsertTrailingCommas = FormatStyle::TCS_None;
1395-
LLVMStyle.IntegerLiteralSeparator = {/*Binary=*/0, /*Decimal=*/0, /*Hex=*/0};
1398+
LLVMStyle.IntegerLiteralSeparator = {
1399+
/*Binary=*/0, /*BinaryMinDigits=*/0,
1400+
/*Decimal=*/0, /*DecimalMinDigits=*/0,
1401+
/*Hex=*/0, /*HexMinDigits=*/0};
13961402
LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave;
13971403
LLVMStyle.JavaScriptWrapImports = true;
13981404
LLVMStyle.KeepEmptyLinesAtTheStartOfBlocks = true;

clang/lib/Format/IntegerLiteralSeparatorFixer.cpp

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ IntegerLiteralSeparatorFixer::process(const Environment &Env,
6969
if (SkipBinary && SkipDecimal && SkipHex)
7070
return {};
7171

72+
const auto BinaryMinDigits =
73+
std::max((int)Option.BinaryMinDigits, Binary + 1);
74+
const auto DecimalMinDigits =
75+
std::max((int)Option.DecimalMinDigits, Decimal + 1);
76+
const auto HexMinDigits = std::max((int)Option.HexMinDigits, Hex + 1);
77+
7278
const auto &SourceMgr = Env.getSourceManager();
7379
AffectedRangeManager AffectedRangeMgr(SourceMgr, Env.getCharRanges());
7480

@@ -116,11 +122,6 @@ IntegerLiteralSeparatorFixer::process(const Environment &Env,
116122
(IsBase16 && Text.find_last_of(".pP") != StringRef::npos)) {
117123
continue;
118124
}
119-
if (((IsBase2 && Binary < 0) || (IsBase10 && Decimal < 0) ||
120-
(IsBase16 && Hex < 0)) &&
121-
Text.find(Separator) == StringRef::npos) {
122-
continue;
123-
}
124125
const auto Start = Text[0] == '0' ? 2 : 0;
125126
auto End = Text.find_first_of("uUlLzZn", Start);
126127
if (End == StringRef::npos)
@@ -130,13 +131,25 @@ IntegerLiteralSeparatorFixer::process(const Environment &Env,
130131
Text = Text.substr(Start, Length);
131132
}
132133
auto DigitsPerGroup = Decimal;
133-
if (IsBase2)
134+
auto MinDigits = DecimalMinDigits;
135+
if (IsBase2) {
134136
DigitsPerGroup = Binary;
135-
else if (IsBase16)
137+
MinDigits = BinaryMinDigits;
138+
} else if (IsBase16) {
136139
DigitsPerGroup = Hex;
137-
if (DigitsPerGroup > 0 && checkSeparator(Text, DigitsPerGroup))
140+
MinDigits = HexMinDigits;
141+
}
142+
const auto SeparatorCount = Text.count(Separator);
143+
const int DigitCount = Length - SeparatorCount;
144+
const bool RemoveSeparator = DigitsPerGroup < 0 || DigitCount < MinDigits;
145+
if (RemoveSeparator && SeparatorCount == 0)
138146
continue;
139-
const auto &Formatted = format(Text, DigitsPerGroup);
147+
if (!RemoveSeparator && SeparatorCount > 0 &&
148+
checkSeparator(Text, DigitsPerGroup)) {
149+
continue;
150+
}
151+
const auto &Formatted =
152+
format(Text, DigitsPerGroup, DigitCount, RemoveSeparator);
140153
assert(Formatted != Text);
141154
if (Start > 0)
142155
Location = Location.getLocWithOffset(Start);
@@ -168,23 +181,20 @@ bool IntegerLiteralSeparatorFixer::checkSeparator(
168181
}
169182

170183
std::string IntegerLiteralSeparatorFixer::format(const StringRef IntegerLiteral,
171-
int DigitsPerGroup) const {
184+
int DigitsPerGroup,
185+
int DigitCount,
186+
bool RemoveSeparator) const {
172187
assert(DigitsPerGroup != 0);
173188

174189
std::string Formatted;
175190

176-
if (DigitsPerGroup < 0) {
191+
if (RemoveSeparator) {
177192
for (auto C : IntegerLiteral)
178193
if (C != Separator)
179194
Formatted.push_back(C);
180195
return Formatted;
181196
}
182197

183-
int DigitCount = 0;
184-
for (auto C : IntegerLiteral)
185-
if (C != Separator)
186-
++DigitCount;
187-
188198
int Remainder = DigitCount % DigitsPerGroup;
189199

190200
int I = 0;

clang/lib/Format/IntegerLiteralSeparatorFixer.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ class IntegerLiteralSeparatorFixer {
2727

2828
private:
2929
bool checkSeparator(const StringRef IntegerLiteral, int DigitsPerGroup) const;
30-
std::string format(const StringRef IntegerLiteral, int DigitsPerGroup) const;
30+
std::string format(const StringRef IntegerLiteral, int DigitsPerGroup,
31+
int DigitCount, bool RemoveSeparator) const;
3132

3233
char Separator;
3334
};

clang/unittests/Format/IntegerLiteralSeparatorTest.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,41 @@ TEST_F(IntegerLiteralSeparatorTest, UnderscoreAsSeparator) {
166166
verifyFormat("o = 0o400000000000000003n;", Style);
167167
}
168168

169+
TEST_F(IntegerLiteralSeparatorTest, MinDigits) {
170+
FormatStyle Style = getLLVMStyle();
171+
Style.IntegerLiteralSeparator.Binary = 3;
172+
Style.IntegerLiteralSeparator.Decimal = 3;
173+
Style.IntegerLiteralSeparator.Hex = 2;
174+
175+
Style.IntegerLiteralSeparator.BinaryMinDigits = 7;
176+
verifyFormat("b1 = 0b101101;\n"
177+
"b2 = 0b1'101'101;",
178+
"b1 = 0b101'101;\n"
179+
"b2 = 0b1101101;",
180+
Style);
181+
182+
Style.IntegerLiteralSeparator.DecimalMinDigits = 5;
183+
verifyFormat("d1 = 2023;\n"
184+
"d2 = 10'000;",
185+
"d1 = 2'023;\n"
186+
"d2 = 100'00;",
187+
Style);
188+
189+
Style.IntegerLiteralSeparator.DecimalMinDigits = 3;
190+
verifyFormat("d1 = 123;\n"
191+
"d2 = 1'234;",
192+
"d1 = 12'3;\n"
193+
"d2 = 12'34;",
194+
Style);
195+
196+
Style.IntegerLiteralSeparator.HexMinDigits = 6;
197+
verifyFormat("h1 = 0xABCDE;\n"
198+
"h2 = 0xAB'CD'EF;",
199+
"h1 = 0xA'BC'DE;\n"
200+
"h2 = 0xABC'DEF;",
201+
Style);
202+
}
203+
169204
TEST_F(IntegerLiteralSeparatorTest, FixRanges) {
170205
FormatStyle Style = getLLVMStyle();
171206
Style.IntegerLiteralSeparator.Decimal = 3;

0 commit comments

Comments
 (0)