[clang] [clang-format] Add option to omit wrapping for empty records (PR #151970)
Tomáš Slanina via cfe-commits
cfe-commits at lists.llvm.org
Sun Aug 17 09:36:27 PDT 2025
https://github.com/itzexpoexpo updated https://github.com/llvm/llvm-project/pull/151970
>From 2c26e66e16bf2c42019e8a5bce421f106fcf978d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoexpo at gmail.com>
Date: Mon, 4 Aug 2025 15:19:53 +0200
Subject: [PATCH 01/10] [clang-format] Add option to omit wrapping for empty
records
Currently, clang-format does not allow empty records to be formatted
on a single line if the corresponding `BraceWrapping.After*` option
is set to true.
This results in unnecessarily wrapped code:
struct foo
{
int i;
};
struct bar
{
};
This patch adds the `BraceWrapping.WrapEmptyRecord` option, which
allows `class`, `struct`, and `union` declarations with empty bodies
to be formatted as one-liners, even when `AfterRecord: true`.
As such, the following becomes possible:
struct foo
{
int i;
};
struct bar {};
---
clang/include/clang/Format/Format.h | 28 ++++++++++++++++++++++
clang/lib/Format/Format.cpp | 13 +++++++++-
clang/lib/Format/TokenAnnotator.cpp | 9 +++----
clang/lib/Format/UnwrappedLineParser.cpp | 20 ++++++++++------
clang/unittests/Format/FormatTest.cpp | 30 ++++++++++++++++++++++++
5 files changed, 88 insertions(+), 12 deletions(-)
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 31582a40de866..cc79dcb7b53ec 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -1355,6 +1355,32 @@ struct FormatStyle {
BWACS_Always
};
+ enum BraceWrapEmptyRecordStyle : int8_t {
+ /// Use default wrapping rules for records
+ /// (AfterClass,AfterStruct,AfterUnion)
+ /// \code
+ /// class foo
+ /// {
+ /// int foo;
+ /// };
+ ///
+ /// class foo
+ /// {
+ /// };
+ /// \endcode
+ BWER_Default,
+ /// Override wrapping for empty records
+ /// \code
+ /// class foo
+ /// {
+ /// int foo;
+ /// };
+ ///
+ /// class foo {};
+ /// \endcode
+ BWER_Never
+ };
+
/// Precise control over the wrapping of braces.
/// \code
/// # Should be declared this way:
@@ -1585,6 +1611,8 @@ struct FormatStyle {
/// \endcode
///
bool SplitEmptyNamespace;
+ /// Wrap empty record (``class``/``struct``/``union``).
+ BraceWrapEmptyRecordStyle WrapEmptyRecord;
};
/// Control of individual brace wrapping cases.
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 063780721423f..0d72410f00c27 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -200,6 +200,7 @@ template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> {
IO.mapOptional("SplitEmptyFunction", Wrapping.SplitEmptyFunction);
IO.mapOptional("SplitEmptyRecord", Wrapping.SplitEmptyRecord);
IO.mapOptional("SplitEmptyNamespace", Wrapping.SplitEmptyNamespace);
+ IO.mapOptional("WrapEmptyRecord", Wrapping.WrapEmptyRecord);
}
};
@@ -232,6 +233,15 @@ struct ScalarEnumerationTraits<
}
};
+template <>
+struct ScalarEnumerationTraits<FormatStyle::BraceWrapEmptyRecordStyle> {
+ static void enumeration(IO &IO,
+ FormatStyle::BraceWrapEmptyRecordStyle &Value) {
+ IO.enumCase(Value, "Default", FormatStyle::BWER_Default);
+ IO.enumCase(Value, "Never", FormatStyle::BWER_Never);
+ }
+};
+
template <>
struct ScalarEnumerationTraits<
FormatStyle::BreakBeforeConceptDeclarationsStyle> {
@@ -1392,7 +1402,8 @@ static void expandPresetsBraceWrapping(FormatStyle &Expanded) {
/*IndentBraces=*/false,
/*SplitEmptyFunction=*/true,
/*SplitEmptyRecord=*/true,
- /*SplitEmptyNamespace=*/true};
+ /*SplitEmptyNamespace=*/true,
+ /*WrapEmptyRecord=*/FormatStyle::BWER_Default};
switch (Expanded.BreakBeforeBraces) {
case FormatStyle::BS_Linux:
Expanded.BraceWrapping.AfterClass = true;
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 4801d27b1395a..22132f6d2fd3b 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -5935,10 +5935,11 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
// Don't attempt to interpret struct return types as structs.
if (Right.isNot(TT_FunctionLBrace)) {
- return (Line.startsWith(tok::kw_class) &&
- Style.BraceWrapping.AfterClass) ||
- (Line.startsWith(tok::kw_struct) &&
- Style.BraceWrapping.AfterStruct);
+ return ((Line.startsWith(tok::kw_class) &&
+ Style.BraceWrapping.AfterClass) ||
+ (Line.startsWith(tok::kw_struct) &&
+ Style.BraceWrapping.AfterStruct)) &&
+ Style.BraceWrapping.WrapEmptyRecord == FormatStyle::BWER_Default;
}
}
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index 91b8fdc8a3c38..e3efb0804d988 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -952,20 +952,26 @@ static bool isIIFE(const UnwrappedLine &Line,
}
static bool ShouldBreakBeforeBrace(const FormatStyle &Style,
- const FormatToken &InitialToken) {
+ const FormatToken &InitialToken,
+ const FormatToken &NextToken) {
tok::TokenKind Kind = InitialToken.Tok.getKind();
if (InitialToken.is(TT_NamespaceMacro))
Kind = tok::kw_namespace;
+ bool IsEmptyBlock = NextToken.is(tok::r_brace);
+ bool WrapRecordAllowed =
+ !(IsEmptyBlock &&
+ Style.BraceWrapping.WrapEmptyRecord == FormatStyle::BWER_Never);
+
switch (Kind) {
case tok::kw_namespace:
return Style.BraceWrapping.AfterNamespace;
case tok::kw_class:
- return Style.BraceWrapping.AfterClass;
+ return Style.BraceWrapping.AfterClass && WrapRecordAllowed;
case tok::kw_union:
- return Style.BraceWrapping.AfterUnion;
+ return Style.BraceWrapping.AfterUnion && WrapRecordAllowed;
case tok::kw_struct:
- return Style.BraceWrapping.AfterStruct;
+ return Style.BraceWrapping.AfterStruct && WrapRecordAllowed;
case tok::kw_enum:
return Style.BraceWrapping.AfterEnum;
default:
@@ -3191,7 +3197,7 @@ void UnwrappedLineParser::parseNamespace() {
if (FormatTok->is(tok::l_brace)) {
FormatTok->setFinalizedType(TT_NamespaceLBrace);
- if (ShouldBreakBeforeBrace(Style, InitialToken))
+ if (ShouldBreakBeforeBrace(Style, InitialToken, *Tokens->peekNextToken()))
addUnwrappedLine();
unsigned AddLevels =
@@ -3856,7 +3862,7 @@ bool UnwrappedLineParser::parseEnum() {
}
if (!Style.AllowShortEnumsOnASingleLine &&
- ShouldBreakBeforeBrace(Style, InitialToken)) {
+ ShouldBreakBeforeBrace(Style, InitialToken, *Tokens->peekNextToken())) {
addUnwrappedLine();
}
// Parse enum body.
@@ -4151,7 +4157,7 @@ void UnwrappedLineParser::parseRecord(bool ParseAsExpr, bool IsJavaRecord) {
if (ParseAsExpr) {
parseChildBlock();
} else {
- if (ShouldBreakBeforeBrace(Style, InitialToken))
+ if (ShouldBreakBeforeBrace(Style, InitialToken, *Tokens->peekNextToken()))
addUnwrappedLine();
unsigned AddLevels = Style.IndentAccessModifiers ? 2u : 1u;
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 96cc650f52a5d..3a5233674bd0f 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -15615,6 +15615,36 @@ TEST_F(FormatTest, NeverMergeShortRecords) {
Style);
}
+TEST_F(FormatTest, WrapEmptyRecords) {
+ FormatStyle Style = getLLVMStyle();
+
+ Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+ Style.BraceWrapping.AfterStruct = true;
+ Style.BraceWrapping.AfterClass = true;
+ Style.BraceWrapping.AfterUnion = true;
+ Style.BraceWrapping.SplitEmptyRecord = false;
+
+ verifyFormat("class foo\n{\n void bar();\n};", Style);
+ verifyFormat("class foo\n{};", Style);
+
+ verifyFormat("struct foo\n{\n int bar;\n};", Style);
+ verifyFormat("struct foo\n{};", Style);
+
+ verifyFormat("union foo\n{\n int bar;\n};", Style);
+ verifyFormat("union foo\n{};", Style);
+
+ Style.BraceWrapping.WrapEmptyRecord = FormatStyle::BWER_Never;
+
+ verifyFormat("class foo\n{\n void bar();\n};", Style);
+ verifyFormat("class foo {};", Style);
+
+ verifyFormat("struct foo\n{\n int bar;\n};", Style);
+ verifyFormat("struct foo {};", Style);
+
+ verifyFormat("union foo\n{\n int bar;\n};", Style);
+ verifyFormat("union foo {};", Style);
+}
+
TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) {
// Elaborate type variable declarations.
verifyFormat("struct foo a = {bar};\nint n;");
>From ce10b36f779b54b07cd90dd4023c949166380327 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoexpo at gmail.com>
Date: Mon, 4 Aug 2025 16:11:48 +0200
Subject: [PATCH 02/10] Fix missing style option docs
---
clang/docs/ClangFormatStyleOptions.rst | 30 ++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 02986a94a656c..f3ee029b6c2bf 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -2579,6 +2579,36 @@ the configuration (without a prefix: ``Auto``).
{} {
}
+ * ``BraceWrapEmptyRecordStyle WrapEmptyRecord``
+ Wrap empty record (``class``/``struct``/``union``).
+
+ Possible values:
+
+ * ``BWËR_Never`` (in configuration: ``Never``)
+ Never wrap braces of empty records.
+
+ .. code-block:: c++
+
+ class foo
+ {
+ int foo;
+ };
+
+ class foo{};
+
+ * ``BWER_Default`` (in configuration: ``MultiLine``)
+ Use default wrapping rules for records. (``AfterClass``, ``AfterStruct``, ``AfterUnion``)
+
+ .. code-block:: c++
+
+ class foo
+ {
+ int foo;
+ };
+
+ class foo
+ {
+ };
.. _BracedInitializerIndentWidth:
>From 38318671aafe724c2c1208468585b884e614edfb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoexpo at gmail.com>
Date: Mon, 11 Aug 2025 16:23:17 +0200
Subject: [PATCH 03/10] !fixup [clang-format] Add option to omit wrapping for
empty records
---
clang/docs/ClangFormatStyleOptions.rst | 22 ++++++++++---------
clang/include/clang/Format/Format.h | 28 ++++++++++++------------
clang/lib/Format/UnwrappedLineParser.cpp | 4 ++--
clang/unittests/Format/FormatTest.cpp | 24 +++++++++++++++-----
4 files changed, 46 insertions(+), 32 deletions(-)
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index f3ee029b6c2bf..8c3b0ad707851 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -2584,8 +2584,9 @@ the configuration (without a prefix: ``Auto``).
Possible values:
- * ``BWËR_Never`` (in configuration: ``Never``)
- Never wrap braces of empty records.
+ * ``BWER_Default`` (in configuration: ``Default``)
+ Use default wrapping rules for records
+ (``AfterClass``,``AfterStruct``,``AfterUnion``).
.. code-block:: c++
@@ -2593,11 +2594,12 @@ the configuration (without a prefix: ``Auto``).
{
int foo;
};
-
- class foo{};
- * ``BWER_Default`` (in configuration: ``MultiLine``)
- Use default wrapping rules for records. (``AfterClass``, ``AfterStruct``, ``AfterUnion``)
+ class foo
+ {};
+
+ * ``BWER_Never`` (in configuration: ``Never``)
+ Override wrapping for empty records.
.. code-block:: c++
@@ -2605,10 +2607,10 @@ the configuration (without a prefix: ``Auto``).
{
int foo;
};
-
- class foo
- {
- };
+
+ class foo {};
+
+
.. _BracedInitializerIndentWidth:
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index cc79dcb7b53ec..5d7d0fd9a48d6 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -1355,28 +1355,28 @@ struct FormatStyle {
BWACS_Always
};
+ /// Override wrapping of empty records.
enum BraceWrapEmptyRecordStyle : int8_t {
/// Use default wrapping rules for records
- /// (AfterClass,AfterStruct,AfterUnion)
+ /// (``AfterClass``,``AfterStruct``,``AfterUnion``).
/// \code
- /// class foo
- /// {
- /// int foo;
- /// };
+ /// class foo
+ /// {
+ /// int foo;
+ /// };
///
- /// class foo
- /// {
- /// };
+ /// class foo
+ /// {};
/// \endcode
BWER_Default,
- /// Override wrapping for empty records
+ /// Override wrapping for empty records.
/// \code
- /// class foo
- /// {
- /// int foo;
- /// };
+ /// class foo
+ /// {
+ /// int foo;
+ /// };
///
- /// class foo {};
+ /// class foo {};
/// \endcode
BWER_Never
};
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index e3efb0804d988..c6bb0103b2081 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -960,8 +960,8 @@ static bool ShouldBreakBeforeBrace(const FormatStyle &Style,
bool IsEmptyBlock = NextToken.is(tok::r_brace);
bool WrapRecordAllowed =
- !(IsEmptyBlock &&
- Style.BraceWrapping.WrapEmptyRecord == FormatStyle::BWER_Never);
+ !IsEmptyBlock ||
+ Style.BraceWrapping.WrapEmptyRecord != FormatStyle::BWER_Never;
switch (Kind) {
case tok::kw_namespace:
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 3a5233674bd0f..c8dff7f2710da 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -15624,24 +15624,36 @@ TEST_F(FormatTest, WrapEmptyRecords) {
Style.BraceWrapping.AfterUnion = true;
Style.BraceWrapping.SplitEmptyRecord = false;
- verifyFormat("class foo\n{\n void bar();\n};", Style);
+ verifyFormat("class foo\n{\n"
+ " void bar();\n"
+ "};", Style);
verifyFormat("class foo\n{};", Style);
- verifyFormat("struct foo\n{\n int bar;\n};", Style);
+ verifyFormat("struct foo\n{\n"
+ " int bar;\n"
+ "};", Style);
verifyFormat("struct foo\n{};", Style);
- verifyFormat("union foo\n{\n int bar;\n};", Style);
+ verifyFormat("union foo\n{\n"
+ " int bar;\n"
+ "};", Style);
verifyFormat("union foo\n{};", Style);
Style.BraceWrapping.WrapEmptyRecord = FormatStyle::BWER_Never;
- verifyFormat("class foo\n{\n void bar();\n};", Style);
+ verifyFormat("class foo\n{\n"
+ " void bar();\n"
+ "};", Style);
verifyFormat("class foo {};", Style);
- verifyFormat("struct foo\n{\n int bar;\n};", Style);
+ verifyFormat("struct foo\n{\n"
+ " int bar;\n"
+ "};", Style);
verifyFormat("struct foo {};", Style);
- verifyFormat("union foo\n{\n int bar;\n};", Style);
+ verifyFormat("union foo\n{\n"
+ " int bar;\n"
+ "};", Style);
verifyFormat("union foo {};", Style);
}
>From 1678747f9915164a56c3076172b8c8f9cf86948e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoexpo at gmail.com>
Date: Mon, 11 Aug 2025 18:06:50 +0200
Subject: [PATCH 04/10] Fix formatting
---
clang/lib/Format/UnwrappedLineParser.cpp | 2 +-
clang/unittests/Format/FormatTest.cpp | 30 ++++++++++++++----------
2 files changed, 19 insertions(+), 13 deletions(-)
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index c6bb0103b2081..5d17bef78e9d2 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -961,7 +961,7 @@ static bool ShouldBreakBeforeBrace(const FormatStyle &Style,
bool IsEmptyBlock = NextToken.is(tok::r_brace);
bool WrapRecordAllowed =
!IsEmptyBlock ||
- Style.BraceWrapping.WrapEmptyRecord != FormatStyle::BWER_Never;
+ Style.BraceWrapping.WrapEmptyRecord != FormatStyle::BWER_Never;
switch (Kind) {
case tok::kw_namespace:
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index c8dff7f2710da..5ac92a45927ce 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -15625,35 +15625,41 @@ TEST_F(FormatTest, WrapEmptyRecords) {
Style.BraceWrapping.SplitEmptyRecord = false;
verifyFormat("class foo\n{\n"
- " void bar();\n"
- "};", Style);
+ " void bar();\n"
+ "};",
+ Style);
verifyFormat("class foo\n{};", Style);
verifyFormat("struct foo\n{\n"
- " int bar;\n"
- "};", Style);
+ " int bar;\n"
+ "};",
+ Style);
verifyFormat("struct foo\n{};", Style);
verifyFormat("union foo\n{\n"
- " int bar;\n"
- "};", Style);
+ " int bar;\n"
+ "};",
+ Style);
verifyFormat("union foo\n{};", Style);
Style.BraceWrapping.WrapEmptyRecord = FormatStyle::BWER_Never;
verifyFormat("class foo\n{\n"
- " void bar();\n"
- "};", Style);
+ " void bar();\n"
+ "};",
+ Style);
verifyFormat("class foo {};", Style);
verifyFormat("struct foo\n{\n"
- " int bar;\n"
- "};", Style);
+ " int bar;\n"
+ "};",
+ Style);
verifyFormat("struct foo {};", Style);
verifyFormat("union foo\n{\n"
- " int bar;\n"
- "};", Style);
+ " int bar;\n"
+ "};",
+ Style);
verifyFormat("union foo {};", Style);
}
>From 19afee66ea5e0b00964641d5b75d6283b98eb413 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoexpo at gmail.com>
Date: Tue, 12 Aug 2025 21:09:08 +0200
Subject: [PATCH 05/10] Deprecate SplitEmptyRecord and replace it with
WrapEmptyRecord
---
clang/docs/ClangFormatStyleOptions.rst | 18 ++++++++---------
clang/docs/tools/dump_format_style.py | 2 +-
clang/include/clang/Format/Format.h | 22 ++++++++++-----------
clang/lib/Format/Format.cpp | 17 +++++++++-------
clang/lib/Format/UnwrappedLineFormatter.cpp | 12 +++++------
clang/unittests/Format/ConfigParseTest.cpp | 1 -
clang/unittests/Format/FormatTest.cpp | 16 +++++++--------
clang/unittests/Format/FormatTestCSharp.cpp | 2 +-
8 files changed, 45 insertions(+), 45 deletions(-)
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 8c3b0ad707851..375393e12691e 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -2555,7 +2555,8 @@ the configuration (without a prefix: ``Auto``).
{} {
}
- * ``bool SplitEmptyRecord`` If ``false``, empty record (e.g. class, struct or union) body
+ * ``bool SplitEmptyRecord`` This option is **deprecated**. See `WrapEmptyRecord`.
+ If ``false``, empty record (e.g. class, struct or union) body
can be put on a single line. This option is used only if the opening
brace of the record has already been wrapped, i.e. the ``AfterClass``
(for classes) brace wrapping mode is set.
@@ -2585,29 +2586,28 @@ the configuration (without a prefix: ``Auto``).
Possible values:
* ``BWER_Default`` (in configuration: ``Default``)
- Use default wrapping rules for records
+ Use default wrapping rules for empty records
(``AfterClass``,``AfterStruct``,``AfterUnion``).
.. code-block:: c++
class foo
{
- int foo;
};
+ * ``BWER_BeforeBrace`` (in configuration: ``BeforeBrace``)
+ Only wrap before brace (equivalent to ``SplitEmptyRecord=false``).
+
+ .. code-block:: c++
+
class foo
{};
* ``BWER_Never`` (in configuration: ``Never``)
- Override wrapping for empty records.
+ Wrap neither before or after the brace.
.. code-block:: c++
- class foo
- {
- int foo;
- };
-
class foo {};
diff --git a/clang/docs/tools/dump_format_style.py b/clang/docs/tools/dump_format_style.py
index f035143f6b3d1..227bf36c58024 100755
--- a/clang/docs/tools/dump_format_style.py
+++ b/clang/docs/tools/dump_format_style.py
@@ -384,7 +384,7 @@ class State:
else:
state = State.InNestedStruct
field_type, field_name = re.match(
- r"([<>:\w(,\s)]+)\s+(\w+);", line
+ r"(?:// )?([<>:\w(,\s)]+)\s+(\w+);", line
).groups()
# if not version:
# self.__warning(f"missing version for {field_name}", line)
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 5d7d0fd9a48d6..22b43a68ed583 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -1357,25 +1357,22 @@ struct FormatStyle {
/// Override wrapping of empty records.
enum BraceWrapEmptyRecordStyle : int8_t {
- /// Use default wrapping rules for records
+ /// Use default wrapping rules for empty records
/// (``AfterClass``,``AfterStruct``,``AfterUnion``).
/// \code
/// class foo
/// {
- /// int foo;
/// };
- ///
- /// class foo
- /// {};
/// \endcode
BWER_Default,
- /// Override wrapping for empty records.
+ /// Only wrap before brace (equivalent to ``SplitEmptyRecord=false``).
/// \code
/// class foo
- /// {
- /// int foo;
- /// };
- ///
+ /// {};
+ /// \endcode
+ BWER_BeforeBrace,
+ /// Wrap neither before or after the brace.
+ /// \code
/// class foo {};
/// \endcode
BWER_Never
@@ -1587,6 +1584,7 @@ struct FormatStyle {
/// \endcode
///
bool SplitEmptyFunction;
+ /// This option is **deprecated**. See `WrapEmptyRecord`.
/// If ``false``, empty record (e.g. class, struct or union) body
/// can be put on a single line. This option is used only if the opening
/// brace of the record has already been wrapped, i.e. the ``AfterClass``
@@ -1597,8 +1595,8 @@ struct FormatStyle {
/// {} {
/// }
/// \endcode
- ///
- bool SplitEmptyRecord;
+ // bool SplitEmptyRecord;
+
/// If ``false``, empty namespace body can be put on a single line.
/// This option is used only if the opening brace of the namespace has
/// already been wrapped, i.e. the ``AfterNamespace`` brace wrapping mode is
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 0d72410f00c27..6f865b66e3aed 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -198,7 +198,7 @@ template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> {
IO.mapOptional("BeforeWhile", Wrapping.BeforeWhile);
IO.mapOptional("IndentBraces", Wrapping.IndentBraces);
IO.mapOptional("SplitEmptyFunction", Wrapping.SplitEmptyFunction);
- IO.mapOptional("SplitEmptyRecord", Wrapping.SplitEmptyRecord);
+ IO.mapOptional("SplitEmptyRecord", Wrapping.WrapEmptyRecord); // For backward compatibility.
IO.mapOptional("SplitEmptyNamespace", Wrapping.SplitEmptyNamespace);
IO.mapOptional("WrapEmptyRecord", Wrapping.WrapEmptyRecord);
}
@@ -239,6 +239,10 @@ struct ScalarEnumerationTraits<FormatStyle::BraceWrapEmptyRecordStyle> {
FormatStyle::BraceWrapEmptyRecordStyle &Value) {
IO.enumCase(Value, "Default", FormatStyle::BWER_Default);
IO.enumCase(Value, "Never", FormatStyle::BWER_Never);
+
+ // For backward compatibility.
+ IO.enumCase(Value, "false", FormatStyle::BWER_BeforeBrace);
+ IO.enumCase(Value, "true", FormatStyle::BWER_Default);
}
};
@@ -1401,7 +1405,6 @@ static void expandPresetsBraceWrapping(FormatStyle &Expanded) {
/*BeforeWhile=*/false,
/*IndentBraces=*/false,
/*SplitEmptyFunction=*/true,
- /*SplitEmptyRecord=*/true,
/*SplitEmptyNamespace=*/true,
/*WrapEmptyRecord=*/FormatStyle::BWER_Default};
switch (Expanded.BreakBeforeBraces) {
@@ -1418,7 +1421,7 @@ static void expandPresetsBraceWrapping(FormatStyle &Expanded) {
Expanded.BraceWrapping.AfterUnion = true;
Expanded.BraceWrapping.AfterExternBlock = true;
Expanded.BraceWrapping.SplitEmptyFunction = true;
- Expanded.BraceWrapping.SplitEmptyRecord = false;
+ Expanded.BraceWrapping.WrapEmptyRecord = FormatStyle::BWER_BeforeBrace;
break;
case FormatStyle::BS_Stroustrup:
Expanded.BraceWrapping.AfterFunction = true;
@@ -1472,8 +1475,8 @@ static void expandPresetsBraceWrapping(FormatStyle &Expanded) {
/*BeforeWhile=*/true,
/*IndentBraces=*/true,
/*SplitEmptyFunction=*/true,
- /*SplitEmptyRecord=*/true,
- /*SplitEmptyNamespace=*/true};
+ /*SplitEmptyNamespace=*/true,
+ /*WrapEmptyRecord=*/FormatStyle::BWER_Default};
break;
case FormatStyle::BS_WebKit:
Expanded.BraceWrapping.AfterFunction = true;
@@ -1572,8 +1575,8 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
/*BeforeWhile=*/false,
/*IndentBraces=*/false,
/*SplitEmptyFunction=*/true,
- /*SplitEmptyRecord=*/true,
- /*SplitEmptyNamespace=*/true};
+ /*SplitEmptyNamespace=*/true,
+ /*WrapEmptyRecord=*/FormatStyle::BWER_Default};
LLVMStyle.BreakAdjacentStringLiterals = true;
LLVMStyle.BreakAfterAttributes = FormatStyle::ABS_Leave;
LLVMStyle.BreakAfterJavaFieldAnnotations = false;
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 0adf7ee9ed543..5adea2d8f1032 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -277,13 +277,13 @@ class LineJoiner {
Tok = Tok->getNextNonComment();
if (Tok && Tok->isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union,
tok::kw_extern, Keywords.kw_interface)) {
- return !Style.BraceWrapping.SplitEmptyRecord && EmptyBlock
+ return Style.BraceWrapping.WrapEmptyRecord != FormatStyle::BWER_Default && EmptyBlock
? tryMergeSimpleBlock(I, E, Limit)
: 0;
}
if (Tok && Tok->is(tok::kw_template) &&
- Style.BraceWrapping.SplitEmptyRecord && EmptyBlock) {
+ Style.BraceWrapping.WrapEmptyRecord == FormatStyle::BWER_Default && EmptyBlock) {
return 0;
}
}
@@ -453,9 +453,9 @@ class LineJoiner {
}
}
- // Don't merge an empty template class or struct if SplitEmptyRecords
- // is defined.
- if (PreviousLine && Style.BraceWrapping.SplitEmptyRecord &&
+ // Merge an empty class or struct only if WrapEmptyRecord
+ // is not set to Default
+ if (PreviousLine && Style.BraceWrapping.WrapEmptyRecord == FormatStyle::BWER_Default &&
TheLine->Last->is(tok::l_brace) && PreviousLine->Last) {
const FormatToken *Previous = PreviousLine->Last;
if (Previous) {
@@ -495,7 +495,7 @@ class LineJoiner {
// elsewhere.
ShouldMerge = !Style.BraceWrapping.AfterClass ||
(NextLine.First->is(tok::r_brace) &&
- !Style.BraceWrapping.SplitEmptyRecord);
+ Style.BraceWrapping.WrapEmptyRecord != FormatStyle::BWER_Default);
} else if (TheLine->InPPDirective ||
!TheLine->First->isOneOf(tok::kw_class, tok::kw_enum,
tok::kw_struct)) {
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index 9de3cca71630d..4479128e00397 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -237,7 +237,6 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
CHECK_PARSE_NESTED_BOOL(BraceWrapping, BeforeWhile);
CHECK_PARSE_NESTED_BOOL(BraceWrapping, IndentBraces);
CHECK_PARSE_NESTED_BOOL(BraceWrapping, SplitEmptyFunction);
- CHECK_PARSE_NESTED_BOOL(BraceWrapping, SplitEmptyRecord);
CHECK_PARSE_NESTED_BOOL(BraceWrapping, SplitEmptyNamespace);
CHECK_PARSE_NESTED_BOOL(KeepEmptyLines, AtEndOfFile);
CHECK_PARSE_NESTED_BOOL(KeepEmptyLines, AtStartOfBlock);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 5ac92a45927ce..a4f85b8c6d131 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -1491,7 +1491,7 @@ TEST_F(FormatTest, FormatShortBracedStatements) {
AllowSimpleBracedStatements.AllowShortLoopsOnASingleLine = true;
AllowSimpleBracedStatements.BreakBeforeBraces = FormatStyle::BS_Custom;
AllowSimpleBracedStatements.BraceWrapping.AfterFunction = true;
- AllowSimpleBracedStatements.BraceWrapping.SplitEmptyRecord = false;
+ AllowSimpleBracedStatements.BraceWrapping.WrapEmptyRecord = FormatStyle::BWER_BeforeBrace;
verifyFormat("if (true) {}", AllowSimpleBracedStatements);
verifyFormat("if constexpr (true) {}", AllowSimpleBracedStatements);
@@ -4678,7 +4678,7 @@ TEST_F(FormatTest, FormatsExternC) {
Style);
Style.BraceWrapping.AfterExternBlock = true;
- Style.BraceWrapping.SplitEmptyRecord = false;
+ Style.BraceWrapping.WrapEmptyRecord = FormatStyle::BWER_BeforeBrace;
verifyFormat("extern \"C\"\n"
"{}",
Style);
@@ -15322,7 +15322,7 @@ TEST_F(FormatTest, SplitEmptyFunctionButNotRecord) {
Style.BreakBeforeBraces = FormatStyle::BS_Custom;
Style.BraceWrapping.AfterFunction = true;
Style.BraceWrapping.SplitEmptyFunction = true;
- Style.BraceWrapping.SplitEmptyRecord = false;
+ Style.BraceWrapping.WrapEmptyRecord = FormatStyle::BWER_BeforeBrace;
verifyFormat("class C {};", Style);
verifyFormat("struct C {};", Style);
@@ -15361,7 +15361,7 @@ TEST_F(FormatTest, SplitEmptyClass) {
FormatStyle Style = getLLVMStyle();
Style.BreakBeforeBraces = FormatStyle::BS_Custom;
Style.BraceWrapping.AfterClass = true;
- Style.BraceWrapping.SplitEmptyRecord = false;
+ Style.BraceWrapping.WrapEmptyRecord = FormatStyle::BWER_BeforeBrace;
verifyFormat("class Foo\n"
"{};",
@@ -15382,7 +15382,7 @@ TEST_F(FormatTest, SplitEmptyClass) {
"} Foo_t;",
Style);
- Style.BraceWrapping.SplitEmptyRecord = true;
+ Style.BraceWrapping.WrapEmptyRecord = FormatStyle::BWER_Default;
Style.BraceWrapping.AfterStruct = true;
verifyFormat("class rep\n"
"{\n"
@@ -15467,7 +15467,7 @@ TEST_F(FormatTest, SplitEmptyStruct) {
FormatStyle Style = getLLVMStyle();
Style.BreakBeforeBraces = FormatStyle::BS_Custom;
Style.BraceWrapping.AfterStruct = true;
- Style.BraceWrapping.SplitEmptyRecord = false;
+ Style.BraceWrapping.WrapEmptyRecord = FormatStyle::BWER_BeforeBrace;
verifyFormat("struct Foo\n"
"{};",
@@ -15494,7 +15494,7 @@ TEST_F(FormatTest, SplitEmptyUnion) {
FormatStyle Style = getLLVMStyle();
Style.BreakBeforeBraces = FormatStyle::BS_Custom;
Style.BraceWrapping.AfterUnion = true;
- Style.BraceWrapping.SplitEmptyRecord = false;
+ Style.BraceWrapping.WrapEmptyRecord = FormatStyle::BWER_BeforeBrace;
verifyFormat("union Foo\n"
"{};",
@@ -15622,7 +15622,7 @@ TEST_F(FormatTest, WrapEmptyRecords) {
Style.BraceWrapping.AfterStruct = true;
Style.BraceWrapping.AfterClass = true;
Style.BraceWrapping.AfterUnion = true;
- Style.BraceWrapping.SplitEmptyRecord = false;
+ Style.BraceWrapping.WrapEmptyRecord = FormatStyle::BWER_BeforeBrace;
verifyFormat("class foo\n{\n"
" void bar();\n"
diff --git a/clang/unittests/Format/FormatTestCSharp.cpp b/clang/unittests/Format/FormatTestCSharp.cpp
index ea85ed6140dd0..303e6f42898e3 100644
--- a/clang/unittests/Format/FormatTestCSharp.cpp
+++ b/clang/unittests/Format/FormatTestCSharp.cpp
@@ -1315,7 +1315,7 @@ if (someThings[i][j][k].Contains(myThing)) {
TEST_F(FormatTestCSharp, CSharpGenericTypeConstraints) {
FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
- EXPECT_TRUE(Style.BraceWrapping.SplitEmptyRecord);
+ EXPECT_EQ(Style.BraceWrapping.WrapEmptyRecord, FormatStyle::BWER_Default);
verifyFormat("class ItemFactory<T>\n"
" where T : new() {\n"
>From 84852590930ca927818113b3cbebe52c15847058 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoexpo at gmail.com>
Date: Wed, 13 Aug 2025 14:39:05 +0200
Subject: [PATCH 06/10] Fix formatting
---
clang/lib/Format/Format.cpp | 4 +++-
clang/lib/Format/UnwrappedLineFormatter.cpp | 17 +++++++++++------
clang/unittests/Format/FormatTest.cpp | 3 ++-
3 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 6f865b66e3aed..3c4b8ba3f54b6 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -198,9 +198,11 @@ template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> {
IO.mapOptional("BeforeWhile", Wrapping.BeforeWhile);
IO.mapOptional("IndentBraces", Wrapping.IndentBraces);
IO.mapOptional("SplitEmptyFunction", Wrapping.SplitEmptyFunction);
- IO.mapOptional("SplitEmptyRecord", Wrapping.WrapEmptyRecord); // For backward compatibility.
IO.mapOptional("SplitEmptyNamespace", Wrapping.SplitEmptyNamespace);
IO.mapOptional("WrapEmptyRecord", Wrapping.WrapEmptyRecord);
+
+ // For backward compatibility.
+ IO.mapOptional("SplitEmptyRecord", Wrapping.WrapEmptyRecord);
}
};
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 5adea2d8f1032..74df699111fb9 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -277,13 +277,16 @@ class LineJoiner {
Tok = Tok->getNextNonComment();
if (Tok && Tok->isOneOf(tok::kw_class, tok::kw_struct, tok::kw_union,
tok::kw_extern, Keywords.kw_interface)) {
- return Style.BraceWrapping.WrapEmptyRecord != FormatStyle::BWER_Default && EmptyBlock
+ return Style.BraceWrapping.WrapEmptyRecord !=
+ FormatStyle::BWER_Default &&
+ EmptyBlock
? tryMergeSimpleBlock(I, E, Limit)
: 0;
}
if (Tok && Tok->is(tok::kw_template) &&
- Style.BraceWrapping.WrapEmptyRecord == FormatStyle::BWER_Default && EmptyBlock) {
+ Style.BraceWrapping.WrapEmptyRecord == FormatStyle::BWER_Default &&
+ EmptyBlock) {
return 0;
}
}
@@ -455,7 +458,8 @@ class LineJoiner {
// Merge an empty class or struct only if WrapEmptyRecord
// is not set to Default
- if (PreviousLine && Style.BraceWrapping.WrapEmptyRecord == FormatStyle::BWER_Default &&
+ if (PreviousLine &&
+ Style.BraceWrapping.WrapEmptyRecord == FormatStyle::BWER_Default &&
TheLine->Last->is(tok::l_brace) && PreviousLine->Last) {
const FormatToken *Previous = PreviousLine->Last;
if (Previous) {
@@ -493,9 +497,10 @@ class LineJoiner {
// NOTE: We use AfterClass (whereas AfterStruct exists) for both classes
// and structs, but it seems that wrapping is still handled correctly
// elsewhere.
- ShouldMerge = !Style.BraceWrapping.AfterClass ||
- (NextLine.First->is(tok::r_brace) &&
- Style.BraceWrapping.WrapEmptyRecord != FormatStyle::BWER_Default);
+ ShouldMerge =
+ !Style.BraceWrapping.AfterClass ||
+ (NextLine.First->is(tok::r_brace) &&
+ Style.BraceWrapping.WrapEmptyRecord != FormatStyle::BWER_Default);
} else if (TheLine->InPPDirective ||
!TheLine->First->isOneOf(tok::kw_class, tok::kw_enum,
tok::kw_struct)) {
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index a4f85b8c6d131..ab5b48f50c86e 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -1491,7 +1491,8 @@ TEST_F(FormatTest, FormatShortBracedStatements) {
AllowSimpleBracedStatements.AllowShortLoopsOnASingleLine = true;
AllowSimpleBracedStatements.BreakBeforeBraces = FormatStyle::BS_Custom;
AllowSimpleBracedStatements.BraceWrapping.AfterFunction = true;
- AllowSimpleBracedStatements.BraceWrapping.WrapEmptyRecord = FormatStyle::BWER_BeforeBrace;
+ AllowSimpleBracedStatements.BraceWrapping.WrapEmptyRecord =
+ FormatStyle::BWER_BeforeBrace;
verifyFormat("if (true) {}", AllowSimpleBracedStatements);
verifyFormat("if constexpr (true) {}", AllowSimpleBracedStatements);
>From 3c440e8e690017f3667af7f907db1c1de914aaf0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoexpo at gmail.com>
Date: Wed, 13 Aug 2025 17:11:18 +0200
Subject: [PATCH 07/10] Fixup docs, config parse, test
---
clang/include/clang/Format/Format.h | 4 ++--
clang/lib/Format/Format.cpp | 8 +++++---
clang/lib/Format/TokenAnnotator.cpp | 6 ++++--
clang/lib/Format/UnwrappedLineFormatter.cpp | 2 +-
clang/unittests/Format/ConfigParseTest.cpp | 18 ++++++++++++++++++
clang/unittests/Format/FormatTest.cpp | 13 +++++++++++++
6 files changed, 43 insertions(+), 8 deletions(-)
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 22b43a68ed583..74055580570d7 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -1365,13 +1365,13 @@ struct FormatStyle {
/// };
/// \endcode
BWER_Default,
- /// Only wrap before brace (equivalent to ``SplitEmptyRecord=false``).
+ /// Only wrap before brace.
/// \code
/// class foo
/// {};
/// \endcode
BWER_BeforeBrace,
- /// Wrap neither before or after the brace.
+ /// Wrap neither before nor after the brace.
/// \code
/// class foo {};
/// \endcode
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 3c4b8ba3f54b6..8687b487b2d15 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -182,6 +182,10 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BraceBreakingStyle> {
template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> {
static void mapping(IO &IO, FormatStyle::BraceWrappingFlags &Wrapping) {
+ // For backward compatibility.
+ if (!IO.outputting())
+ IO.mapOptional("SplitEmptyRecord", Wrapping.WrapEmptyRecord);
+
IO.mapOptional("AfterCaseLabel", Wrapping.AfterCaseLabel);
IO.mapOptional("AfterClass", Wrapping.AfterClass);
IO.mapOptional("AfterControlStatement", Wrapping.AfterControlStatement);
@@ -200,9 +204,6 @@ template <> struct MappingTraits<FormatStyle::BraceWrappingFlags> {
IO.mapOptional("SplitEmptyFunction", Wrapping.SplitEmptyFunction);
IO.mapOptional("SplitEmptyNamespace", Wrapping.SplitEmptyNamespace);
IO.mapOptional("WrapEmptyRecord", Wrapping.WrapEmptyRecord);
-
- // For backward compatibility.
- IO.mapOptional("SplitEmptyRecord", Wrapping.WrapEmptyRecord);
}
};
@@ -240,6 +241,7 @@ struct ScalarEnumerationTraits<FormatStyle::BraceWrapEmptyRecordStyle> {
static void enumeration(IO &IO,
FormatStyle::BraceWrapEmptyRecordStyle &Value) {
IO.enumCase(Value, "Default", FormatStyle::BWER_Default);
+ IO.enumCase(Value, "BeforeBrace", FormatStyle::BWER_BeforeBrace);
IO.enumCase(Value, "Never", FormatStyle::BWER_Never);
// For backward compatibility.
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 22132f6d2fd3b..804a6fb0418c6 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -5933,12 +5933,14 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
return true;
}
- // Don't attempt to interpret struct return types as structs.
+ // Don't attempt to interpret record return types as records.
if (Right.isNot(TT_FunctionLBrace)) {
return ((Line.startsWith(tok::kw_class) &&
Style.BraceWrapping.AfterClass) ||
(Line.startsWith(tok::kw_struct) &&
- Style.BraceWrapping.AfterStruct)) &&
+ Style.BraceWrapping.AfterStruct) ||
+ (Line.startsWith(tok::kw_union) &&
+ Style.BraceWrapping.AfterUnion)) &&
Style.BraceWrapping.WrapEmptyRecord == FormatStyle::BWER_Default;
}
}
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 74df699111fb9..01bc06a754c53 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -457,7 +457,7 @@ class LineJoiner {
}
// Merge an empty class or struct only if WrapEmptyRecord
- // is not set to Default
+ // is not set to Default.
if (PreviousLine &&
Style.BraceWrapping.WrapEmptyRecord == FormatStyle::BWER_Default &&
TheLine->Last->is(tok::l_brace) && PreviousLine->Last) {
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index 4479128e00397..809244bf86eb2 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -758,6 +758,24 @@ TEST(ConfigParseTest, ParsesConfiguration) {
" AfterControlStatement: false",
BraceWrapping.AfterControlStatement, FormatStyle::BWACS_Never);
+ Style.BraceWrapping.WrapEmptyRecord = FormatStyle::BWER_Default;
+ CHECK_PARSE("BraceWrapping:\n"
+ " WrapEmptyRecord: BeforeBrace",
+ BraceWrapping.WrapEmptyRecord, FormatStyle::BWER_BeforeBrace);
+ CHECK_PARSE("BraceWrapping:\n"
+ " WrapEmptyRecord: Default",
+ BraceWrapping.WrapEmptyRecord, FormatStyle::BWER_Default);
+ CHECK_PARSE("BraceWrapping:\n"
+ " WrapEmptyRecord: Never",
+ BraceWrapping.WrapEmptyRecord, FormatStyle::BWER_Never);
+ // For backward compatibility:
+ CHECK_PARSE("BraceWrapping:\n"
+ " WrapEmptyRecord: true",
+ BraceWrapping.WrapEmptyRecord, FormatStyle::BWER_Default);
+ CHECK_PARSE("BraceWrapping:\n"
+ " WrapEmptyRecord: false",
+ BraceWrapping.WrapEmptyRecord, FormatStyle::BWER_BeforeBrace);
+
Style.BreakAfterReturnType = FormatStyle::RTBS_All;
CHECK_PARSE("BreakAfterReturnType: None", BreakAfterReturnType,
FormatStyle::RTBS_None);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index ab5b48f50c86e..fa03bea45a533 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -8625,6 +8625,19 @@ TEST_F(FormatTest, BreaksFunctionDeclarations) {
Style);
}
+TEST_F(FormatTest, BreakFunctionsReturningRecords) {
+ FormatStyle Style = getLLVMStyle();
+ Style.BreakBeforeBraces = FormatStyle::BS_Custom;
+ Style.BraceWrapping.AfterFunction = true;
+ Style.BraceWrapping.AfterClass = false;
+ Style.BraceWrapping.AfterStruct = false;
+ Style.BraceWrapping.AfterUnion = false;
+
+ verifyFormat("class Bar foo() {}", Style);
+ verifyFormat("struct Bar foo() {}", Style);
+ verifyFormat("union Bar foo() {}", Style);
+}
+
TEST_F(FormatTest, DontBreakBeforeQualifiedOperator) {
// Regression test for https://bugs.llvm.org/show_bug.cgi?id=40516:
// Prefer keeping `::` followed by `operator` together.
>From 0a50d975af9e253f6e4ddfab37cb42288d93cfde Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoexpo at gmail.com>
Date: Wed, 13 Aug 2025 17:24:05 +0200
Subject: [PATCH 08/10] Regenerate format option docs
---
clang/docs/ClangFormatStyleOptions.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 375393e12691e..1197ede357dd4 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -2596,7 +2596,7 @@ the configuration (without a prefix: ``Auto``).
};
* ``BWER_BeforeBrace`` (in configuration: ``BeforeBrace``)
- Only wrap before brace (equivalent to ``SplitEmptyRecord=false``).
+ Only wrap before brace.
.. code-block:: c++
@@ -2604,7 +2604,7 @@ the configuration (without a prefix: ``Auto``).
{};
* ``BWER_Never`` (in configuration: ``Never``)
- Wrap neither before or after the brace.
+ Wrap neither before nor after the brace.
.. code-block:: c++
>From c11352ed314c356e67902aaf602a54226c143473 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoexpo at gmail.com>
Date: Thu, 14 Aug 2025 13:10:40 +0200
Subject: [PATCH 09/10] Fix formatting
---
clang/include/clang/Format/Format.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 74055580570d7..4f3784e33cb45 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -1596,7 +1596,7 @@ struct FormatStyle {
/// }
/// \endcode
// bool SplitEmptyRecord;
-
+
/// If ``false``, empty namespace body can be put on a single line.
/// This option is used only if the opening brace of the namespace has
/// already been wrapped, i.e. the ``AfterNamespace`` brace wrapping mode is
>From 0e74ac2a0d68452d017caea4fed33caaf8966048 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Slanina?= <itzexpoexpo at gmail.com>
Date: Sun, 17 Aug 2025 18:36:04 +0200
Subject: [PATCH 10/10] Extend backward compatibility tests
---
clang/unittests/Format/ConfigParseTest.cpp | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index 809244bf86eb2..11c041ec719f9 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -775,6 +775,20 @@ TEST(ConfigParseTest, ParsesConfiguration) {
CHECK_PARSE("BraceWrapping:\n"
" WrapEmptyRecord: false",
BraceWrapping.WrapEmptyRecord, FormatStyle::BWER_BeforeBrace);
+ CHECK_PARSE("BraceWrapping:\n"
+ " SplitEmptyRecord: true",
+ BraceWrapping.WrapEmptyRecord, FormatStyle::BWER_Default);
+ CHECK_PARSE("BraceWrapping:\n"
+ " SplitEmptyRecord: false",
+ BraceWrapping.WrapEmptyRecord, FormatStyle::BWER_BeforeBrace);
+ CHECK_PARSE("BraceWrapping:\n"
+ " SplitEmptyRecord: true\n"
+ " WrapEmptyRecord: Never",
+ BraceWrapping.WrapEmptyRecord, FormatStyle::BWER_Never);
+ CHECK_PARSE("BraceWrapping:\n"
+ " WrapEmptyRecord: BeforeBrace\n"
+ " SplitEmptyRecord: true",
+ BraceWrapping.WrapEmptyRecord, FormatStyle::BWER_BeforeBrace);
Style.BreakAfterReturnType = FormatStyle::RTBS_All;
CHECK_PARSE("BreakAfterReturnType: None", BreakAfterReturnType,
More information about the cfe-commits
mailing list