[clang] [clang-format] add an option to insert a space only for non-code block empty braces, not for empty parentheses (PR #93634)
Kohei Asano via cfe-commits
cfe-commits at lists.llvm.org
Sun Jun 2 19:02:19 PDT 2024
https://github.com/khei4 updated https://github.com/llvm/llvm-project/pull/93634
>From 5d409bcd0966a7581effdf1488c2f4cfa32aebc6 Mon Sep 17 00:00:00 2001
From: Kohei Asano <Kohei.Asano at sony.com>
Date: Mon, 3 Jun 2024 09:15:44 +0900
Subject: [PATCH] [clang-format] add an option to insert a space only for empty
braces
---
clang/docs/ClangFormatStyleOptions.rst | 78 +++++++++++++++++++-
clang/include/clang/Format/Format.h | 82 +++++++++++++++++++--
clang/lib/Format/Format.cpp | 36 ++++++++-
clang/lib/Format/TokenAnnotator.cpp | 12 ++-
clang/lib/Format/UnwrappedLineFormatter.cpp | 6 +-
clang/unittests/Format/ConfigParseTest.cpp | 9 ++-
clang/unittests/Format/FormatTest.cpp | 42 ++++++++++-
7 files changed, 246 insertions(+), 19 deletions(-)
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 6d092219877f9..bf0088203dd54 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -6028,12 +6028,84 @@ the configuration (without a prefix: ``Auto``).
**SpaceInEmptyBlock** (``Boolean``) :versionbadge:`clang-format 10` :ref:`¶ <SpaceInEmptyBlock>`
If ``true``, spaces will be inserted into ``{}``.
+ This option is **deprecated**. The previous behavior is preserved by using
+ ``SpaceInEmptyBraces`` with ``Custom`` and by setting Record
+ ``SpaceInEmptyBracesOptions`` to ``true``.
+
+.. _SpaceInEmptyBlock:
+
+**SpaceInEmptyBlock** (``Boolean``) :versionbadge:`clang-format 10` :ref:`¶ <SpaceInEmptyBlock>`
+ If ``true``, spaces will be inserted into ``{}`` for record declarations
+ and blocks. This option is **deprecated**. The previous behavior is
+ preserved by using ``SpaceInEmptyBraces`` with ``Custom`` and by setting
+ ``Record`` on ``SpaceInEmptyBracesOptions`` to ``true``.
+
+.. _SpaceInEmptyBraces:
+
+**SpaceInEmptyBraces** (``SpaceInEmptyBracesStyle``) :versionbadge:`clang-format 19` :ref:`¶ <SpaceInEmptyBraces>`
+ Defines in which cases spaces will be inserted in empty braces.
+
+ Possible values:
+
+ * ``SIEBO_Never`` (in configuration: ``Never``)
+ Never put a space in empty braces.
+
+ .. code-block:: c++
+
+ T x{};
+ while (true) {}
+ struct Unit {};
+
+ * ``SIEBO_Custom`` (in configuration: ``Custom``)
+ Configure each individual space in empty braces in
+ `SpacesInEmptyBracesOptions`.
+
+
+
+.. _SpaceInEmptyBracesOptions:
+
+**SpaceInEmptyBracesOptions** (``SpaceInEmptyBracesCustom``) :versionbadge:`clang-format 19` :ref:`¶ <SpaceInEmptyBracesOptions>`
+ Control of individual spaces in empty braces.
+
+ If ``SpaceInEmptyBraces`` is set to ``Custom``, use this to specify
+ how each individual space in empty braces case should be handled.
+ Otherwise, this is ignored.
+
+ .. code-block:: yaml
+
+ # Example of usage:
+ SpaceInEmptyBraces: Custom
+ SpaceInEmptyBracesOptions:
+ Block: true
+ Record: true
+
+ Nested configuration flags:
+
+ Precise control over the spacing in empty braces.
.. code-block:: c++
- true: false:
- void f() { } vs. void f() {}
- while (true) { } while (true) {}
+ # Should be declared this way:
+ SpaceInEmptyBraces: Custom
+ SpaceInEmptyBracesOptions:
+ Block: true
+ Record: true
+
+ * ``bool Block`` Put a space in empty braces of code blocks and record declarations.
+
+ .. code-block:: c++
+
+ true: false:
+ int f() { } vs. int f() {}
+ struct Unit {}; struct Unit {};
+
+ * ``bool InitList`` Put a space in empty braces of initializer list.
+
+ .. code-block:: c++
+
+ true: false:
+ T x{ }; vs. T x{};
+
.. _SpaceInEmptyParentheses:
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 274b45d1bc586..b63ddd7e2b92b 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -4487,13 +4487,11 @@ struct FormatStyle {
bool SpaceBeforeRangeBasedForLoopColon;
/// If ``true``, spaces will be inserted into ``{}``.
- /// \code
- /// true: false:
- /// void f() { } vs. void f() {}
- /// while (true) { } while (true) {}
- /// \endcode
+ /// This option is **deprecated**. The previous behavior is preserved by using
+ /// ``SpaceInEmptyBraces`` with ``Custom`` and by setting Record
+ /// ``SpaceInEmptyBracesOptions`` to ``true``.
/// \version 10
- bool SpaceInEmptyBlock;
+ // bool SpaceInEmptyBlock;
/// If ``true``, spaces may be inserted into ``()``.
/// This option is **deprecated**. See ``InEmptyParentheses`` of
@@ -4715,6 +4713,75 @@ struct FormatStyle {
/// \version 17
SpacesInParensCustom SpacesInParensOptions;
+ /// Different ways to put a space in empty braces.
+ enum SpaceInEmptyBracesStyle : int8_t {
+ /// Never put a space in empty braces.
+ /// \code
+ /// T x{};
+ /// while (true) {}
+ /// struct Unit {};
+ /// \endcode
+ SIEBO_Never,
+ /// Configure each individual space in empty braces in
+ /// `SpacesInEmptyBracesOptions`.
+ SIEBO_Custom,
+ };
+
+ /// Defines in which cases spaces will be inserted in empty braces.
+ /// \version 19
+ SpaceInEmptyBracesStyle SpaceInEmptyBraces;
+
+ /// Precise control over the spacing in empty braces.
+ /// \code
+ /// # Should be declared this way:
+ /// SpaceInEmptyBraces: Custom
+ /// SpaceInEmptyBracesOptions:
+ /// Block: true
+ /// Record: true
+ /// \endcode
+ struct SpaceInEmptyBracesCustom {
+ /// Put a space in empty braces of code blocks and record declarations.
+ /// \code
+ /// true: false:
+ /// int f() { } vs. int f() {}
+ /// struct Unit {}; struct Unit {};
+ /// \endcode
+ bool Block;
+ /// Put a space in empty braces of initializer list.
+ /// \code
+ /// true: false:
+ /// T x{ }; vs. T x{};
+ /// \endcode
+ bool InitList;
+
+ SpaceInEmptyBracesCustom() : Block(false), InitList(false) {}
+
+ SpaceInEmptyBracesCustom(bool Block, bool InitList)
+ : Block(Block), InitList(InitList) {}
+
+ bool operator==(const SpaceInEmptyBracesCustom &R) const {
+ return Block == R.Block && InitList == R.InitList;
+ }
+ bool operator!=(const SpaceInEmptyBracesCustom &R) const {
+ return !(*this == R);
+ }
+ };
+
+ /// Control of individual spaces in empty braces.
+ ///
+ /// If ``SpaceInEmptyBraces`` is set to ``Custom``, use this to specify
+ /// how each individual space in empty braces case should be handled.
+ /// Otherwise, this is ignored.
+ /// \code{.yaml}
+ /// # Example of usage:
+ /// SpaceInEmptyBraces: Custom
+ /// SpaceInEmptyBracesOptions:
+ /// Block: true
+ /// Record: true
+ /// \endcode
+ /// \version 19
+ SpaceInEmptyBracesCustom SpaceInEmptyBracesOptions;
+
/// If ``true``, spaces will be inserted after ``[`` and before ``]``.
/// Lambdas without arguments or unspecified size array declarations will not
/// be affected.
@@ -5088,7 +5155,8 @@ struct FormatStyle {
SpaceBeforeRangeBasedForLoopColon ==
R.SpaceBeforeRangeBasedForLoopColon &&
SpaceBeforeSquareBrackets == R.SpaceBeforeSquareBrackets &&
- SpaceInEmptyBlock == R.SpaceInEmptyBlock &&
+ SpaceInEmptyBraces == R.SpaceInEmptyBraces &&
+ SpaceInEmptyBracesOptions == R.SpaceInEmptyBracesOptions &&
SpacesBeforeTrailingComments == R.SpacesBeforeTrailingComments &&
SpacesInAngles == R.SpacesInAngles &&
SpacesInContainerLiterals == R.SpacesInContainerLiterals &&
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 9cba0c2614eef..8c6f8c440d73d 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -718,6 +718,21 @@ template <> struct MappingTraits<FormatStyle::SpacesInLineComment> {
}
};
+template <> struct MappingTraits<FormatStyle::SpaceInEmptyBracesCustom> {
+ static void mapping(IO &IO, FormatStyle::SpaceInEmptyBracesCustom &Space) {
+ IO.mapOptional("Block", Space.Block);
+ IO.mapOptional("InitList", Space.InitList);
+ }
+};
+
+template <>
+struct ScalarEnumerationTraits<FormatStyle::SpaceInEmptyBracesStyle> {
+ static void enumeration(IO &IO, FormatStyle::SpaceInEmptyBracesStyle &Value) {
+ IO.enumCase(Value, "Never", FormatStyle::SIEBO_Never);
+ IO.enumCase(Value, "Custom", FormatStyle::SIEBO_Custom);
+ }
+};
+
template <> struct MappingTraits<FormatStyle::SpacesInParensCustom> {
static void mapping(IO &IO, FormatStyle::SpacesInParensCustom &Spaces) {
IO.mapOptional("InCStyleCasts", Spaces.InCStyleCasts);
@@ -849,6 +864,7 @@ template <> struct MappingTraits<FormatStyle> {
bool UseCRLF = false;
bool SpaceInEmptyParentheses = false;
+ bool SpaceInEmptyBlock = false;
bool SpacesInConditionalStatement = false;
bool SpacesInCStyleCastParentheses = false;
bool SpacesInParentheses = false;
@@ -875,6 +891,7 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("SpaceAfterControlStatementKeyword",
Style.SpaceBeforeParens);
IO.mapOptional("SpaceInEmptyParentheses", SpaceInEmptyParentheses);
+ IO.mapOptional("SpaceInEmptyBlock", SpaceInEmptyBlock);
IO.mapOptional("SpacesInConditionalStatement",
SpacesInConditionalStatement);
IO.mapOptional("SpacesInCStyleCastParentheses",
@@ -1091,7 +1108,6 @@ template <> struct MappingTraits<FormatStyle> {
Style.SpaceBeforeRangeBasedForLoopColon);
IO.mapOptional("SpaceBeforeSquareBrackets",
Style.SpaceBeforeSquareBrackets);
- IO.mapOptional("SpaceInEmptyBlock", Style.SpaceInEmptyBlock);
IO.mapOptional("SpacesBeforeTrailingComments",
Style.SpacesBeforeTrailingComments);
IO.mapOptional("SpacesInAngles", Style.SpacesInAngles);
@@ -1099,6 +1115,9 @@ template <> struct MappingTraits<FormatStyle> {
Style.SpacesInContainerLiterals);
IO.mapOptional("SpacesInLineCommentPrefix",
Style.SpacesInLineCommentPrefix);
+ IO.mapOptional("SpaceInEmptyBraces", Style.SpaceInEmptyBraces);
+ IO.mapOptional("SpaceInEmptyBracesOptions",
+ Style.SpaceInEmptyBracesOptions);
IO.mapOptional("SpacesInParens", Style.SpacesInParens);
IO.mapOptional("SpacesInParensOptions", Style.SpacesInParensOptions);
IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets);
@@ -1193,6 +1212,13 @@ template <> struct MappingTraits<FormatStyle> {
}
Style.SpacesInParens = FormatStyle::SIPO_Custom;
}
+
+ if (Style.SpaceInEmptyBraces != FormatStyle::SIEBO_Custom &&
+ SpaceInEmptyBlock) {
+ Style.SpaceInEmptyBraces = FormatStyle::SIEBO_Custom;
+ Style.SpaceInEmptyBracesOptions.Block = true;
+ Style.SpaceInEmptyBracesOptions.InitList = false;
+ }
}
};
@@ -1562,7 +1588,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.SpaceBeforeParensOptions.AfterIfMacros = true;
LLVMStyle.SpaceBeforeRangeBasedForLoopColon = true;
LLVMStyle.SpaceBeforeSquareBrackets = false;
- LLVMStyle.SpaceInEmptyBlock = false;
+ LLVMStyle.SpaceInEmptyBraces = FormatStyle::SIEBO_Never;
LLVMStyle.SpacesBeforeTrailingComments = 1;
LLVMStyle.SpacesInAngles = FormatStyle::SIAS_Never;
LLVMStyle.SpacesInContainerLiterals = true;
@@ -1863,7 +1889,11 @@ FormatStyle getWebKitStyle() {
Style.ObjCSpaceAfterProperty = true;
Style.PointerAlignment = FormatStyle::PAS_Left;
Style.SpaceBeforeCpp11BracedList = true;
- Style.SpaceInEmptyBlock = true;
+ Style.SpaceInEmptyBraces = FormatStyle::SIEBO_Custom;
+ Style.SpaceInEmptyBracesOptions.Block = true;
+ Style.SpaceInEmptyBracesOptions.InitList = true;
+ Style.SpacesInParensOptions.InEmptyParentheses = false;
+ Style.SpacesInParensOptions.Other = false;
return Style;
}
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 7c4c76a91f2c5..c94a8ad2bb571 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -4337,13 +4337,21 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
return Left.is(tok::hash);
if (Left.isOneOf(tok::hashhash, tok::hash))
return Right.is(tok::hash);
+ // FIXME: separate function and other block?
if (Left.is(BK_Block) && Right.is(tok::r_brace) &&
Right.MatchingParen == &Left && Line.Children.empty()) {
- return Style.SpaceInEmptyBlock;
+ return Style.SpaceInEmptyBracesOptions.Block;
}
- if ((Left.is(tok::l_paren) && Right.is(tok::r_paren)) ||
+ if (Style.SpaceInEmptyBracesOptions.InitList &&
(Left.is(tok::l_brace) && Left.isNot(BK_Block) &&
Right.is(tok::r_brace) && Right.isNot(BK_Block))) {
+ return Style.SpaceInEmptyBracesOptions.InitList;
+ }
+ if ((Left.is(tok::l_paren) && Right.is(tok::r_paren)) ||
+ ((Style.SpaceInEmptyBraces == FormatStyle::SIEBO_Never ||
+ Style.SpaceInEmptyBracesOptions.InitList) &&
+ Left.is(tok::l_brace) && Left.isNot(BK_Block) &&
+ Right.is(tok::r_brace) && Right.isNot(BK_Block))) {
return Style.SpacesInParensOptions.InEmptyParentheses;
}
if (Style.SpacesInParensOptions.InConditionalStatements) {
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 4d53361aaf333..e1a17f29b627d 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -824,7 +824,11 @@ class LineJoiner {
if (ShouldMerge()) {
// We merge empty blocks even if the line exceeds the column limit.
Tok->SpacesRequiredBefore =
- (Style.SpaceInEmptyBlock || Line.Last->is(tok::comment)) ? 1 : 0;
+ ((Style.SpaceInEmptyBraces == FormatStyle::SIEBO_Custom &&
+ Style.SpaceInEmptyBracesOptions.Block) ||
+ Line.Last->is(tok::comment))
+ ? 1
+ : 0;
Tok->CanBreakBefore = true;
return 1;
} else if (Limit != 0 && !Line.startsWithNamespace() &&
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index 82e72f08ffb5e..44d418b7ed575 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -187,7 +187,6 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
CHECK_PARSE_BOOL(RemoveSemicolon);
CHECK_PARSE_BOOL(SkipMacroDefinitionBody);
CHECK_PARSE_BOOL(SpacesInSquareBrackets);
- CHECK_PARSE_BOOL(SpaceInEmptyBlock);
CHECK_PARSE_BOOL(SpacesInContainerLiterals);
CHECK_PARSE_BOOL(SpaceAfterCStyleCast);
CHECK_PARSE_BOOL(SpaceAfterTemplateKeyword);
@@ -235,6 +234,8 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, AfterOverloadedOperator);
CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, AfterPlacementOperator);
CHECK_PARSE_NESTED_BOOL(SpaceBeforeParensOptions, BeforeNonEmptyParentheses);
+ CHECK_PARSE_NESTED_BOOL(SpaceInEmptyBracesOptions, Block);
+ CHECK_PARSE_NESTED_BOOL(SpaceInEmptyBracesOptions, InitList);
CHECK_PARSE_NESTED_BOOL(SpacesInParensOptions, InCStyleCasts);
CHECK_PARSE_NESTED_BOOL(SpacesInParensOptions, InConditionalStatements);
CHECK_PARSE_NESTED_BOOL(SpacesInParensOptions, InEmptyParentheses);
@@ -636,6 +637,12 @@ TEST(ConfigParseTest, ParsesConfiguration) {
Style.SpacesInParens = FormatStyle::SIPO_Never;
Style.SpacesInParensOptions = {};
+ // For backward compatibility
+ Style.SpaceInEmptyBraces = FormatStyle::SIEBO_Never;
+ Style.SpaceInEmptyBracesOptions = {};
+ CHECK_PARSE("SpaceInEmptyBlock: true", SpaceInEmptyBracesOptions,
+ FormatStyle::SpaceInEmptyBracesCustom(true, false));
+
Style.ColumnLimit = 123;
FormatStyle BaseStyle = getLLVMStyle();
CHECK_PARSE("BasedOnStyle: LLVM", ColumnLimit, BaseStyle.ColumnLimit);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 2f0c0f0266774..6961d863a3007 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -6961,7 +6961,8 @@ TEST_F(FormatTest, PutEmptyBlocksIntoOneLine) {
verifyFormat("enum E {};");
verifyFormat("enum E {}");
FormatStyle Style = getLLVMStyle();
- Style.SpaceInEmptyBlock = true;
+ Style.SpaceInEmptyBraces = FormatStyle::SIEBO_Custom;
+ Style.SpaceInEmptyBracesOptions.Block = true;
verifyFormat("void f() { }", "void f() {}", Style);
Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Empty;
verifyFormat("{ }", Style);
@@ -6989,7 +6990,8 @@ TEST_F(FormatTest, PutEmptyBlocksIntoOneLine) {
Style);
Style = getLLVMStyle(FormatStyle::LK_CSharp);
- Style.SpaceInEmptyBlock = true;
+ Style.SpaceInEmptyBraces = FormatStyle::SIEBO_Custom;
+ Style.SpaceInEmptyBracesOptions.Block = true;
verifyFormat("Event += () => { };", Style);
}
@@ -14029,6 +14031,42 @@ TEST_F(FormatTest, LayoutCxx11BraceInitializers) {
verifyFormat("vector< int > x{ };", SpaceBetweenBraces);
}
+TEST_F(FormatTest, EmptyBracesTest) {
+ FormatStyle SpaceInEmptyBraces = getLLVMStyle();
+ SpaceInEmptyBraces.SpaceInEmptyBraces = FormatStyle::SIEBO_Never;
+ verifyFormat("void f() {}\n"
+ "struct Unit {};\n"
+ "int x{};\n",
+ SpaceInEmptyBraces);
+
+ SpaceInEmptyBraces.SpaceInEmptyBraces = FormatStyle::SIEBO_Custom;
+ SpaceInEmptyBraces.SpaceInEmptyBracesOptions.Block = true;
+ SpaceInEmptyBraces.SpaceInEmptyBracesOptions.InitList = false;
+ verifyFormat("void f() { }\n"
+ "struct Unit { };\n"
+ "int x{};\n",
+ SpaceInEmptyBraces);
+
+ SpaceInEmptyBraces.SpaceInEmptyBraces = FormatStyle::SIEBO_Custom;
+ SpaceInEmptyBraces.SpaceInEmptyBracesOptions.Block = false;
+ SpaceInEmptyBraces.SpaceInEmptyBracesOptions.InitList = true;
+ verifyFormat("void f() {}\n"
+ "struct Unit {};\n"
+ "int x{ };\n",
+ SpaceInEmptyBraces);
+
+ // SpacesInParensOptions.InEmptyParentheses can be overwritten.
+ SpaceInEmptyBraces.SpaceInEmptyBraces = FormatStyle::SIEBO_Custom;
+ SpaceInEmptyBraces.SpaceInEmptyBracesOptions.Block = false;
+ SpaceInEmptyBraces.SpaceInEmptyBracesOptions.InitList = false;
+ SpaceInEmptyBraces.SpacesInParens = FormatStyle::SIPO_Custom;
+ SpaceInEmptyBraces.SpacesInParensOptions.InEmptyParentheses = true;
+ verifyFormat("void f( ) {}\n"
+ "struct Unit {};\n"
+ "int x{};\n",
+ SpaceInEmptyBraces);
+}
+
TEST_F(FormatTest, FormatsBracedListsInColumnLayout) {
verifyFormat("vector<int> x = {1, 22, 333, 4444, 55555, 666666, 7777777,\n"
" 1, 22, 333, 4444, 55555, 666666, 7777777,\n"
More information about the cfe-commits
mailing list