Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4651,7 +4651,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.

Expand All @@ -4671,6 +4676,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
Expand All @@ -4688,6 +4706,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
Expand All @@ -4706,6 +4737,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:

Expand Down
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,7 @@ clang-format
literals.
- Add ``Leave`` suboption to ``IndentPPDirectives``.
- Add ``AllowBreakBeforeQtProperty`` option.
- Add ``(Binary|Decimal|Hex)MaxDigitsSeparator`` suboptions to ``IntegerLiteralSeparator``.

libclang
--------
Expand Down
52 changes: 50 additions & 2 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -3174,7 +3174,12 @@ struct FormatStyle {
///
/// 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.
struct IntegerLiteralSeparatorStyle {
/// Format separators in binary literals.
/// \code{.text}
Expand All @@ -3192,6 +3197,18 @@ struct FormatStyle {
/// b2 = 0b1'101'101;
/// \endcode
int8_t BinaryMinDigits;
/// Remove separators in binary literals with a maximum number of digits.
/// \code{.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.
/// \endcode
int8_t BinaryMaxDigitsNoSeparator;
/// Format separators in decimal literals.
/// \code{.text}
/// /* -1: */ d = 18446744073709550592ull;
Expand All @@ -3207,6 +3224,18 @@ struct FormatStyle {
/// d2 = 10'000;
/// \endcode
int8_t DecimalMinDigits;
/// Remove separators in decimal literals with a maximum number of digits.
/// \code{.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.
/// \endcode
int8_t DecimalMaxDigitsNoSeparator;
/// Format separators in hexadecimal literals.
/// \code{.text}
/// /* -1: */ h = 0xDEADBEEFDEADBEEFuz;
Expand All @@ -3223,10 +3252,29 @@ struct FormatStyle {
/// h2 = 0xAB'CD'EF;
/// \endcode
int8_t HexMinDigits;
/// Remove separators in hexadecimal literals with a maximum number of
/// digits.
/// \code{.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.
/// \endcode
int8_t HexMaxDigitsNoSeparator;
bool operator==(const IntegerLiteralSeparatorStyle &R) const {
return Binary == R.Binary && BinaryMinDigits == R.BinaryMinDigits &&
BinaryMaxDigitsNoSeparator == R.BinaryMaxDigitsNoSeparator &&
Decimal == R.Decimal && DecimalMinDigits == R.DecimalMinDigits &&
Hex == R.Hex && HexMinDigits == R.HexMinDigits;
DecimalMaxDigitsNoSeparator == R.DecimalMaxDigitsNoSeparator &&
Hex == R.Hex && HexMinDigits == R.HexMinDigits &&
HexMaxDigitsNoSeparator == R.HexMaxDigitsNoSeparator;
}
bool operator!=(const IntegerLiteralSeparatorStyle &R) const {
return !operator==(R);
}
};

Expand Down
18 changes: 14 additions & 4 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,10 +399,15 @@ 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("BinaryMaxDigitsNoSeparator",
Base.BinaryMaxDigitsNoSeparator);
IO.mapOptional("Decimal", Base.Decimal);
IO.mapOptional("DecimalMinDigits", Base.DecimalMinDigits);
IO.mapOptional("DecimalMaxDigitsNoSeparator",
Base.DecimalMaxDigitsNoSeparator);
IO.mapOptional("Hex", Base.Hex);
IO.mapOptional("HexMinDigits", Base.HexMinDigits);
IO.mapOptional("HexMaxDigitsNoSeparator", Base.HexMaxDigitsNoSeparator);
}
};

Expand Down Expand Up @@ -1673,10 +1678,15 @@ 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 = {/*Binary=*/0,
/*BinaryMinDigits=*/0,
/*BinaryMaxDigitsNoSeparator=*/-1,
/*Decimal=*/0,
/*DecimalMinDigits=*/0,
/*DecimalMaxDigitsNoSeparator=*/-1,
/*Hex=*/0,
/*HexMinDigits=*/0,
/*HexMaxDigitsNoSeparator=*/-1};
LLVMStyle.JavaScriptQuotes = FormatStyle::JSQS_Leave;
LLVMStyle.JavaScriptWrapImports = true;
LLVMStyle.KeepEmptyLines = {
Expand Down
38 changes: 31 additions & 7 deletions clang/lib/Format/IntegerLiteralSeparatorFixer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [](int8_t Digits, int8_t MinDigits,
int8_t MaxDigitsNoSeparator) {
std::pair<int, int> Ret;
Ret.first = std::max<int>(MinDigits, Digits + 1);
if (Ret.first == 0)
Ret.second = 0;
else if (MaxDigitsNoSeparator < 0)
Ret.second = Ret.first - 1;
else
Ret.second = std::min<int>(MaxDigitsNoSeparator, Ret.first - 1);
return Ret;
};

const auto [BinaryMinDigits, BinaryMaxDigitsNoSeparator] = CalcMinAndMax(
Binary, Option.BinaryMinDigits, Option.BinaryMaxDigitsNoSeparator);
const auto [DecimalMinDigits, DecimalMaxDigitsNoSeparator] = CalcMinAndMax(
Decimal, Option.DecimalMinDigits, Option.DecimalMaxDigitsNoSeparator);
const auto [HexMinDigits, HexMaxDigitsNoSeparator] =
CalcMinAndMax(Hex, Option.HexMinDigits, Option.HexMaxDigitsNoSeparator);

const auto &SourceMgr = Env.getSourceManager();
AffectedRangeManager AffectedRangeMgr(SourceMgr, Env.getCharRanges());
Expand Down Expand Up @@ -139,19 +153,29 @@ IntegerLiteralSeparatorFixer::process(const Environment &Env,
}
auto DigitsPerGroup = Decimal;
auto MinDigits = DecimalMinDigits;
auto MaxDigitsNoSeparator = DecimalMaxDigitsNoSeparator;
if (IsBase2) {
DigitsPerGroup = Binary;
MinDigits = BinaryMinDigits;
MaxDigitsNoSeparator = BinaryMaxDigitsNoSeparator;
} else if (IsBase16) {
DigitsPerGroup = Hex;
MinDigits = HexMinDigits;
MaxDigitsNoSeparator = HexMaxDigitsNoSeparator;
}
const auto SeparatorCount = Text.count(Separator);
const int DigitCount = Length - SeparatorCount;
const bool RemoveSeparator = DigitsPerGroup < 0 || DigitCount < MinDigits;
const bool RemoveSeparator =
DigitsPerGroup < 0 || DigitCount <= MaxDigitsNoSeparator;
const bool AddSeparator =
DigitsPerGroup > 0 &&
(DigitCount >= MinDigits ||
(DigitCount > MaxDigitsNoSeparator && SeparatorCount > 0));
if (!RemoveSeparator && !AddSeparator)
continue;
if (RemoveSeparator && SeparatorCount == 0)
continue;
if (!RemoveSeparator && SeparatorCount > 0 &&
if (AddSeparator && SeparatorCount > 0 &&
checkSeparator(Text, DigitsPerGroup)) {
continue;
}
Expand Down
22 changes: 22 additions & 0 deletions clang/unittests/Format/ConfigParseTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,28 @@ TEST(ConfigParseTest, ParsesConfiguration) {
FormatStyle::BLS_Block);
CHECK_PARSE("Cpp11BracedListStyle: true", Cpp11BracedListStyle,
FormatStyle::BLS_AlignFirstComment);

const FormatStyle::IntegerLiteralSeparatorStyle
ExpectedIntegerLiteralSeparatorStyle{/*Binary=*/2,
/*BinaryMinDigit=*/5,
/*BinaryMaxDigitNoSeparator=*/2,
/*Decimal=*/6,
/*DecimalMinDigit=*/6,
/*DecimalMaxDigitNoSeparator=*/3,
/*Hex=*/4,
/*HexMinDigit=*/2,
/*HexMaxDigitNoSeparator=*/1};
CHECK_PARSE("IntegerLiteralSeparator:\n"
" Binary: 2\n"
" BinaryMinDigits: 5\n"
" BinaryMaxDigitsNoSeparator: 2\n"
" Decimal: 6\n"
" DecimalMinDigits: 6\n"
" DecimalMaxDigitsNoSeparator: 3\n"
" Hex: 4\n"
" HexMinDigits: 2\n"
" HexMaxDigitsNoSeparator: 1",
IntegerLiteralSeparator, ExpectedIntegerLiteralSeparatorStyle);
}

TEST(ConfigParseTest, ParsesConfigurationWithLanguages) {
Expand Down
16 changes: 16 additions & 0 deletions clang/unittests/Format/IntegerLiteralSeparatorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,22 @@ TEST_F(IntegerLiteralSeparatorTest, FloatingPoint) {
Style);
}

TEST_F(IntegerLiteralSeparatorTest, MaxDigitsNoSeparator) {
auto Style = getLLVMStyle();
Style.IntegerLiteralSeparator.Decimal = 3;
Style.IntegerLiteralSeparator.DecimalMaxDigitsNoSeparator = 4;
Style.IntegerLiteralSeparator.DecimalMinDigits = 7;
verifyFormat("d0 = 2023;\n"
"d1 = 123456;\n"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's weird that unlike d2, d1 doesn't get a separator.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not weird at all, maybe not good enough explained by me.
Everything with 4 or less digits gets all separators stripped, everything with 7 or above digits get separators added or corrected, and everything in between gets none added, if there were none, but if there is at least one separator they will be corrected.

"d2 = 123'456;\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
Expand Down