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?= <itzexpoe...@gmail.com>
Date: Mon, 4 Aug 2025 15:19:53 +0200
Subject: [PATCH 1/4] [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?= <itzexpoe...@gmail.com>
Date: Mon, 4 Aug 2025 16:11:48 +0200
Subject: [PATCH 2/4] 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?= <itzexpoe...@gmail.com>
Date: Mon, 11 Aug 2025 16:23:17 +0200
Subject: [PATCH 3/4] !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?= <itzexpoe...@gmail.com>
Date: Mon, 11 Aug 2025 18:06:50 +0200
Subject: [PATCH 4/4] 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);
 }
 

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to