Skip to content

Commit 4cdd7bd

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

File tree

7 files changed

+368
-20
lines changed

7 files changed

+368
-20
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: 105 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,105 @@ 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+
/// Configure each individual space in empty braces in
4736+
/// `SpacesInEmptyBracesOptions`.
4737+
SIEBO_Custom,
4738+
};
4739+
4740+
/// Defines in which cases spaces will be inserted in empty braces.
4741+
/// \version 19
4742+
SpaceInEmptyBracesStyle SpaceInEmptyBraces;
4743+
4744+
/// Precise control over the spacing in empty braces.
4745+
/// \code
4746+
/// # Should be declared this way:
4747+
/// SpaceInEmptyBraces: Custom
4748+
/// SpaceInEmptyBracesOptions:
4749+
/// Function: true
4750+
/// Record: false
4751+
/// InitList: true
4752+
/// Block: false
4753+
/// \endcode
4754+
struct SpaceInEmptyBracesCustom {
4755+
/// Put a space in empty braces of function definition.
4756+
/// \code
4757+
/// true: false:
4758+
/// void f() { } vs. void f() {}
4759+
/// \endcode
4760+
bool Function;
4761+
/// Put a space in empty braces of record/struct definition.
4762+
/// \code
4763+
/// true: false:
4764+
/// struct U1 { }; vs. struct U1 {};
4765+
/// union U2 { }; union U2 {};
4766+
/// class U3 { }; class U3 {};
4767+
/// enum U4 { }; enum U4 {};
4768+
/// \endcode
4769+
bool Record;
4770+
/// Put a space in empty braces of initializer list.
4771+
/// \code
4772+
/// true: false:
4773+
/// T x{ }; vs. T x{};
4774+
/// \endcode
4775+
bool InitList;
4776+
/// Put a space in empty braces of other blocks, including functions and
4777+
/// record, compatible with ``SpaceInEmptyBlock``.
4778+
/// \code
4779+
/// true: false:
4780+
/// void f() { } vs. void f() {}
4781+
/// enum Unit { }; enum Unit {};
4782+
/// while (true) { } while (true) {}
4783+
/// \endcode
4784+
bool Block;
4785+
4786+
SpaceInEmptyBracesCustom()
4787+
: Function(false), Record(false), InitList(false), Block(false) {}
4788+
4789+
SpaceInEmptyBracesCustom(bool Function, bool Record, bool InitList,
4790+
bool Block)
4791+
: Function(Function), Record(Record), InitList(InitList), Block(Block) {
4792+
}
4793+
4794+
bool operator==(const SpaceInEmptyBracesCustom &R) const {
4795+
return Function == R.Function && Record == R.Record &&
4796+
InitList == R.InitList && Block == R.Block;
4797+
}
4798+
4799+
bool operator!=(const SpaceInEmptyBracesCustom &R) const {
4800+
return !(*this == R);
4801+
}
4802+
};
4803+
4804+
/// Control of individual spaces in empty braces.
4805+
///
4806+
/// If ``SpaceInEmptyBraces`` is set to ``Custom``, use this to specify
4807+
/// how each individual space in empty braces case should be handled.
4808+
/// Otherwise, this is ignored.
4809+
/// \code{.yaml}
4810+
/// # Example of usage:
4811+
/// SpaceInEmptyBraces: Custom
4812+
/// SpaceInEmptyBracesOptions:
4813+
/// Function: true
4814+
/// Record: false
4815+
/// InitList: true
4816+
/// Block: false
4817+
/// \endcode
4818+
/// \version 19
4819+
SpaceInEmptyBracesCustom SpaceInEmptyBracesOptions;
4820+
47244821
/// If ``true``, spaces will be inserted after ``[`` and before ``]``.
47254822
/// Lambdas without arguments or unspecified size array declarations will not
47264823
/// be affected.
@@ -5094,7 +5191,8 @@ struct FormatStyle {
50945191
SpaceBeforeRangeBasedForLoopColon ==
50955192
R.SpaceBeforeRangeBasedForLoopColon &&
50965193
SpaceBeforeSquareBrackets == R.SpaceBeforeSquareBrackets &&
5097-
SpaceInEmptyBlock == R.SpaceInEmptyBlock &&
5194+
SpaceInEmptyBraces == R.SpaceInEmptyBraces &&
5195+
SpaceInEmptyBracesOptions == R.SpaceInEmptyBracesOptions &&
50985196
SpacesBeforeTrailingComments == R.SpacesBeforeTrailingComments &&
50995197
SpacesInAngles == R.SpacesInAngles &&
51005198
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,23 @@ 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, "Custom", FormatStyle::SIEBO_Custom);
736+
}
737+
};
738+
722739
template <> struct MappingTraits<FormatStyle::SpacesInParensCustom> {
723740
static void mapping(IO &IO, FormatStyle::SpacesInParensCustom &Spaces) {
724741
IO.mapOptional("InCStyleCasts", Spaces.InCStyleCasts);
@@ -850,6 +867,7 @@ template <> struct MappingTraits<FormatStyle> {
850867
bool UseCRLF = false;
851868

852869
bool SpaceInEmptyParentheses = false;
870+
bool SpaceInEmptyBlock = false;
853871
bool SpacesInConditionalStatement = false;
854872
bool SpacesInCStyleCastParentheses = false;
855873
bool SpacesInParentheses = false;
@@ -876,6 +894,7 @@ template <> struct MappingTraits<FormatStyle> {
876894
IO.mapOptional("SpaceAfterControlStatementKeyword",
877895
Style.SpaceBeforeParens);
878896
IO.mapOptional("SpaceInEmptyParentheses", SpaceInEmptyParentheses);
897+
IO.mapOptional("SpaceInEmptyBlock", SpaceInEmptyBlock);
879898
IO.mapOptional("SpacesInConditionalStatement",
880899
SpacesInConditionalStatement);
881900
IO.mapOptional("SpacesInCStyleCastParentheses",
@@ -1092,14 +1111,16 @@ template <> struct MappingTraits<FormatStyle> {
10921111
Style.SpaceBeforeRangeBasedForLoopColon);
10931112
IO.mapOptional("SpaceBeforeSquareBrackets",
10941113
Style.SpaceBeforeSquareBrackets);
1095-
IO.mapOptional("SpaceInEmptyBlock", Style.SpaceInEmptyBlock);
10961114
IO.mapOptional("SpacesBeforeTrailingComments",
10971115
Style.SpacesBeforeTrailingComments);
10981116
IO.mapOptional("SpacesInAngles", Style.SpacesInAngles);
10991117
IO.mapOptional("SpacesInContainerLiterals",
11001118
Style.SpacesInContainerLiterals);
11011119
IO.mapOptional("SpacesInLineCommentPrefix",
11021120
Style.SpacesInLineCommentPrefix);
1121+
IO.mapOptional("SpaceInEmptyBraces", Style.SpaceInEmptyBraces);
1122+
IO.mapOptional("SpaceInEmptyBracesOptions",
1123+
Style.SpaceInEmptyBracesOptions);
11031124
IO.mapOptional("SpacesInParens", Style.SpacesInParens);
11041125
IO.mapOptional("SpacesInParensOptions", Style.SpacesInParensOptions);
11051126
IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets);
@@ -1194,6 +1215,15 @@ template <> struct MappingTraits<FormatStyle> {
11941215
}
11951216
Style.SpacesInParens = FormatStyle::SIPO_Custom;
11961217
}
1218+
1219+
if (Style.SpaceInEmptyBraces != FormatStyle::SIEBO_Custom &&
1220+
SpaceInEmptyBlock) {
1221+
Style.SpaceInEmptyBraces = FormatStyle::SIEBO_Custom;
1222+
Style.SpaceInEmptyBracesOptions.Function = true;
1223+
Style.SpaceInEmptyBracesOptions.Record = true;
1224+
Style.SpaceInEmptyBracesOptions.InitList = false;
1225+
Style.SpaceInEmptyBracesOptions.Block = true;
1226+
}
11971227
}
11981228
};
11991229

@@ -1563,7 +1593,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
15631593
LLVMStyle.SpaceBeforeParensOptions.AfterIfMacros = true;
15641594
LLVMStyle.SpaceBeforeRangeBasedForLoopColon = true;
15651595
LLVMStyle.SpaceBeforeSquareBrackets = false;
1566-
LLVMStyle.SpaceInEmptyBlock = false;
1596+
LLVMStyle.SpaceInEmptyBraces = FormatStyle::SIEBO_Never;
15671597
LLVMStyle.SpacesBeforeTrailingComments = 1;
15681598
LLVMStyle.SpacesInAngles = FormatStyle::SIAS_Never;
15691599
LLVMStyle.SpacesInContainerLiterals = true;
@@ -1864,7 +1894,11 @@ FormatStyle getWebKitStyle() {
18641894
Style.ObjCSpaceAfterProperty = true;
18651895
Style.PointerAlignment = FormatStyle::PAS_Left;
18661896
Style.SpaceBeforeCpp11BracedList = true;
1867-
Style.SpaceInEmptyBlock = true;
1897+
Style.SpaceInEmptyBraces = FormatStyle::SIEBO_Custom;
1898+
Style.SpaceInEmptyBracesOptions.Block = true;
1899+
Style.SpaceInEmptyBracesOptions.InitList = true;
1900+
Style.SpacesInParensOptions.InEmptyParentheses = false;
1901+
Style.SpacesInParensOptions.Other = false;
18681902
return Style;
18691903
}
18701904

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4337,12 +4337,24 @@ 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) &&
4340+
// Other braces for records are handled in tryMergeSimpleBlock on
4341+
// UnwrappedLineFormatter.cpp.
4342+
if (Style.SpaceInEmptyBraces == FormatStyle::SIEBO_Custom &&
4343+
Left.is(tok::l_brace) && Right.is(tok::r_brace) &&
43414344
Right.MatchingParen == &Left && Line.Children.empty()) {
4342-
return Style.SpaceInEmptyBlock;
4345+
if (Left.is(BK_BracedInit) && Right.is(BK_BracedInit))
4346+
return Style.SpaceInEmptyBracesOptions.InitList;
4347+
if (Left.is(TT_EnumLBrace) && Right.is(TT_EnumRBrace)) {
4348+
return Style.SpaceInEmptyBracesOptions.Record ||
4349+
Style.SpaceInEmptyBracesOptions.Block;
4350+
}
4351+
if (Left.is(BK_Block))
4352+
return Style.SpaceInEmptyBracesOptions.Block;
43434353
}
43444354
if ((Left.is(tok::l_paren) && Right.is(tok::r_paren)) ||
4345-
(Left.is(tok::l_brace) && Left.isNot(BK_Block) &&
4355+
((Style.SpaceInEmptyBraces == FormatStyle::SIEBO_Never ||
4356+
Style.SpaceInEmptyBracesOptions.InitList) &&
4357+
Left.is(tok::l_brace) && Left.isNot(BK_Block) &&
43464358
Right.is(tok::r_brace) && Right.isNot(BK_Block))) {
43474359
return Style.SpacesInParensOptions.InEmptyParentheses;
43484360
}

clang/lib/Format/UnwrappedLineFormatter.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -823,8 +823,19 @@ class LineJoiner {
823823

824824
if (ShouldMerge()) {
825825
// We merge empty blocks even if the line exceeds the column limit.
826+
bool braceRequireSpace = false;
827+
if (Style.SpaceInEmptyBraces == FormatStyle::SIEBO_Custom) {
828+
if (Style.SpaceInEmptyBracesOptions.Record) {
829+
braceRequireSpace |= Line.Last->isOneOf(
830+
TT_StructLBrace, TT_UnionLBrace, TT_ClassLBrace);
831+
}
832+
if (Style.SpaceInEmptyBracesOptions.Function)
833+
braceRequireSpace |= Line.Last->is(TT_FunctionLBrace);
834+
if (Style.SpaceInEmptyBracesOptions.Block)
835+
braceRequireSpace |= Line.Last->is(BK_Block);
836+
}
826837
Tok->SpacesRequiredBefore =
827-
(Style.SpaceInEmptyBlock || Line.Last->is(tok::comment)) ? 1 : 0;
838+
(braceRequireSpace || Line.Last->is(tok::comment)) ? 1 : 0;
828839
Tok->CanBreakBefore = true;
829840
return 1;
830841
} else if (Limit != 0 && !Line.startsWithNamespace() &&

0 commit comments

Comments
 (0)