Skip to content

Commit f4be7c7

Browse files
[clang-format] Add xxxMaxDigitsNoSeparator
This basically adds a Leave option for a specific range of literals.
1 parent 2272726 commit f4be7c7

File tree

5 files changed

+148
-14
lines changed

5 files changed

+148
-14
lines changed

clang/docs/ClangFormatStyleOptions.rst

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4651,7 +4651,12 @@ the configuration (without a prefix: ``Auto``).
46514651

46524652
You can also specify a minimum number of digits (``BinaryMinDigits``,
46534653
``DecimalMinDigits``, and ``HexMinDigits``) the integer literal must
4654-
have in order for the separators to be inserted.
4654+
have in order for the separators to be inserted, and a maximum number of
4655+
digits (``BinaryMaxDigitsNoSeparator``, ``DecimalMaxDigitsNoSeparator``,
4656+
and ``HexMaxDigitsNoSeparator``) until the separators are removed. This
4657+
divides the literals in 3 regions, always without separator (up until
4658+
including ``xxxMaxDigitsNoSeparator``), maybe with, or without separators
4659+
(up until excluding ``xxxMinDigits``), and finally always with separators.
46554660

46564661
* ``int8_t Binary`` Format separators in binary literals.
46574662

@@ -4671,6 +4676,18 @@ the configuration (without a prefix: ``Auto``).
46714676
b1 = 0b101101;
46724677
b2 = 0b1'101'101;
46734678
4679+
* ``int8_t BinaryMaxDigitsNoSeparator`` Remove separators in binary literals with a maximum number of digits.
4680+
4681+
.. code-block:: text
4682+
4683+
// Binary: 3
4684+
// BinaryMinDigits: 7
4685+
// BinaryMaxDigitsNoSeparator: 4
4686+
b0 = 0b1011; // Always removed.
4687+
b1 = 0b101101; // Not added.
4688+
b2 = 0b101'101; // Not removed.
4689+
b3 = 0b1'101'101; // Always added.
4690+
46744691
* ``int8_t Decimal`` Format separators in decimal literals.
46754692

46764693
.. code-block:: text
@@ -4688,6 +4705,18 @@ the configuration (without a prefix: ``Auto``).
46884705
d1 = 2023;
46894706
d2 = 10'000;
46904707
4708+
* ``int8_t DecimalMaxDigitsNoSeparator`` Remove separators in decimal literals with a maximum number of digits.
4709+
4710+
.. code-block:: text
4711+
4712+
// Decimal: 3
4713+
// DecimalMinDigits: 7
4714+
// DecimalMaxDigitsNoSeparator: 4
4715+
d0 = 2023; // Always removed.
4716+
d1 = 123456; // Not added.
4717+
d2 = 123'456; // Not removed.
4718+
d3 = 5'000'000; // Always added.
4719+
46914720
* ``int8_t Hex`` Format separators in hexadecimal literals.
46924721

46934722
.. code-block:: text
@@ -4706,6 +4735,19 @@ the configuration (without a prefix: ``Auto``).
47064735
h1 = 0xABCDE;
47074736
h2 = 0xAB'CD'EF;
47084737
4738+
* ``int8_t HexMaxDigitsNoSeparator`` Remove separators in hexadecimal literals with a maximum number of
4739+
digits.
4740+
4741+
.. code-block:: text
4742+
4743+
// Hex: 2
4744+
// HexMinDigits: 6
4745+
// HexMaxDigitsNoSeparator: 4
4746+
h0 = 0xAFFE; // Always removed.
4747+
h1 = 0xABCDE; // Not added.
4748+
h2 = 0xA'BC'DE; // Not removed.
4749+
h3 = 0xAB'CD'EF; // Always added.
4750+
47094751
47104752
.. _JavaImportGroups:
47114753

clang/include/clang/Format/Format.h

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3174,7 +3174,12 @@ struct FormatStyle {
31743174
///
31753175
/// You can also specify a minimum number of digits (``BinaryMinDigits``,
31763176
/// ``DecimalMinDigits``, and ``HexMinDigits``) the integer literal must
3177-
/// have in order for the separators to be inserted.
3177+
/// have in order for the separators to be inserted, and a maximum number of
3178+
/// digits (``BinaryMaxDigitsNoSeparator``, ``DecimalMaxDigitsNoSeparator``,
3179+
/// and ``HexMaxDigitsNoSeparator``) until the separators are removed. This
3180+
/// divides the literals in 3 regions, always without separator (up until
3181+
/// including ``xxxMaxDigitsNoSeparator``), maybe with, or without separators
3182+
/// (up until excluding ``xxxMinDigits``), and finally always with separators.
31783183
struct IntegerLiteralSeparatorStyle {
31793184
/// Format separators in binary literals.
31803185
/// \code{.text}
@@ -3192,6 +3197,17 @@ struct FormatStyle {
31923197
/// b2 = 0b1'101'101;
31933198
/// \endcode
31943199
int8_t BinaryMinDigits;
3200+
/// Remove separators in binary literals with a maximum number of digits.
3201+
/// \code{.text}
3202+
/// // Binary: 3
3203+
/// // BinaryMinDigits: 7
3204+
/// // BinaryMaxDigitsNoSeparator: 4
3205+
/// b0 = 0b1011; // Always removed.
3206+
/// b1 = 0b101101; // Not added.
3207+
/// b2 = 0b101'101; // Not removed.
3208+
/// b3 = 0b1'101'101; // Always added.
3209+
/// \endcode
3210+
int8_t BinaryMaxDigitsNoSeparator;
31953211
/// Format separators in decimal literals.
31963212
/// \code{.text}
31973213
/// /* -1: */ d = 18446744073709550592ull;
@@ -3207,6 +3223,17 @@ struct FormatStyle {
32073223
/// d2 = 10'000;
32083224
/// \endcode
32093225
int8_t DecimalMinDigits;
3226+
/// Remove separators in decimal literals with a maximum number of digits.
3227+
/// \code{.text}
3228+
/// // Decimal: 3
3229+
/// // DecimalMinDigits: 7
3230+
/// // DecimalMaxDigitsNoSeparator: 4
3231+
/// d0 = 2023; // Always removed.
3232+
/// d1 = 123456; // Not added.
3233+
/// d2 = 123'456; // Not removed.
3234+
/// d3 = 5'000'000; // Always added.
3235+
/// \endcode
3236+
int8_t DecimalMaxDigitsNoSeparator;
32103237
/// Format separators in hexadecimal literals.
32113238
/// \code{.text}
32123239
/// /* -1: */ h = 0xDEADBEEFDEADBEEFuz;
@@ -3223,10 +3250,25 @@ struct FormatStyle {
32233250
/// h2 = 0xAB'CD'EF;
32243251
/// \endcode
32253252
int8_t HexMinDigits;
3253+
/// Remove separators in hexadecimal literals with a maximum number of
3254+
/// digits.
3255+
/// \code{.text}
3256+
/// // Hex: 2
3257+
/// // HexMinDigits: 6
3258+
/// // HexMaxDigitsNoSeparator: 4
3259+
/// h0 = 0xAFFE; // Always removed.
3260+
/// h1 = 0xABCDE; // Not added.
3261+
/// h2 = 0xA'BC'DE; // Not removed.
3262+
/// h3 = 0xAB'CD'EF; // Always added.
3263+
/// \endcode
3264+
int8_t HexMaxDigitsNoSeparator;
32263265
bool operator==(const IntegerLiteralSeparatorStyle &R) const {
32273266
return Binary == R.Binary && BinaryMinDigits == R.BinaryMinDigits &&
3267+
BinaryMaxDigitsNoSeparator == R.BinaryMaxDigitsNoSeparator &&
32283268
Decimal == R.Decimal && DecimalMinDigits == R.DecimalMinDigits &&
3229-
Hex == R.Hex && HexMinDigits == R.HexMinDigits;
3269+
DecimalMaxDigitsNoSeparator == R.DecimalMaxDigitsNoSeparator &&
3270+
Hex == R.Hex && HexMinDigits == R.HexMinDigits &&
3271+
HexMaxDigitsNoSeparator == R.HexMaxDigitsNoSeparator;
32303272
}
32313273
};
32323274

clang/lib/Format/Format.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -399,10 +399,15 @@ template <> struct MappingTraits<FormatStyle::IntegerLiteralSeparatorStyle> {
399399
static void mapping(IO &IO, FormatStyle::IntegerLiteralSeparatorStyle &Base) {
400400
IO.mapOptional("Binary", Base.Binary);
401401
IO.mapOptional("BinaryMinDigits", Base.BinaryMinDigits);
402+
IO.mapOptional("BinaryMaxDigitsNoSeparator",
403+
Base.BinaryMaxDigitsNoSeparator);
402404
IO.mapOptional("Decimal", Base.Decimal);
403405
IO.mapOptional("DecimalMinDigits", Base.DecimalMinDigits);
406+
IO.mapOptional("DecimalMaxDigitsNoSeparator",
407+
Base.DecimalMaxDigitsNoSeparator);
404408
IO.mapOptional("Hex", Base.Hex);
405409
IO.mapOptional("HexMinDigits", Base.HexMinDigits);
410+
IO.mapOptional("HexMaxDigitsNoSeparator", Base.HexMaxDigitsNoSeparator);
406411
}
407412
};
408413

@@ -1673,10 +1678,15 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
16731678
LLVMStyle.InsertBraces = false;
16741679
LLVMStyle.InsertNewlineAtEOF = false;
16751680
LLVMStyle.InsertTrailingCommas = FormatStyle::TCS_None;
1676-
LLVMStyle.IntegerLiteralSeparator = {
1677-
/*Binary=*/0, /*BinaryMinDigits=*/0,
1678-
/*Decimal=*/0, /*DecimalMinDigits=*/0,
1679-
/*Hex=*/0, /*HexMinDigits=*/0};
1681+
LLVMStyle.IntegerLiteralSeparator = {/*Binary=*/0,
1682+
/*BinaryMinDigits=*/0,
1683+
/*BinaryMaxDigitsNoSeparator=*/-1,
1684+
/*Decimal=*/0,
1685+
/*DecimalMinDigits=*/0,
1686+
/*DecimalMaxDigitsNoSeparator=*/-1,
1687+
/*Hex=*/0,
1688+
/*HexMinDigits=*/0,
1689+
/*HexMaxDigitsNoSeparator=*/-1};
16801690
LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave;
16811691
LLVMStyle.JavaScriptWrapImports = true;
16821692
LLVMStyle.KeepEmptyLines = {

clang/lib/Format/IntegerLiteralSeparatorFixer.cpp

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,25 @@ IntegerLiteralSeparatorFixer::process(const Environment &Env,
7272
if (SkipBinary && SkipDecimal && SkipHex)
7373
return {};
7474

75-
const auto BinaryMinDigits =
76-
std::max((int)Option.BinaryMinDigits, Binary + 1);
77-
const auto DecimalMinDigits =
78-
std::max((int)Option.DecimalMinDigits, Decimal + 1);
79-
const auto HexMinDigits = std::max((int)Option.HexMinDigits, Hex + 1);
75+
auto CalcMinAndMax = [](int8_t Digits, int8_t MinDigits,
76+
int8_t MaxDigitsNoSeparator) {
77+
std::pair<int, int> Ret;
78+
Ret.first = std::max<int>(MinDigits, Digits + 1);
79+
if (Ret.first == 0)
80+
Ret.second = 0;
81+
else if (MaxDigitsNoSeparator < 0)
82+
Ret.second = Ret.first - 1;
83+
else
84+
Ret.second = std::min<int>(MaxDigitsNoSeparator, Ret.first - 1);
85+
return Ret;
86+
};
87+
88+
const auto [BinaryMinDigits, BinaryMaxDigitsNoSeparator] = CalcMinAndMax(
89+
Binary, Option.BinaryMinDigits, Option.BinaryMaxDigitsNoSeparator);
90+
const auto [DecimalMinDigits, DecimalMaxDigitsNoSeparator] = CalcMinAndMax(
91+
Decimal, Option.DecimalMinDigits, Option.DecimalMaxDigitsNoSeparator);
92+
const auto [HexMinDigits, HexMaxDigitsNoSeparator] =
93+
CalcMinAndMax(Hex, Option.HexMinDigits, Option.HexMaxDigitsNoSeparator);
8094

8195
const auto &SourceMgr = Env.getSourceManager();
8296
AffectedRangeManager AffectedRangeMgr(SourceMgr, Env.getCharRanges());
@@ -139,19 +153,29 @@ IntegerLiteralSeparatorFixer::process(const Environment &Env,
139153
}
140154
auto DigitsPerGroup = Decimal;
141155
auto MinDigits = DecimalMinDigits;
156+
auto MaxDigitsNoSeparator = DecimalMaxDigitsNoSeparator;
142157
if (IsBase2) {
143158
DigitsPerGroup = Binary;
144159
MinDigits = BinaryMinDigits;
160+
MaxDigitsNoSeparator = BinaryMaxDigitsNoSeparator;
145161
} else if (IsBase16) {
146162
DigitsPerGroup = Hex;
147163
MinDigits = HexMinDigits;
164+
MaxDigitsNoSeparator = HexMaxDigitsNoSeparator;
148165
}
149166
const auto SeparatorCount = Text.count(Separator);
150167
const int DigitCount = Length - SeparatorCount;
151-
const bool RemoveSeparator = DigitsPerGroup < 0 || DigitCount < MinDigits;
168+
const bool RemoveSeparator =
169+
DigitsPerGroup < 0 || DigitCount <= MaxDigitsNoSeparator;
170+
const bool AddSeparator =
171+
DigitsPerGroup > 0 &&
172+
(DigitCount >= MinDigits ||
173+
(DigitCount > MaxDigitsNoSeparator && SeparatorCount > 0));
174+
if (!RemoveSeparator && !AddSeparator)
175+
continue;
152176
if (RemoveSeparator && SeparatorCount == 0)
153177
continue;
154-
if (!RemoveSeparator && SeparatorCount > 0 &&
178+
if (AddSeparator && SeparatorCount > 0 &&
155179
checkSeparator(Text, DigitsPerGroup)) {
156180
continue;
157181
}

clang/unittests/Format/IntegerLiteralSeparatorTest.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,22 @@ TEST_F(IntegerLiteralSeparatorTest, FloatingPoint) {
243243
Style);
244244
}
245245

246+
TEST_F(IntegerLiteralSeparatorTest, MaxDigitsNoSeparator) {
247+
auto Style = getLLVMStyle();
248+
Style.IntegerLiteralSeparator.Decimal = 3;
249+
Style.IntegerLiteralSeparator.DecimalMaxDigitsNoSeparator = 4;
250+
Style.IntegerLiteralSeparator.DecimalMinDigits = 7;
251+
verifyFormat("d0 = 2023;\n"
252+
"d1 = 123456;\n"
253+
"d2 = 123'456;\n"
254+
"d3 = 5'000'000;",
255+
"d0 = 20'2'3;\n"
256+
"d1 = 123456;\n"
257+
"d2 = 1234'56;\n"
258+
"d3 = 5000000;",
259+
Style);
260+
}
261+
246262
} // namespace
247263
} // namespace test
248264
} // namespace format

0 commit comments

Comments
 (0)