[clang] [clang-format] Add AlignAfterOpenBracketOptions (PR #108332)

Gedare Bloom via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 11 22:20:44 PDT 2024


https://github.com/gedare created https://github.com/llvm/llvm-project/pull/108332

Introduce sub-options for `AlignAfterOpenBracketBreak` to allow for control of `AlignAfterOpenBracket` with `AlwaysBreak` and `BlockIndent` selectively for `if` conditional statements (as currently supported), other conditional statements (for/while/switch), and other statements.
 
Fixes #67738 
Fixes #79176 
Fixes #80123 


>From d7f91961dc2fba5d441d2e6b4f04042d4cbd01ed Mon Sep 17 00:00:00 2001
From: Gedare Bloom <gedare at rtems.org>
Date: Thu, 20 Jun 2024 17:35:39 -0600
Subject: [PATCH 1/2] Format: add AlignAfterOpenBracketOptions

Introduce new options to allow for control of AlwaysBreak and
BlockIndent selectively for If conditional statements (as currently
supported), other conditional statements (for/while/switch), and
other statements.

Fixes #67738.
Fixes #79176.
Fixes #80123.
---
 clang/docs/ClangFormatStyleOptions.rst     |  60 +++++++++
 clang/include/clang/Format/Format.h        |  73 +++++++++++
 clang/lib/Format/ContinuationIndenter.cpp  |  41 ++++--
 clang/lib/Format/Format.cpp                |  26 ++++
 clang/lib/Format/TokenAnnotator.cpp        |   8 +-
 clang/unittests/Format/ConfigParseTest.cpp |  12 ++
 clang/unittests/Format/FormatTest.cpp      | 143 +++++++++++++++++++++
 7 files changed, 353 insertions(+), 10 deletions(-)

diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index a427d7cd40fcdd..62462c3202bee0 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -246,6 +246,66 @@ the configuration (without a prefix: ``Auto``).
 
 
 
+.. _AlignAfterOpenBracketBreak:
+
+**AlignAfterOpenBracketBreak** (``AlignAfterOpenBracketCustom``) :versionbadge:`clang-format 20` :ref:`¶ <AlignAfterOpenBracketBreak>`
+  Control of when ``AlignAfterOpenBracket`` breaks an opening bracket.
+
+  If ``AlignAfterOpenBracket`` is set to ``AlwaysBreak`` or ``BlockIndent``,
+  use this to specify how different cases of breaking the opening brackets
+  should be handled. Otherwise, this is ignored. Setting any of these to
+  ``false`` will cause them to not break. At least one of these must be set
+  to ``true``, otherwise a default (backward compatible) breaking behavior
+  is used. This is ignored for ``Align`` and ``DontAlign``.
+
+  .. code-block:: c++
+
+    # Example of usage:
+    AlignAfterOpenBracket: AlwaysBreak
+    AlignAfterOpenBracketBreak:
+      InIfConditionalStatements: true
+      InOtherConditionalStatements: false
+      Other: true
+
+  Nested configuration flags:
+
+  Precise control over breaking the opening bracket of
+  ``AlignAfterOpenBracket``.
+
+  .. code-block:: c++
+
+    # Should be declared this way:
+    AlignAfterOpenBracketBreak:
+      InIfConditionalStatements: true
+      InOtherConditionalStatements: false
+      Other: true
+
+  * ``bool InIfConditionalStatements`` Break inside if/else if statements.
+
+    .. code-block:: c++
+
+       true:                                  false:
+       if constexpr (                   vs.   if constexpr (a ||
+          a || b)                                           b)
+
+  * ``bool InOtherConditionalStatements`` Break inside conditional statements not covered by preceding options.
+    (``for/while/switch...``).
+
+    .. code-block:: c++
+
+       true:                                  false:
+       while (                          vs.   while (a &&
+          a && b ) {                                 b) {
+
+  * ``bool Other`` Break inside brackets not covered by preceding options.
+
+    .. code-block:: c++
+
+       true:                                  false:
+       someLongFunction(                vs.   someLongFunction(argument1,
+          argument1, argument2);                               argument2);
+
+
 .. _AlignArrayOfStructures:
 
 **AlignArrayOfStructures** (``ArrayInitializerAlignmentStyle``) :versionbadge:`clang-format 13` :ref:`¶ <AlignArrayOfStructures>`
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index d8b62c7652a0f6..6e173d6d2b459f 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -106,6 +106,78 @@ struct FormatStyle {
   /// \version 3.8
   BracketAlignmentStyle AlignAfterOpenBracket;
 
+  /// Precise control over breaking the opening bracket of
+  /// ``AlignAfterOpenBracket``.
+  /// \code
+  ///   # Should be declared this way:
+  ///   AlignAfterOpenBracketBreak:
+  ///     InIfConditionalStatements: true
+  ///     InOtherConditionalStatements: false
+  ///     Other: true
+  /// \endcode
+  struct AlignAfterOpenBracketCustom {
+    /// Break inside if/else if statements.
+    /// \code
+    ///    true:                                  false:
+    ///    if constexpr (                   vs.   if constexpr (a ||
+    ///       a || b)                                           b)
+    /// \endcode
+    bool InIfConditionalStatements;
+    /// Break inside conditional statements not covered by preceding options.
+    /// (``for/while/switch...``).
+    /// \code
+    ///    true:                                  false:
+    ///    while (                          vs.   while (a &&
+    ///       a && b ) {                                 b) {
+    /// \endcode
+    bool InOtherConditionalStatements;
+    /// Break inside brackets not covered by preceding options.
+    /// \code
+    ///    true:                                  false:
+    ///    someLongFunction(                vs.   someLongFunction(argument1,
+    ///       argument1, argument2);                               argument2);
+    /// \endcode
+    bool Other;
+
+    AlignAfterOpenBracketCustom()
+        : InIfConditionalStatements(false), InOtherConditionalStatements(false),
+          Other(false) {}
+
+    AlignAfterOpenBracketCustom(bool InIfConditionalStatements,
+                                bool InOtherConditionalStatements, bool Other)
+        : InIfConditionalStatements(InIfConditionalStatements),
+          InOtherConditionalStatements(InOtherConditionalStatements),
+          Other(Other) {}
+
+    bool operator==(const AlignAfterOpenBracketCustom &R) const {
+      return InIfConditionalStatements == R.InIfConditionalStatements &&
+             InOtherConditionalStatements == R.InOtherConditionalStatements &&
+             Other == R.Other;
+    }
+    bool operator!=(const AlignAfterOpenBracketCustom &R) const {
+      return !(*this == R);
+    }
+  };
+
+  /// Control of when ``AlignAfterOpenBracket`` breaks an opening bracket.
+  ///
+  /// If ``AlignAfterOpenBracket`` is set to ``AlwaysBreak`` or ``BlockIndent``,
+  /// use this to specify how different cases of breaking the opening brackets
+  /// should be handled. Otherwise, this is ignored. Setting any of these to
+  /// ``false`` will cause them to not break. At least one of these must be set
+  /// to ``true``, otherwise a default (backward compatible) breaking behavior
+  /// is used. This is ignored for ``Align`` and ``DontAlign``.
+  /// \code
+  ///   # Example of usage:
+  ///   AlignAfterOpenBracket: AlwaysBreak
+  ///   AlignAfterOpenBracketBreak:
+  ///     InIfConditionalStatements: true
+  ///     InOtherConditionalStatements: false
+  ///     Other: true
+  /// \endcode
+  /// \version 20
+  AlignAfterOpenBracketCustom AlignAfterOpenBracketBreak;
+
   /// Different style for aligning array initializers.
   enum ArrayInitializerAlignmentStyle : int8_t {
     /// Align array column and left justify the columns e.g.:
@@ -5060,6 +5132,7 @@ struct FormatStyle {
   bool operator==(const FormatStyle &R) const {
     return AccessModifierOffset == R.AccessModifierOffset &&
            AlignAfterOpenBracket == R.AlignAfterOpenBracket &&
+           AlignAfterOpenBracketBreak == R.AlignAfterOpenBracketBreak &&
            AlignArrayOfStructures == R.AlignArrayOfStructures &&
            AlignConsecutiveAssignments == R.AlignConsecutiveAssignments &&
            AlignConsecutiveBitFields == R.AlignConsecutiveBitFields &&
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index f29f8796ea9290..673e8ca54ddc03 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -795,6 +795,9 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
   // parenthesis by disallowing any further line breaks if there is no line
   // break after the opening parenthesis. Don't break if it doesn't conserve
   // columns.
+  auto IsOtherConditional = [](const FormatToken &Tok) {
+    return Tok.isOneOf(tok::kw_for, tok::kw_while, tok::kw_switch);
+  };
   auto IsOpeningBracket = [&](const FormatToken &Tok) {
     auto IsStartOfBracedList = [&]() {
       return Tok.is(tok::l_brace) && Tok.isNot(BK_Block) &&
@@ -807,9 +810,11 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
     if (!Tok.Previous)
       return true;
     if (Tok.Previous->isIf())
-      return Style.AlignAfterOpenBracket == FormatStyle::BAS_AlwaysBreak;
-    return !Tok.Previous->isOneOf(TT_CastRParen, tok::kw_for, tok::kw_while,
-                                  tok::kw_switch);
+      return Style.AlignAfterOpenBracketBreak.InIfConditionalStatements;
+    if (IsOtherConditional(*Tok.Previous))
+      return Style.AlignAfterOpenBracketBreak.InOtherConditionalStatements;
+    return !Tok.Previous->is(TT_CastRParen) &&
+           Style.AlignAfterOpenBracketBreak.Other;
   };
   auto IsFunctionCallParen = [](const FormatToken &Tok) {
     return Tok.is(tok::l_paren) && Tok.ParameterCount > 0 && Tok.Previous &&
@@ -844,10 +849,15 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
          Tok.isOneOf(tok::ellipsis, Keywords.kw_await))) {
       return true;
     }
-    const auto *Previous = Tok.Previous;
-    if (!Previous || (!Previous->isOneOf(TT_FunctionDeclarationLParen,
-                                         TT_LambdaDefinitionLParen) &&
-                      !IsFunctionCallParen(*Previous))) {
+    const auto *Previous = TokAfterLParen.Previous;
+    assert(Previous); // IsOpeningBracket(Previous)
+    if (Previous->Previous && (Previous->Previous->isIf() ||
+                               IsOtherConditional(*Previous->Previous))) {
+      return false;
+    }
+    if (!Previous->isOneOf(TT_FunctionDeclarationLParen,
+                           TT_LambdaDefinitionLParen) &&
+        !IsFunctionCallParen(*Previous)) {
       return true;
     }
     if (IsOpeningBracket(Tok) || IsInTemplateString(Tok))
@@ -1225,8 +1235,21 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
   }
 
   if (PreviousNonComment && PreviousNonComment->is(tok::l_paren)) {
-    CurrentState.BreakBeforeClosingParen =
-        Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent;
+    CurrentState.BreakBeforeClosingParen = false;
+    if (Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent) {
+      auto Previous = PreviousNonComment->Previous;
+      if (Previous && Previous->isIf()) {
+        CurrentState.BreakBeforeClosingParen =
+            Style.AlignAfterOpenBracketBreak.InIfConditionalStatements;
+      } else if (Previous && Previous->isOneOf(tok::kw_for, tok::kw_while,
+                                               tok::kw_switch)) {
+        CurrentState.BreakBeforeClosingParen =
+            Style.AlignAfterOpenBracketBreak.InOtherConditionalStatements;
+      } else {
+        CurrentState.BreakBeforeClosingParen =
+            Style.AlignAfterOpenBracketBreak.Other;
+      }
+    }
   }
 
   if (CurrentState.AvoidBinPacking) {
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index d2463b892fbb96..79069cb1678c91 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -216,6 +216,16 @@ template <> struct ScalarEnumerationTraits<FormatStyle::BracketAlignmentStyle> {
   }
 };
 
+template <> struct MappingTraits<FormatStyle::AlignAfterOpenBracketCustom> {
+  static void mapping(IO &IO, FormatStyle::AlignAfterOpenBracketCustom &Value) {
+    IO.mapOptional("InIfConditionalStatements",
+                   Value.InIfConditionalStatements);
+    IO.mapOptional("InOtherConditionalStatements",
+                   Value.InOtherConditionalStatements);
+    IO.mapOptional("Other", Value.Other);
+  }
+};
+
 template <>
 struct ScalarEnumerationTraits<
     FormatStyle::BraceWrappingAfterControlStatementStyle> {
@@ -922,6 +932,8 @@ template <> struct MappingTraits<FormatStyle> {
 
     IO.mapOptional("AccessModifierOffset", Style.AccessModifierOffset);
     IO.mapOptional("AlignAfterOpenBracket", Style.AlignAfterOpenBracket);
+    IO.mapOptional("AlignAfterOpenBracketBreak",
+                   Style.AlignAfterOpenBracketBreak);
     IO.mapOptional("AlignArrayOfStructures", Style.AlignArrayOfStructures);
     IO.mapOptional("AlignConsecutiveAssignments",
                    Style.AlignConsecutiveAssignments);
@@ -1155,6 +1167,18 @@ template <> struct MappingTraits<FormatStyle> {
     IO.mapOptional("WhitespaceSensitiveMacros",
                    Style.WhitespaceSensitiveMacros);
 
+    // If AlignAfterOpenBracket was specified but AlignAfterOpenBracketBreak
+    // was not, initialize the latter for backwards compatibility.
+    if ((Style.AlignAfterOpenBracket == FormatStyle::BAS_AlwaysBreak ||
+         Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent) &&
+        Style.AlignAfterOpenBracketBreak ==
+            FormatStyle::AlignAfterOpenBracketCustom()) {
+      if (Style.AlignAfterOpenBracket == FormatStyle::BAS_AlwaysBreak)
+        Style.AlignAfterOpenBracketBreak.InIfConditionalStatements = true;
+      Style.AlignAfterOpenBracketBreak.InOtherConditionalStatements = false;
+      Style.AlignAfterOpenBracketBreak.Other = true;
+    }
+
     // If AlwaysBreakAfterDefinitionReturnType was specified but
     // BreakAfterReturnType was not, initialize the latter from the former for
     // backwards compatibility.
@@ -1438,6 +1462,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
   FormatStyle LLVMStyle;
   LLVMStyle.AccessModifierOffset = -2;
   LLVMStyle.AlignAfterOpenBracket = FormatStyle::BAS_Align;
+  LLVMStyle.AlignAfterOpenBracketBreak = {};
   LLVMStyle.AlignArrayOfStructures = FormatStyle::AIAS_None;
   LLVMStyle.AlignConsecutiveAssignments = {};
   LLVMStyle.AlignConsecutiveAssignments.AcrossComments = false;
@@ -1750,6 +1775,7 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
     GoogleStyle.SpacesBeforeTrailingComments = 1;
   } else if (Language == FormatStyle::LK_JavaScript) {
     GoogleStyle.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
+    GoogleStyle.AlignAfterOpenBracketBreak = {true, false, true};
     GoogleStyle.AlignOperands = FormatStyle::OAS_DontAlign;
     GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
     // TODO: still under discussion whether to switch to SLS_All.
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index dfa703aed0d34d..caa840f461da8f 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -6259,7 +6259,13 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
     if (Next && Next->is(tok::l_paren))
       return false;
     const FormatToken *Previous = Right.MatchingParen->Previous;
-    return !(Previous && (Previous->is(tok::kw_for) || Previous->isIf()));
+    if (!Previous)
+      return true;
+    if (Previous->isOneOf(tok::kw_for, tok::kw_while, tok::kw_switch))
+      return Style.AlignAfterOpenBracketBreak.InOtherConditionalStatements;
+    if (Previous->isIf())
+      return Style.AlignAfterOpenBracketBreak.InIfConditionalStatements;
+    return Style.AlignAfterOpenBracketBreak.Other;
   }
 
   if (Left.isOneOf(tok::r_paren, TT_TrailingAnnotation) &&
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index b8bdfaaa74e10e..c46a3e277e9134 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -203,6 +203,11 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
   CHECK_PARSE_BOOL(SpaceBeforeSquareBrackets);
   CHECK_PARSE_BOOL(VerilogBreakBetweenInstancePorts);
 
+  CHECK_PARSE_NESTED_BOOL(AlignAfterOpenBracketBreak,
+                          InIfConditionalStatements);
+  CHECK_PARSE_NESTED_BOOL(AlignAfterOpenBracketBreak,
+                          InOtherConditionalStatements);
+  CHECK_PARSE_NESTED_BOOL(AlignAfterOpenBracketBreak, Other);
   CHECK_PARSE_NESTED_BOOL(AlignConsecutiveShortCaseStatements, Enabled);
   CHECK_PARSE_NESTED_BOOL(AlignConsecutiveShortCaseStatements,
                           AcrossEmptyLines);
@@ -500,6 +505,13 @@ TEST(ConfigParseTest, ParsesConfiguration) {
               FormatStyle::BAS_DontAlign);
   CHECK_PARSE("AlignAfterOpenBracket: true", AlignAfterOpenBracket,
               FormatStyle::BAS_Align);
+  Style.AlignAfterOpenBracket = FormatStyle::BAS_Align;
+  Style.AlignAfterOpenBracketBreak = {};
+  CHECK_PARSE("AlignAfterOpenBracket: AlwaysBreak", AlignAfterOpenBracketBreak,
+              FormatStyle::AlignAfterOpenBracketCustom(true, false, true));
+  Style.AlignAfterOpenBracketBreak = {};
+  CHECK_PARSE("AlignAfterOpenBracket: BlockIndent", AlignAfterOpenBracketBreak,
+              FormatStyle::AlignAfterOpenBracketCustom(false, false, true));
 
   Style.AlignEscapedNewlines = FormatStyle::ENAS_Left;
   CHECK_PARSE("AlignEscapedNewlines: DontAlign", AlignEscapedNewlines,
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 5ebf0d7068dd6c..641b685127f2e4 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -5072,6 +5072,7 @@ TEST_F(FormatTest, BracedInitializerIndentWidth) {
   auto Style = getLLVMStyleWithColumns(60);
   Style.BinPackArguments = true;
   Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
+  Style.AlignAfterOpenBracketBreak = {true, false, true};
   Style.BracedInitializerIndentWidth = 6;
 
   // Non-initializing braces are unaffected by BracedInitializerIndentWidth.
@@ -7320,6 +7321,7 @@ TEST_F(FormatTest, ExpressionIndentationBreakingBeforeOperators) {
   Style = getLLVMStyleWithColumns(20);
   Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
   Style.BinPackParameters = FormatStyle::BPPS_OnePerLine;
+  Style.AlignAfterOpenBracketBreak = {true, false, true};
   Style.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment;
   Style.ContinuationIndentWidth = 2;
   verifyFormat("struct Foo {\n"
@@ -7989,12 +7991,14 @@ TEST_F(FormatTest, AllowAllArgumentsOnNextLineDontAlign) {
   // However, BAS_AlwaysBreak and BAS_BlockIndent should take precedence over
   // AllowAllArgumentsOnNextLine.
   Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
+  Style.AlignAfterOpenBracketBreak = {true, false, true};
   verifyFormat(StringRef("functionCall(\n"
                          "    paramA, paramB, paramC);\n"
                          "void functionDecl(\n"
                          "    int A, int B, int C);"),
                Input, Style);
   Style.AlignAfterOpenBracket = FormatStyle::BAS_BlockIndent;
+  Style.AlignAfterOpenBracketBreak = {false, false, true};
   verifyFormat("functionCall(\n"
                "    paramA, paramB, paramC\n"
                ");\n"
@@ -8007,6 +8011,7 @@ TEST_F(FormatTest, AllowAllArgumentsOnNextLineDontAlign) {
   // first argument.
   Style.AllowAllArgumentsOnNextLine = true;
   Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
+  Style.AlignAfterOpenBracketBreak = {true, false, true};
   verifyFormat(StringRef("functionCall(\n"
                          "    paramA, paramB, paramC);\n"
                          "void functionDecl(\n"
@@ -8928,6 +8933,7 @@ TEST_F(FormatTest, FormatsOneParameterPerLineIfNecessary) {
 TEST_F(FormatTest, FormatsDeclarationBreakAlways) {
   FormatStyle BreakAlways = getGoogleStyle();
   BreakAlways.BinPackParameters = FormatStyle::BPPS_AlwaysOnePerLine;
+  BreakAlways.AlignAfterOpenBracketBreak = {true, false, true};
   verifyFormat("void f(int a,\n"
                "       int b);",
                BreakAlways);
@@ -8956,6 +8962,7 @@ TEST_F(FormatTest, FormatsDeclarationBreakAlways) {
 TEST_F(FormatTest, FormatsDefinitionBreakAlways) {
   FormatStyle BreakAlways = getGoogleStyle();
   BreakAlways.BinPackParameters = FormatStyle::BPPS_AlwaysOnePerLine;
+  BreakAlways.AlignAfterOpenBracketBreak = {true, false, true};
   verifyFormat("void f(int a,\n"
                "       int b) {\n"
                "  f(a, b);\n"
@@ -9346,6 +9353,7 @@ TEST_F(FormatTest, AlignsAfterOpenBracket) {
   Style.ColumnLimit = 80;
 
   Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
+  Style.AlignAfterOpenBracketBreak = {true, false, true};
   Style.BinPackArguments = false;
   Style.BinPackParameters = FormatStyle::BPPS_OnePerLine;
   verifyFormat("void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
@@ -9397,6 +9405,7 @@ TEST_F(FormatTest, AlignsAfterOpenBracket) {
       Style);
 
   Style.AlignAfterOpenBracket = FormatStyle::BAS_BlockIndent;
+  Style.AlignAfterOpenBracketBreak = {false, false, true};
   Style.BinPackArguments = false;
   Style.BinPackParameters = FormatStyle::BPPS_OnePerLine;
   verifyFormat("void aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
@@ -9490,6 +9499,127 @@ TEST_F(FormatTest, ParenthesesAndOperandAlignment) {
                Style);
 }
 
+TEST_F(FormatTest, AlignAfterOpenBracketBreakConditionalStatements) {
+  FormatStyle Style = getLLVMStyle();
+  Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
+  Style.BinPackArguments = false;
+  Style.BinPackParameters = FormatStyle::BPPS_OnePerLine;
+  Style.AlignAfterOpenBracketBreak = {true, true, false};
+
+  verifyFormat(
+      "aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaa(\n"
+      "                             aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaa)) &&\n"
+      "                         aaaaaaaaaaaaaaaa);",
+      Style);
+
+  verifyFormat("void foo() {\n"
+               "  if constexpr (\n"
+               "      (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n"
+               "       bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+               ") == 0) {\n"
+               "    return;\n"
+               "  } else if (\n"
+               "      (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &\n"
+               "       bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+               ") == 0) {\n"
+               "    return;\n"
+               "  }\n"
+               "}",
+               Style);
+
+  verifyFormat("void foo() {\n"
+               "  switch (\n"
+               "      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n"
+               "      bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n"
+               "  default:\n"
+               "    break;\n"
+               "  }\n"
+               "}",
+               Style);
+
+  verifyFormat("void foo() {\n"
+               "  for (\n"
+               "      aaaaaaaaaaaaaaaaaaaaaa = 0;\n"
+               "      (aaaaaaaaaaaaaaaaaaaaaa->bbbbbbbbbbbbbb |\n"
+               "       aaaaaaaaaaaaaaaaaaaaaa->ccccccccccccccccccccccc) == 0;\n"
+               "      aaaaaaaaaaaaaaaaaaaaa = aaaaaaaaaaaaaaaaaaaaaa->next) {\n"
+               "    ;\n"
+               "  }\n"
+               "}",
+               Style);
+
+  verifyFormat("void foo() {\n"
+               "  while (\n"
+               "      (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n"
+               "       bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) == 0) "
+               "{\n"
+               "    continue;\n"
+               "  }\n"
+               "}",
+               Style);
+
+  Style.AlignAfterOpenBracket = FormatStyle::BAS_BlockIndent;
+  Style.BinPackArguments = false;
+  Style.BinPackParameters = FormatStyle::BPPS_OnePerLine;
+  Style.AlignAfterOpenBracketBreak = {true, true, false};
+
+  verifyFormat(
+      "aaaaaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaaaaaaa(\n"
+      "                             aaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaa)) &&\n"
+      "                         aaaaaaaaaaaaaaaa);",
+      Style);
+
+  verifyFormat("void foo() {\n"
+               "  if constexpr (\n"
+               "      (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n"
+               "       bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+               ") == 0\n"
+               "  ) {\n"
+               "    return;\n"
+               "  } else if (\n"
+               "      (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &\n"
+               "       bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
+               ") == 0\n"
+               "  ) {\n"
+               "    return;\n"
+               "  }\n"
+               "}",
+               Style);
+
+  verifyFormat("void foo() {\n"
+               "  switch (\n"
+               "      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | "
+               "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"
+               "  ) {\n"
+               "  default:\n"
+               "    break;\n"
+               "  }\n"
+               "}",
+               Style);
+
+  verifyFormat("void foo() {\n"
+               "  for (\n"
+               "      aaaaaaaaaaaaaaaaaaaaaa = 0;\n"
+               "      (aaaaaaaaaaaaaaaaaaaaaa->bbbbbbbbbbbbbb |\n"
+               "       aaaaaaaaaaaaaaaaaaaaaa->ccccccccccccccccccccccc) == 0;\n"
+               "      aaaaaaaaaaaaaaaaaaaaa = aaaaaaaaaaaaaaaaaaaaaa->next\n"
+               "  ) {\n"
+               "    ;\n"
+               "  }\n"
+               "}",
+               Style);
+
+  verifyFormat("void foo() {\n"
+               "  while (\n"
+               "      (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |\n"
+               "       bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) == 0\n"
+               "  ) {\n"
+               "    continue;\n"
+               "  }\n"
+               "}",
+               Style);
+}
+
 TEST_F(FormatTest, BreaksConditionalExpressions) {
   verifyFormat(
       "aaaa(aaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaa\n"
@@ -11091,6 +11221,7 @@ TEST_F(FormatTest, WrapsTemplateParameters) {
       "    y;",
       Style);
   Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
+  Style.AlignAfterOpenBracketBreak = {true, false, true};
   Style.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
   verifyFormat("template <typename... a> struct s {};\n"
                "extern s<\n"
@@ -11101,6 +11232,7 @@ TEST_F(FormatTest, WrapsTemplateParameters) {
                "    y;",
                Style);
   Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
+  Style.AlignAfterOpenBracketBreak = {true, false, true};
   Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
   verifyFormat("template <typename... a> struct t {};\n"
                "extern t<\n"
@@ -14034,6 +14166,7 @@ TEST_F(FormatTest, LayoutCxx11BraceInitializers) {
       NoBinPacking);
 
   NoBinPacking.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
+  NoBinPacking.AlignAfterOpenBracketBreak = {true, false, true};
   verifyFormat("static uint8 CddDp83848Reg[] = {\n"
                "    CDDDP83848_BMCR_REGISTER,\n"
                "    CDDDP83848_BMSR_REGISTER,\n"
@@ -15675,12 +15808,14 @@ TEST_F(FormatTest, BreaksStringLiteralOperands) {
   // the first must be broken with a line break before it.
   FormatStyle Style = getLLVMStyleWithColumns(25);
   Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
+  Style.AlignAfterOpenBracketBreak = {true, false, true};
   verifyFormat("someFunction(\n"
                "    \"long long long \"\n"
                "    \"long\",\n"
                "    a);",
                "someFunction(\"long long long long\", a);", Style);
   Style.AlignAfterOpenBracket = FormatStyle::BAS_BlockIndent;
+  Style.AlignAfterOpenBracketBreak = {false, false, true};
   verifyFormat("someFunction(\n"
                "    \"long long long \"\n"
                "    \"long\",\n"
@@ -17458,6 +17593,7 @@ TEST_F(FormatTest, ConfigurableSpacesInParens) {
   Spaces.ColumnLimit = 80;
   Spaces.IndentWidth = 4;
   Spaces.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
+  Spaces.AlignAfterOpenBracketBreak = {true, false, true};
   verifyFormat("void foo( ) {\n"
                "    size_t foo = (*(function))(\n"
                "        Foooo, Barrrrr, Foooo, Barrrr, FoooooooooLooooong, "
@@ -17483,6 +17619,7 @@ TEST_F(FormatTest, ConfigurableSpacesInParens) {
                Spaces);
 
   Spaces.AlignAfterOpenBracket = FormatStyle::BAS_BlockIndent;
+  Spaces.AlignAfterOpenBracketBreak = {false, false, true};
   verifyFormat("void foo( ) {\n"
                "    size_t foo = (*(function))(\n"
                "        Foooo, Barrrrr, Foooo, Barrrr, FoooooooooLooooong, "
@@ -22361,6 +22498,7 @@ TEST_F(FormatTest, ConstructorInitializerIndentWidth) {
       "  aaaaaaaaaaaaa(aaaaaaaaaaaaaa) {}",
       Style);
   Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
+  Style.AlignAfterOpenBracketBreak = {true, false, true};
   verifyFormat(
       "SomeLongTemplateVariableName<\n"
       "    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa>",
@@ -23615,6 +23753,7 @@ TEST_F(FormatTest, FormatsLambdas) {
                "    }} {}",
                Style);
   Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
+  Style.AlignAfterOpenBracketBreak = {true, false, true};
   // FIXME: The following test should pass, but fails at the time of writing.
 #if 0
   // As long as all the non-lambda arguments fit on a single line, AlwaysBreak
@@ -26803,6 +26942,7 @@ TEST_F(FormatTest, AlignAfterOpenBracketBlockIndent) {
                Style);
 
   Style.AlignAfterOpenBracket = FormatStyle::BAS_BlockIndent;
+  Style.AlignAfterOpenBracketBreak = {false, false, true};
 
   verifyFormat(Short, Style);
   verifyFormat(
@@ -26927,6 +27067,7 @@ TEST_F(FormatTest, AlignAfterOpenBracketBlockIndentIfStatement) {
                Style);
 
   Style.AlignAfterOpenBracket = FormatStyle::BAS_BlockIndent;
+  Style.AlignAfterOpenBracketBreak = {false, false, true};
 
   verifyFormat("if (foo()) {\n"
                "  return;\n"
@@ -26989,6 +27130,7 @@ TEST_F(FormatTest, AlignAfterOpenBracketBlockIndentForStatement) {
                Style);
 
   Style.AlignAfterOpenBracket = FormatStyle::BAS_BlockIndent;
+  Style.AlignAfterOpenBracketBreak = {false, false, true};
 
   verifyFormat("for (int i = 0; i < 5; ++i) {\n"
                "  doSomething();\n"
@@ -27006,6 +27148,7 @@ TEST_F(FormatTest, AlignAfterOpenBracketBlockIndentForStatement) {
 TEST_F(FormatTest, AlignAfterOpenBracketBlockIndentInitializers) {
   auto Style = getLLVMStyleWithColumns(60);
   Style.AlignAfterOpenBracket = FormatStyle::BAS_BlockIndent;
+  Style.AlignAfterOpenBracketBreak = {false, false, true};
   // Aggregate initialization.
   verifyFormat("int LooooooooooooooooooooooooongVariable[2] = {\n"
                "    10000000, 20000000\n"

>From d37d461a6e328b151e603eff899e5cd5194ede31 Mon Sep 17 00:00:00 2001
From: Gedare Bloom <gedare at rtems.org>
Date: Wed, 11 Sep 2024 22:48:12 -0600
Subject: [PATCH 2/2] Update release notes

---
 clang/docs/ReleaseNotes.rst | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 9860b25f2e7fa6..2141f6b2ad1d41 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -502,6 +502,8 @@ clang-format
 ------------
 
 - Adds ``BreakBinaryOperations`` option.
+- Adds ``AlignAfterOpenBracketBreak`` sub-options for better control of
+  ``AlignAfterOpenBracket`` with ``AlwaysBreak`` or ``BlockIndent`` modes.
 
 libclang
 --------



More information about the cfe-commits mailing list