Skip to content

Commit 4f25089

Browse files
committed
[clang-format] add an option to insert a space only for empty braces
1 parent 4b70294 commit 4f25089

File tree

7 files changed

+405
-24
lines changed

7 files changed

+405
-24
lines changed

clang/docs/ClangFormatStyleOptions.rst

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6036,12 +6036,103 @@ the configuration (without a prefix: ``Auto``).
60366036

60376037
**SpaceInEmptyBlock** (``Boolean``) :versionbadge:`clang-format 10` :ref:`<SpaceInEmptyBlock>`
60386038
If ``true``, spaces will be inserted into ``{}``.
6039+
This option is **deprecated**. The previous behavior is preserved by using
6040+
``SpaceInEmptyBraces`` with ``Custom`` and by setting ``Block`` in
6041+
``SpaceInEmptyBracesOptions`` to ``true``.
6042+
6043+
.. _SpaceInEmptyBraces:
6044+
6045+
**SpaceInEmptyBraces** (``SpaceInEmptyBracesStyle``) :versionbadge:`clang-format 19` :ref:`<SpaceInEmptyBraces>`
6046+
Defines in which cases spaces will be inserted in empty braces.
6047+
6048+
Possible values:
6049+
6050+
* ``SIEBO_Never`` (in configuration: ``Never``)
6051+
Never put a space in empty braces.
6052+
6053+
.. code-block:: c++
6054+
6055+
void f() {}
6056+
T x{};
6057+
while (true) {}
6058+
struct U1 {};
6059+
union U2 {};
6060+
class U3 {};
6061+
enum U4 {};
6062+
6063+
* ``SIEBO_Custom`` (in configuration: ``Custom``)
6064+
Configure each individual space in empty braces in
6065+
`SpacesInEmptyBracesOptions`.
6066+
6067+
6068+
6069+
.. _SpaceInEmptyBracesOptions:
6070+
6071+
**SpaceInEmptyBracesOptions** (``SpaceInEmptyBracesCustom``) :versionbadge:`clang-format 19` :ref:`<SpaceInEmptyBracesOptions>`
6072+
Control of individual spaces in empty braces.
6073+
6074+
If ``SpaceInEmptyBraces`` is set to ``Custom``, use this to specify
6075+
how each individual space in empty braces case should be handled.
6076+
Otherwise, this is ignored.
6077+
6078+
.. code-block:: yaml
6079+
6080+
# Example of usage:
6081+
SpaceInEmptyBraces: Custom
6082+
SpaceInEmptyBracesOptions:
6083+
Function: true
6084+
Record: false
6085+
InitList: true
6086+
Block: false
6087+
6088+
Nested configuration flags:
6089+
6090+
Precise control over the spacing in empty braces.
60396091

60406092
.. code-block:: c++
60416093

6042-
true: false:
6043-
void f() { } vs. void f() {}
6044-
while (true) { } while (true) {}
6094+
# Should be declared this way:
6095+
SpaceInEmptyBraces: Custom
6096+
SpaceInEmptyBracesOptions:
6097+
Function: true
6098+
Record: false
6099+
InitList: true
6100+
Block: false
6101+
6102+
* ``bool Function`` Put a space in empty braces of function definition.
6103+
6104+
.. code-block:: c++
6105+
6106+
true: false:
6107+
void f() { } vs. void f() {}
6108+
6109+
* ``bool Record`` Put a space in empty braces of record/struct definition.
6110+
6111+
.. code-block:: c++
6112+
6113+
true: false:
6114+
struct U1 { }; vs. struct U1 {};
6115+
union U2 { }; union U2 {};
6116+
class U3 { }; class U3 {};
6117+
enum U4 { }; enum U4 {};
6118+
6119+
* ``bool InitList`` Put a space in empty braces of initializer list.
6120+
6121+
.. code-block:: c++
6122+
6123+
true: false:
6124+
T x{ }; vs. T x{};
6125+
6126+
* ``bool Block`` Put a space in empty braces of other blocks, including functions and
6127+
record, compatible with ``SpaceInEmptyBlock``.
6128+
6129+
.. code-block:: c++
6130+
6131+
true: false:
6132+
void f() { } vs. void f() {}
6133+
enum Unit { }; enum Unit {};
6134+
while (true) { } while (true) {}
6135+
60456136

60466137
.. _SpaceInEmptyParentheses:
60476138

clang/include/clang/Format/Format.h

Lines changed: 107 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4493,13 +4493,11 @@ struct FormatStyle {
44934493
bool SpaceBeforeRangeBasedForLoopColon;
44944494

44954495
/// If ``true``, spaces will be inserted into ``{}``.
4496-
/// \code
4497-
/// true: false:
4498-
/// void f() { } vs. void f() {}
4499-
/// while (true) { } while (true) {}
4500-
/// \endcode
4496+
/// This option is **deprecated**. The previous behavior is preserved by using
4497+
/// ``SpaceInEmptyBraces`` with ``Custom`` and by setting ``Block`` in
4498+
/// ``SpaceInEmptyBracesOptions`` to ``true``.
45014499
/// \version 10
4502-
bool SpaceInEmptyBlock;
4500+
// bool SpaceInEmptyBlock;
45034501

45044502
/// If ``true``, spaces may be inserted into ``()``.
45054503
/// This option is **deprecated**. See ``InEmptyParentheses`` of
@@ -4721,6 +4719,107 @@ struct FormatStyle {
47214719
/// \version 17
47224720
SpacesInParensCustom SpacesInParensOptions;
47234721

4722+
/// Different ways to put a space in empty braces.
4723+
enum SpaceInEmptyBracesStyle : int8_t {
4724+
/// Never put a space in empty braces.
4725+
/// \code
4726+
/// void f() {}
4727+
/// T x{};
4728+
/// while (true) {}
4729+
/// struct U1 {};
4730+
/// union U2 {};
4731+
/// class U3 {};
4732+
/// enum U4 {};
4733+
/// \endcode
4734+
SIEBO_Never,
4735+
/// Always put a space in empty braces.
4736+
SIEBO_Always,
4737+
/// Configure each individual space in empty braces in
4738+
/// `SpacesInEmptyBracesOptions`.
4739+
SIEBO_Custom,
4740+
};
4741+
4742+
/// Defines in which cases spaces will be inserted in empty braces.
4743+
/// \version 19
4744+
SpaceInEmptyBracesStyle SpaceInEmptyBraces;
4745+
4746+
/// Precise control over the spacing in empty braces.
4747+
/// \code
4748+
/// # Should be declared this way:
4749+
/// SpaceInEmptyBraces: Custom
4750+
/// SpaceInEmptyBracesOptions:
4751+
/// Function: true
4752+
/// Record: false
4753+
/// InitList: true
4754+
/// Block: false
4755+
/// \endcode
4756+
struct SpaceInEmptyBracesCustom {
4757+
/// Put a space in empty braces of function definition.
4758+
/// \code
4759+
/// true: false:
4760+
/// void f() { } vs. void f() {}
4761+
/// \endcode
4762+
bool Function;
4763+
/// Put a space in empty braces of record/struct definition.
4764+
/// \code
4765+
/// true: false:
4766+
/// struct U1 { }; vs. struct U1 {};
4767+
/// union U2 { }; union U2 {};
4768+
/// class U3 { }; class U3 {};
4769+
/// enum U4 { }; enum U4 {};
4770+
/// \endcode
4771+
bool Record;
4772+
/// Put a space in empty braces of initializer list.
4773+
/// \code
4774+
/// true: false:
4775+
/// T x{ }; vs. T x{};
4776+
/// \endcode
4777+
bool InitList;
4778+
/// Put a space in empty braces of other blocks, including functions and
4779+
/// record, compatible with ``SpaceInEmptyBlock``.
4780+
/// \code
4781+
/// true: false:
4782+
/// void f() { } vs. void f() {}
4783+
/// enum Unit { }; enum Unit {};
4784+
/// while (true) { } while (true) {}
4785+
/// \endcode
4786+
bool Block;
4787+
4788+
SpaceInEmptyBracesCustom()
4789+
: Function(false), Record(false), InitList(false), Block(false) {}
4790+
4791+
SpaceInEmptyBracesCustom(bool Function, bool Record, bool InitList,
4792+
bool Block)
4793+
: Function(Function), Record(Record), InitList(InitList), Block(Block) {
4794+
}
4795+
4796+
bool operator==(const SpaceInEmptyBracesCustom &R) const {
4797+
return Function == R.Function && Record == R.Record &&
4798+
InitList == R.InitList && Block == R.Block;
4799+
}
4800+
4801+
bool operator!=(const SpaceInEmptyBracesCustom &R) const {
4802+
return !(*this == R);
4803+
}
4804+
};
4805+
4806+
/// Control of individual spaces in empty braces.
4807+
///
4808+
/// If ``SpaceInEmptyBraces`` is set to ``Custom``, use this to specify
4809+
/// how each individual space in empty braces case should be handled.
4810+
/// Otherwise, this is ignored.
4811+
/// \code{.yaml}
4812+
/// # Example of usage:
4813+
/// SpaceInEmptyBraces: Custom
4814+
/// SpaceInEmptyBracesOptions:
4815+
/// Function: true
4816+
/// Record: false
4817+
/// InitList: true
4818+
/// Block: false
4819+
/// \endcode
4820+
/// \version 19
4821+
SpaceInEmptyBracesCustom SpaceInEmptyBracesOptions;
4822+
47244823
/// If ``true``, spaces will be inserted after ``[`` and before ``]``.
47254824
/// Lambdas without arguments or unspecified size array declarations will not
47264825
/// be affected.
@@ -5094,7 +5193,8 @@ struct FormatStyle {
50945193
SpaceBeforeRangeBasedForLoopColon ==
50955194
R.SpaceBeforeRangeBasedForLoopColon &&
50965195
SpaceBeforeSquareBrackets == R.SpaceBeforeSquareBrackets &&
5097-
SpaceInEmptyBlock == R.SpaceInEmptyBlock &&
5196+
SpaceInEmptyBraces == R.SpaceInEmptyBraces &&
5197+
SpaceInEmptyBracesOptions == R.SpaceInEmptyBracesOptions &&
50985198
SpacesBeforeTrailingComments == R.SpacesBeforeTrailingComments &&
50995199
SpacesInAngles == R.SpacesInAngles &&
51005200
SpacesInContainerLiterals == R.SpacesInContainerLiterals &&

clang/lib/Format/Format.cpp

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,24 @@ template <> struct MappingTraits<FormatStyle::SpacesInLineComment> {
719719
}
720720
};
721721

722+
template <> struct MappingTraits<FormatStyle::SpaceInEmptyBracesCustom> {
723+
static void mapping(IO &IO, FormatStyle::SpaceInEmptyBracesCustom &Space) {
724+
IO.mapOptional("Function", Space.Function);
725+
IO.mapOptional("Record", Space.Record);
726+
IO.mapOptional("InitList", Space.InitList);
727+
IO.mapOptional("Block", Space.Block);
728+
}
729+
};
730+
731+
template <>
732+
struct ScalarEnumerationTraits<FormatStyle::SpaceInEmptyBracesStyle> {
733+
static void enumeration(IO &IO, FormatStyle::SpaceInEmptyBracesStyle &Value) {
734+
IO.enumCase(Value, "Never", FormatStyle::SIEBO_Never);
735+
IO.enumCase(Value, "Always", FormatStyle::SIEBO_Always);
736+
IO.enumCase(Value, "Custom", FormatStyle::SIEBO_Custom);
737+
}
738+
};
739+
722740
template <> struct MappingTraits<FormatStyle::SpacesInParensCustom> {
723741
static void mapping(IO &IO, FormatStyle::SpacesInParensCustom &Spaces) {
724742
IO.mapOptional("InCStyleCasts", Spaces.InCStyleCasts);
@@ -850,6 +868,7 @@ template <> struct MappingTraits<FormatStyle> {
850868
bool UseCRLF = false;
851869

852870
bool SpaceInEmptyParentheses = false;
871+
bool SpaceInEmptyBlock = false;
853872
bool SpacesInConditionalStatement = false;
854873
bool SpacesInCStyleCastParentheses = false;
855874
bool SpacesInParentheses = false;
@@ -876,6 +895,7 @@ template <> struct MappingTraits<FormatStyle> {
876895
IO.mapOptional("SpaceAfterControlStatementKeyword",
877896
Style.SpaceBeforeParens);
878897
IO.mapOptional("SpaceInEmptyParentheses", SpaceInEmptyParentheses);
898+
IO.mapOptional("SpaceInEmptyBlock", SpaceInEmptyBlock);
879899
IO.mapOptional("SpacesInConditionalStatement",
880900
SpacesInConditionalStatement);
881901
IO.mapOptional("SpacesInCStyleCastParentheses",
@@ -1092,14 +1112,16 @@ template <> struct MappingTraits<FormatStyle> {
10921112
Style.SpaceBeforeRangeBasedForLoopColon);
10931113
IO.mapOptional("SpaceBeforeSquareBrackets",
10941114
Style.SpaceBeforeSquareBrackets);
1095-
IO.mapOptional("SpaceInEmptyBlock", Style.SpaceInEmptyBlock);
10961115
IO.mapOptional("SpacesBeforeTrailingComments",
10971116
Style.SpacesBeforeTrailingComments);
10981117
IO.mapOptional("SpacesInAngles", Style.SpacesInAngles);
10991118
IO.mapOptional("SpacesInContainerLiterals",
11001119
Style.SpacesInContainerLiterals);
11011120
IO.mapOptional("SpacesInLineCommentPrefix",
11021121
Style.SpacesInLineCommentPrefix);
1122+
IO.mapOptional("SpaceInEmptyBraces", Style.SpaceInEmptyBraces);
1123+
IO.mapOptional("SpaceInEmptyBracesOptions",
1124+
Style.SpaceInEmptyBracesOptions);
11031125
IO.mapOptional("SpacesInParens", Style.SpacesInParens);
11041126
IO.mapOptional("SpacesInParensOptions", Style.SpacesInParensOptions);
11051127
IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets);
@@ -1194,6 +1216,15 @@ template <> struct MappingTraits<FormatStyle> {
11941216
}
11951217
Style.SpacesInParens = FormatStyle::SIPO_Custom;
11961218
}
1219+
1220+
if (Style.SpaceInEmptyBraces != FormatStyle::SIEBO_Custom &&
1221+
SpaceInEmptyBlock) {
1222+
Style.SpaceInEmptyBraces = FormatStyle::SIEBO_Custom;
1223+
Style.SpaceInEmptyBracesOptions.Function = true;
1224+
Style.SpaceInEmptyBracesOptions.Record = true;
1225+
Style.SpaceInEmptyBracesOptions.InitList = false;
1226+
Style.SpaceInEmptyBracesOptions.Block = true;
1227+
}
11971228
}
11981229
};
11991230

@@ -1563,7 +1594,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
15631594
LLVMStyle.SpaceBeforeParensOptions.AfterIfMacros = true;
15641595
LLVMStyle.SpaceBeforeRangeBasedForLoopColon = true;
15651596
LLVMStyle.SpaceBeforeSquareBrackets = false;
1566-
LLVMStyle.SpaceInEmptyBlock = false;
1597+
LLVMStyle.SpaceInEmptyBraces = FormatStyle::SIEBO_Never;
15671598
LLVMStyle.SpacesBeforeTrailingComments = 1;
15681599
LLVMStyle.SpacesInAngles = FormatStyle::SIAS_Never;
15691600
LLVMStyle.SpacesInContainerLiterals = true;
@@ -1864,7 +1895,10 @@ FormatStyle getWebKitStyle() {
18641895
Style.ObjCSpaceAfterProperty = true;
18651896
Style.PointerAlignment = FormatStyle::PAS_Left;
18661897
Style.SpaceBeforeCpp11BracedList = true;
1867-
Style.SpaceInEmptyBlock = true;
1898+
Style.SpaceInEmptyBraces = FormatStyle::SIEBO_Custom;
1899+
Style.SpaceInEmptyBracesOptions.Block = true;
1900+
Style.SpacesInParensOptions.InEmptyParentheses = false;
1901+
Style.SpacesInParensOptions.Other = false;
18681902
return Style;
18691903
}
18701904

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4337,15 +4337,32 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
43374337
return Left.is(tok::hash);
43384338
if (Left.isOneOf(tok::hashhash, tok::hash))
43394339
return Right.is(tok::hash);
4340-
if (Left.is(BK_Block) && Right.is(tok::r_brace) &&
4341-
Right.MatchingParen == &Left && Line.Children.empty()) {
4342-
return Style.SpaceInEmptyBlock;
4343-
}
4340+
43444341
if ((Left.is(tok::l_paren) && Right.is(tok::r_paren)) ||
43454342
(Left.is(tok::l_brace) && Left.isNot(BK_Block) &&
4346-
Right.is(tok::r_brace) && Right.isNot(BK_Block))) {
4343+
Right.is(tok::r_brace) && Right.isNot(BK_Block) &&
4344+
Style.SpaceInEmptyBraces == FormatStyle::SIEBO_Never)) {
43474345
return Style.SpacesInParensOptions.InEmptyParentheses;
43484346
}
4347+
// Other braces for records are handled in tryMergeSimpleBlock on
4348+
// UnwrappedLineFormatter.cpp.
4349+
if (Left.is(tok::l_brace) && Right.is(tok::r_brace) &&
4350+
Right.MatchingParen == &Left && Line.Children.empty()) {
4351+
if (Style.SpaceInEmptyBraces == FormatStyle::SIEBO_Never)
4352+
return false;
4353+
if (Style.SpaceInEmptyBraces == FormatStyle::SIEBO_Always)
4354+
return true;
4355+
if (Style.SpaceInEmptyBraces == FormatStyle::SIEBO_Custom) {
4356+
if (Left.is(BK_BracedInit) && Right.is(BK_BracedInit))
4357+
return Style.SpaceInEmptyBracesOptions.InitList;
4358+
if (Left.is(TT_EnumLBrace) && Right.is(TT_EnumRBrace)) {
4359+
return Style.SpaceInEmptyBracesOptions.Record ||
4360+
Style.SpaceInEmptyBracesOptions.Block;
4361+
}
4362+
if (Left.is(BK_Block))
4363+
return Style.SpaceInEmptyBracesOptions.Block;
4364+
}
4365+
}
43494366
if (Style.SpacesInParensOptions.InConditionalStatements) {
43504367
const FormatToken *LeftParen = nullptr;
43514368
if (Left.is(tok::l_paren))

0 commit comments

Comments
 (0)