[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
Fri Jun 14 00:18:37 PDT 2024


https://github.com/khei4 updated https://github.com/llvm/llvm-project/pull/93634

>From 02b4de5799efe104f1111352d3f586e8779c5cd4 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      |  97 ++++++++++++++-
 clang/include/clang/Format/Format.h         | 114 ++++++++++++++++--
 clang/lib/Format/Format.cpp                 |  40 ++++++-
 clang/lib/Format/TokenAnnotator.cpp         |  27 ++++-
 clang/lib/Format/UnwrappedLineFormatter.cpp |  23 +++-
 clang/unittests/Format/ConfigParseTest.cpp  |   9 +-
 clang/unittests/Format/FormatTest.cpp       | 126 +++++++++++++++++++-
 7 files changed, 412 insertions(+), 24 deletions(-)

diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index bb00c20922d36..9879d122f8d57 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -6036,12 +6036,103 @@ 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 ``Block`` in
+  ``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++
+
+       void f() {}
+       T x{};
+       while (true) {}
+       struct U1 {};
+       union U2 {};
+       class U3 {};
+       enum U4 {};
+
+  * ``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:
+      Function: true
+      Record: false
+      InitList: true
+      Block: false
+
+  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:
+      Function: true
+      Record: false
+      InitList: true
+      Block: false
+
+  * ``bool Function`` Put a space in empty braces of function definition.
+
+    .. code-block:: c++
+
+       true:                                  false:
+       void f() { }                   vs.     void f() {}
+
+  * ``bool Record`` Put a space in empty braces of record/struct definition.
+
+    .. code-block:: c++
+
+       true:                                  false:
+       struct U1 { };                 vs.     struct U1 {};
+       union U2 { };                          union U2 {};
+       class U3 { };                          class U3 {};
+       enum U4 { };                           enum U4 {};
+
+  * ``bool InitList`` Put a space in empty braces of initializer list.
+
+    .. code-block:: c++
+
+       true:                                  false:
+       T x{ };                        vs.     T x{};
+
+  * ``bool Block`` Put a space in empty braces of other blocks, including functions and
+    record, compatible with ``SpaceInEmptyBlock``.
+
+    .. code-block:: c++
+
+       true:                                  false:
+       void f() { }                   vs.     void f() {}
+       enum Unit { };                         enum Unit {};
+       while (true) { }                       while (true) {}
+
 
 .. _SpaceInEmptyParentheses:
 
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 4fd6e013df25b..661147a454694 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -4493,13 +4493,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 ``Block`` in
+  /// ``SpaceInEmptyBracesOptions`` to ``true``.
   /// \version 10
-  bool SpaceInEmptyBlock;
+  // bool SpaceInEmptyBlock;
 
   /// If ``true``, spaces may be inserted into ``()``.
   /// This option is **deprecated**. See ``InEmptyParentheses`` of
@@ -4721,6 +4719,107 @@ 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
+    ///    void f() {}
+    ///    T x{};
+    ///    while (true) {}
+    ///    struct U1 {};
+    ///    union U2 {};
+    ///    class U3 {};
+    ///    enum U4 {};
+    /// \endcode
+    SIEBO_Never,
+    /// Always put a space in empty braces.
+    SIEBO_Always,
+    /// 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:
+  ///     Function: true
+  ///     Record: false
+  ///     InitList: true
+  ///     Block: false
+  /// \endcode
+  struct SpaceInEmptyBracesCustom {
+    /// Put a space in empty braces of function definition.
+    /// \code
+    ///    true:                                  false:
+    ///    void f() { }                   vs.     void f() {}
+    /// \endcode
+    bool Function;
+    /// Put a space in empty braces of record/struct definition.
+    /// \code
+    ///    true:                                  false:
+    ///    struct U1 { };                 vs.     struct U1 {};
+    ///    union U2 { };                          union U2 {};
+    ///    class U3 { };                          class U3 {};
+    ///    enum U4 { };                           enum U4 {};
+    /// \endcode
+    bool Record;
+    /// Put a space in empty braces of initializer list.
+    /// \code
+    ///    true:                                  false:
+    ///    T x{ };                        vs.     T x{};
+    /// \endcode
+    bool InitList;
+    /// Put a space in empty braces of other blocks, including functions and
+    /// record, compatible with ``SpaceInEmptyBlock``.
+    /// \code
+    ///    true:                                  false:
+    ///    void f() { }                   vs.     void f() {}
+    ///    enum Unit { };                         enum Unit {};
+    ///    while (true) { }                       while (true) {}
+    /// \endcode
+    bool Block;
+
+    SpaceInEmptyBracesCustom()
+        : Function(false), Record(false), InitList(false), Block(false) {}
+
+    SpaceInEmptyBracesCustom(bool Function, bool Record, bool InitList,
+                             bool Block)
+        : Function(Function), Record(Record), InitList(InitList), Block(Block) {
+    }
+
+    bool operator==(const SpaceInEmptyBracesCustom &R) const {
+      return Function == R.Function && Record == R.Record &&
+             InitList == R.InitList && Block == R.Block;
+    }
+
+    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:
+  ///     Function: true
+  ///     Record: false
+  ///     InitList: true
+  ///     Block: false
+  /// \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.
@@ -5094,7 +5193,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 c015e03fa15e7..1a3446f9c883d 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -719,6 +719,24 @@ template <> struct MappingTraits<FormatStyle::SpacesInLineComment> {
   }
 };
 
+template <> struct MappingTraits<FormatStyle::SpaceInEmptyBracesCustom> {
+  static void mapping(IO &IO, FormatStyle::SpaceInEmptyBracesCustom &Space) {
+    IO.mapOptional("Function", Space.Function);
+    IO.mapOptional("Record", Space.Record);
+    IO.mapOptional("InitList", Space.InitList);
+    IO.mapOptional("Block", Space.Block);
+  }
+};
+
+template <>
+struct ScalarEnumerationTraits<FormatStyle::SpaceInEmptyBracesStyle> {
+  static void enumeration(IO &IO, FormatStyle::SpaceInEmptyBracesStyle &Value) {
+    IO.enumCase(Value, "Never", FormatStyle::SIEBO_Never);
+    IO.enumCase(Value, "Always", FormatStyle::SIEBO_Always);
+    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);
@@ -850,6 +868,7 @@ template <> struct MappingTraits<FormatStyle> {
     bool UseCRLF = false;
 
     bool SpaceInEmptyParentheses = false;
+    bool SpaceInEmptyBlock = false;
     bool SpacesInConditionalStatement = false;
     bool SpacesInCStyleCastParentheses = false;
     bool SpacesInParentheses = false;
@@ -876,6 +895,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",
@@ -1092,7 +1112,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);
@@ -1100,6 +1119,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);
@@ -1194,6 +1216,15 @@ template <> struct MappingTraits<FormatStyle> {
       }
       Style.SpacesInParens = FormatStyle::SIPO_Custom;
     }
+
+    if (Style.SpaceInEmptyBraces != FormatStyle::SIEBO_Custom &&
+        SpaceInEmptyBlock) {
+      Style.SpaceInEmptyBraces = FormatStyle::SIEBO_Custom;
+      Style.SpaceInEmptyBracesOptions.Function = true;
+      Style.SpaceInEmptyBracesOptions.Record = true;
+      Style.SpaceInEmptyBracesOptions.InitList = false;
+      Style.SpaceInEmptyBracesOptions.Block = true;
+    }
   }
 };
 
@@ -1563,7 +1594,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;
@@ -1864,7 +1895,10 @@ 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.SpacesInParensOptions.InEmptyParentheses = false;
+  Style.SpacesInParensOptions.Other = false;
   return Style;
 }
 
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 26c0aa36bdcb6..198800d586700 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -4337,15 +4337,32 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
     return Left.is(tok::hash);
   if (Left.isOneOf(tok::hashhash, tok::hash))
     return Right.is(tok::hash);
-  if (Left.is(BK_Block) && Right.is(tok::r_brace) &&
-      Right.MatchingParen == &Left && Line.Children.empty()) {
-    return Style.SpaceInEmptyBlock;
-  }
+
   if ((Left.is(tok::l_paren) && Right.is(tok::r_paren)) ||
       (Left.is(tok::l_brace) && Left.isNot(BK_Block) &&
-       Right.is(tok::r_brace) && Right.isNot(BK_Block))) {
+       Right.is(tok::r_brace) && Right.isNot(BK_Block) &&
+       Style.SpaceInEmptyBraces == FormatStyle::SIEBO_Never)) {
     return Style.SpacesInParensOptions.InEmptyParentheses;
   }
+  // Other braces for records are handled in tryMergeSimpleBlock on
+  // UnwrappedLineFormatter.cpp.
+  if (Left.is(tok::l_brace) && Right.is(tok::r_brace) &&
+      Right.MatchingParen == &Left && Line.Children.empty()) {
+    if (Style.SpaceInEmptyBraces == FormatStyle::SIEBO_Never)
+      return false;
+    if (Style.SpaceInEmptyBraces == FormatStyle::SIEBO_Always)
+      return true;
+    if (Style.SpaceInEmptyBraces == FormatStyle::SIEBO_Custom) {
+      if (Left.is(BK_BracedInit) && Right.is(BK_BracedInit))
+        return Style.SpaceInEmptyBracesOptions.InitList;
+      if (Left.is(TT_EnumLBrace) && Right.is(TT_EnumRBrace)) {
+        return Style.SpaceInEmptyBracesOptions.Record ||
+               Style.SpaceInEmptyBracesOptions.Block;
+      }
+      if (Left.is(BK_Block))
+        return Style.SpaceInEmptyBracesOptions.Block;
+    }
+  }
   if (Style.SpacesInParensOptions.InConditionalStatements) {
     const FormatToken *LeftParen = nullptr;
     if (Left.is(tok::l_paren))
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 4d53361aaf333..f46af2425ed81 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -823,12 +823,29 @@ class LineJoiner {
 
       if (ShouldMerge()) {
         // We merge empty blocks even if the line exceeds the column limit.
+        bool braceRequireSpace = false;
+        if (Style.SpaceInEmptyBraces == FormatStyle::SIEBO_Always) {
+          braceRequireSpace =
+              Line.Last->isOneOf(TT_StructLBrace, TT_UnionLBrace,
+                                 TT_ClassLBrace, TT_FunctionLBrace) ||
+              Line.Last->is(BK_Block);
+        } else if (Style.SpaceInEmptyBraces == FormatStyle::SIEBO_Custom) {
+          if (Style.SpaceInEmptyBracesOptions.Record) {
+            braceRequireSpace |= Line.Last->isOneOf(
+                TT_StructLBrace, TT_UnionLBrace, TT_ClassLBrace);
+          }
+          if (Style.SpaceInEmptyBracesOptions.Function)
+            braceRequireSpace |= Line.Last->is(TT_FunctionLBrace);
+          if (Style.SpaceInEmptyBracesOptions.Block)
+            braceRequireSpace |= Line.Last->is(BK_Block);
+        }
         Tok->SpacesRequiredBefore =
-            (Style.SpaceInEmptyBlock || Line.Last->is(tok::comment)) ? 1 : 0;
+            (braceRequireSpace || Line.Last->is(tok::comment)) ? 1 : 0;
         Tok->CanBreakBefore = true;
         return 1;
-      } else if (Limit != 0 && !Line.startsWithNamespace() &&
-                 !startsExternCBlock(Line)) {
+      }
+      if (Limit != 0 && !Line.startsWithNamespace() &&
+          !startsExternCBlock(Line)) {
         // We don't merge short records.
         if (isRecordLBrace(*Line.Last))
           return 0;
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index ff3ced38a1f31..3ebc503955e54 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);
@@ -638,6 +639,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, true, false, true));
+
   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 4e427268fb82a..a7848a7fca18d 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -6981,7 +6981,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);
@@ -7009,7 +7010,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);
 }
 
@@ -14046,9 +14048,129 @@ TEST_F(FormatTest, LayoutCxx11BraceInitializers) {
   verifyFormat("vector< int > x{};", SpaceBetweenBraces);
   SpaceBetweenBraces.SpacesInParens = FormatStyle::SIPO_Custom;
   SpaceBetweenBraces.SpacesInParensOptions.InEmptyParentheses = true;
+  SpaceBetweenBraces.SpaceInEmptyBraces = FormatStyle::SIEBO_Custom;
+  SpaceBetweenBraces.SpaceInEmptyBracesOptions.InitList = true;
   verifyFormat("vector< int > x{ };", SpaceBetweenBraces);
 }
 
+TEST_F(FormatTest, EmptyBracesTest) {
+  FormatStyle SpaceInEmptyBraces = getLLVMStyle();
+  SpaceInEmptyBraces.SpaceInEmptyBraces = FormatStyle::SIEBO_Never;
+  SpaceInEmptyBraces.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Empty;
+  verifyFormat("void f() {}\n"
+               "struct Unit {};\n"
+               "union U2 {};\n"
+               "class U3 {};\n"
+               "enum U4 {};\n"
+               "int x{};\n"
+               "while (true) {}\n"
+               "auto a = [] {};\n"
+               "toImpl(listenerRef)->use({});\n",
+               SpaceInEmptyBraces);
+
+  SpaceInEmptyBraces.SpaceInEmptyBraces = FormatStyle::SIEBO_Always;
+  SpaceInEmptyBraces.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Empty;
+  verifyFormat("void f() { }\n"
+               "struct Unit { };\n"
+               "union U2 { };\n"
+               "class U3 { };\n"
+               "enum U4 { };\n"
+               "int x{ };\n"
+               "while (true) { }\n"
+               "auto a = [] { };\n"
+               "toImpl(listenerRef)->use({ });\n",
+               SpaceInEmptyBraces);
+
+  SpaceInEmptyBraces.SpaceInEmptyBraces = FormatStyle::SIEBO_Custom;
+  SpaceInEmptyBraces.SpaceInEmptyBracesOptions.Function = true;
+  SpaceInEmptyBraces.SpaceInEmptyBracesOptions.Record = false;
+  SpaceInEmptyBraces.SpaceInEmptyBracesOptions.InitList = false;
+  SpaceInEmptyBraces.SpaceInEmptyBracesOptions.Block = false;
+  SpaceInEmptyBraces.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Empty;
+  verifyFormat("void f() { }\n"
+               "struct Unit {};\n"
+               "union U2 {};\n"
+               "class U3 {};\n"
+               "enum U4 {};\n"
+               "int x{};\n"
+               "while (true) {}\n"
+               "auto a = [] {};\n"
+               "toImpl(listenerRef)->use({});\n",
+               SpaceInEmptyBraces);
+
+  SpaceInEmptyBraces.SpaceInEmptyBraces = FormatStyle::SIEBO_Custom;
+  SpaceInEmptyBraces.SpaceInEmptyBracesOptions.Function = false;
+  SpaceInEmptyBraces.SpaceInEmptyBracesOptions.Record = true;
+  SpaceInEmptyBraces.SpaceInEmptyBracesOptions.InitList = false;
+  SpaceInEmptyBraces.SpaceInEmptyBracesOptions.Block = false;
+  SpaceInEmptyBraces.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Empty;
+  verifyFormat("void f() {}\n"
+               "struct Unit { };\n"
+               "union U2 { };\n"
+               "class U3 { };\n"
+               "enum U4 { };\n"
+               "int x{};\n"
+               "while (true) {}\n"
+               "auto a = [] {};\n"
+               "toImpl(listenerRef)->use({});\n",
+               SpaceInEmptyBraces);
+
+  SpaceInEmptyBraces.SpaceInEmptyBraces = FormatStyle::SIEBO_Custom;
+  SpaceInEmptyBraces.SpaceInEmptyBracesOptions.Function = false;
+  SpaceInEmptyBraces.SpaceInEmptyBracesOptions.Record = false;
+  SpaceInEmptyBraces.SpaceInEmptyBracesOptions.InitList = true;
+  SpaceInEmptyBraces.SpaceInEmptyBracesOptions.Block = false;
+  SpaceInEmptyBraces.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Empty;
+  verifyFormat("void f() {}\n"
+               "struct Unit {};\n"
+               "union U2 {};\n"
+               "class U3 {};\n"
+               "enum U4 {};\n"
+               "int x{ };\n"
+               "while (true) {}\n"
+               "auto a = [] {};\n"
+               "toImpl(listenerRef)->use({ });\n",
+               SpaceInEmptyBraces);
+
+  // Compatible with SpaceInEmptyBlock.
+  SpaceInEmptyBraces.SpaceInEmptyBraces = FormatStyle::SIEBO_Custom;
+  SpaceInEmptyBraces.SpaceInEmptyBracesOptions.Function = true;
+  SpaceInEmptyBraces.SpaceInEmptyBracesOptions.Record = true;
+  SpaceInEmptyBraces.SpaceInEmptyBracesOptions.InitList = false;
+  SpaceInEmptyBraces.SpaceInEmptyBracesOptions.Block = true;
+  SpaceInEmptyBraces.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Empty;
+  verifyFormat("void f() { }\n"
+               "struct Unit { };\n"
+               "union U2 { };\n"
+               "class U3 { };\n"
+               "enum U4 { };\n"
+               "int x{};\n"
+               "while (true) { }\n"
+               "auto a = [] { };\n"
+               "toImpl(listenerRef)->use({});\n",
+               SpaceInEmptyBraces);
+
+  // We can insert a space only for parens by overwriting
+  // SpacesInParensOptions.InEmptyParentheses.
+  SpaceInEmptyBraces.SpaceInEmptyBraces = FormatStyle::SIEBO_Custom;
+  SpaceInEmptyBraces.SpaceInEmptyBracesOptions.Function = false;
+  SpaceInEmptyBraces.SpaceInEmptyBracesOptions.Record = false;
+  SpaceInEmptyBraces.SpaceInEmptyBracesOptions.InitList = false;
+  SpaceInEmptyBraces.SpaceInEmptyBracesOptions.Block = false;
+  SpaceInEmptyBraces.SpacesInParens = FormatStyle::SIPO_Custom;
+  SpaceInEmptyBraces.SpacesInParensOptions.InEmptyParentheses = true;
+  SpaceInEmptyBraces.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Empty;
+  verifyFormat("void f( ) {}\n"
+               "struct Unit {};\n"
+               "union U2 {};\n"
+               "enum U3 {};\n"
+               "int x{};\n"
+               "while (true) {}\n"
+               "auto a = [] {};\n"
+               "toImpl(listenerRef)->use({});\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