Author: owenca
Date: 2026-03-18T23:14:38-07:00
New Revision: 79042e701b7bfd0fe3ffcd3a155c0c8f5b2e2eaa

URL: 
https://github.com/llvm/llvm-project/commit/79042e701b7bfd0fe3ffcd3a155c0c8f5b2e2eaa
DIFF: 
https://github.com/llvm/llvm-project/commit/79042e701b7bfd0fe3ffcd3a155c0c8f5b2e2eaa.diff

LOG: [clang-format] Add LeaveAll to the BreakAfterAttributes option (#187204)

Closes #163537

Added: 
    

Modified: 
    clang/docs/ClangFormatStyleOptions.rst
    clang/include/clang/Format/Format.h
    clang/lib/Format/Format.cpp
    clang/lib/Format/TokenAnnotator.cpp
    clang/lib/Format/TokenAnnotator.h
    clang/unittests/Format/ConfigParseTest.cpp
    clang/unittests/Format/FormatTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ClangFormatStyleOptions.rst 
b/clang/docs/ClangFormatStyleOptions.rst
index 342eb0bdb1279..05ebb997a41ae 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -2727,7 +2727,7 @@ the configuration (without a prefix: ``Auto``).
   Possible values:
 
   * ``ABS_Always`` (in configuration: ``Always``)
-    Always break after attributes.
+    Always break after the last attribute of the group.
 
     .. code-block:: c++
 
@@ -2758,7 +2758,7 @@ the configuration (without a prefix: ``Auto``).
       }
 
   * ``ABS_Leave`` (in configuration: ``Leave``)
-    Leave the line breaking after attributes as is.
+    Leave the line breaking after the last attribute of the group as is.
 
     .. code-block:: c++
 
@@ -2784,8 +2784,24 @@ the configuration (without a prefix: ``Auto``).
         return;
       }
 
+  * ``ABS_LeaveAll`` (in configuration: ``LeaveAll``)
+    Same as ``Leave`` except that it applies to all attributes of the group.
+
+    .. code-block:: c++
+
+      [[deprecated("Don't use this version")]]
+      [[nodiscard]]
+      bool foo() {
+        return true;
+      }
+
+      [[deprecated("Don't use this version")]]
+      [[nodiscard]] bool bar() {
+        return true;
+      }
+
   * ``ABS_Never`` (in configuration: ``Never``)
-    Never break after attributes.
+    Never break after the last attribute of the group.
 
     .. code-block:: c++
 

diff  --git a/clang/include/clang/Format/Format.h 
b/clang/include/clang/Format/Format.h
index 45369e2e142c2..e5bf3c08d350a 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -1717,9 +1717,10 @@ struct FormatStyle {
   /// \version 18
   bool BreakAdjacentStringLiterals;
 
-  /// Different ways to break after attributes.
+  /// Different ways to break after the last attribute of a group before a
+  /// declaration or control statement.
   enum AttributeBreakingStyle : int8_t {
-    /// Always break after attributes.
+    /// Always break after the last attribute of the group.
     /// \code
     ///   [[maybe_unused]]
     ///   const int i;
@@ -1748,7 +1749,7 @@ struct FormatStyle {
     ///   }
     /// \endcode
     ABS_Always,
-    /// Leave the line breaking after attributes as is.
+    /// Leave the line breaking after the last attribute of the group as is.
     /// \code
     ///   [[maybe_unused]] const int i;
     ///   [[gnu::const]] [[maybe_unused]]
@@ -1773,7 +1774,21 @@ struct FormatStyle {
     ///   }
     /// \endcode
     ABS_Leave,
-    /// Never break after attributes.
+    /// Same as ``Leave`` except that it applies to all attributes of the 
group.
+    /// \code
+    ///   [[deprecated("Don't use this version")]]
+    ///   [[nodiscard]]
+    ///   bool foo() {
+    ///     return true;
+    ///   }
+    ///
+    ///   [[deprecated("Don't use this version")]]
+    ///   [[nodiscard]] bool bar() {
+    ///     return true;
+    ///   }
+    /// \endcode
+    ABS_LeaveAll,
+    /// Never break after the last attribute of the group.
     /// \code
     ///   [[maybe_unused]] const int i;
     ///   [[gnu::const]] [[maybe_unused]] int j;

diff  --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 148124b190f4a..d6bff8e402cf1 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -121,6 +121,7 @@ struct 
ScalarEnumerationTraits<FormatStyle::AttributeBreakingStyle> {
   static void enumeration(IO &IO, FormatStyle::AttributeBreakingStyle &Value) {
     IO.enumCase(Value, "Always", FormatStyle::ABS_Always);
     IO.enumCase(Value, "Leave", FormatStyle::ABS_Leave);
+    IO.enumCase(Value, "LeaveAll", FormatStyle::ABS_LeaveAll);
     IO.enumCase(Value, "Never", FormatStyle::ABS_Never);
   }
 };

diff  --git a/clang/lib/Format/TokenAnnotator.cpp 
b/clang/lib/Format/TokenAnnotator.cpp
index c32822ce90d1f..55a6d1a9427f9 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -28,10 +28,10 @@ static bool mustBreakAfterAttributes(const FormatToken &Tok,
   switch (Style.BreakAfterAttributes) {
   case FormatStyle::ABS_Always:
     return true;
-  case FormatStyle::ABS_Leave:
-    return Tok.NewlinesBefore > 0;
-  default:
+  case FormatStyle::ABS_Never:
     return false;
+  default: // ABS_Leave and ABS_LeaveAll
+    return Tok.NewlinesBefore > 0;
   }
 }
 
@@ -4121,6 +4121,7 @@ void 
TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
     }
 
     if (!LineIsFunctionDeclaration) {
+      Line.ReturnTypeWrapped = false;
       // Annotate */&/&& in `operator` function calls as binary operators.
       for (const auto *Tok = FirstNonComment; Tok; Tok = Tok->Next) {
         if (Tok->isNot(tok::kw_operator))
@@ -5706,7 +5707,7 @@ static bool isAllmanLambdaBrace(const FormatToken &Tok) {
          Tok.isNoneOf(TT_ObjCBlockLBrace, TT_DictLiteral);
 }
 
-bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
+bool TokenAnnotator::mustBreakBefore(AnnotatedLine &Line,
                                      const FormatToken &Right) const {
   if (Right.NewlinesBefore > 1 && Style.MaxEmptyLinesToKeep > 0 &&
       (!Style.RemoveEmptyLinesInUnwrappedLines || &Right == Line.First)) {
@@ -6183,6 +6184,12 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine 
&Line,
       return true;
   }
 
+  if (Style.BreakAfterAttributes == FormatStyle::ABS_LeaveAll &&
+      Left.is(TT_AttributeRSquare) && Right.NewlinesBefore > 0) {
+    Line.ReturnTypeWrapped = true;
+    return true;
+  }
+
   return false;
 }
 

diff  --git a/clang/lib/Format/TokenAnnotator.h 
b/clang/lib/Format/TokenAnnotator.h
index e4b94431e68b4..597dd890ee990 100644
--- a/clang/lib/Format/TokenAnnotator.h
+++ b/clang/lib/Format/TokenAnnotator.h
@@ -247,8 +247,7 @@ class TokenAnnotator {
   bool spaceRequiredBefore(const AnnotatedLine &Line,
                            const FormatToken &Right) const;
 
-  bool mustBreakBefore(const AnnotatedLine &Line,
-                       const FormatToken &Right) const;
+  bool mustBreakBefore(AnnotatedLine &Line, const FormatToken &Right) const;
 
   bool canBreakBefore(const AnnotatedLine &Line,
                       const FormatToken &Right) const;

diff  --git a/clang/unittests/Format/ConfigParseTest.cpp 
b/clang/unittests/Format/ConfigParseTest.cpp
index f13c68c3002e2..a7b410f03abfe 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -1196,6 +1196,8 @@ TEST(ConfigParseTest, ParsesConfiguration) {
               FormatStyle::ABS_Always);
   CHECK_PARSE("BreakAfterAttributes: Leave", BreakAfterAttributes,
               FormatStyle::ABS_Leave);
+  CHECK_PARSE("BreakAfterAttributes: LeaveAll", BreakAfterAttributes,
+              FormatStyle::ABS_LeaveAll);
   CHECK_PARSE("BreakAfterAttributes: Never", BreakAfterAttributes,
               FormatStyle::ABS_Never);
 

diff  --git a/clang/unittests/Format/FormatTest.cpp 
b/clang/unittests/Format/FormatTest.cpp
index db01af9593b1a..53fe4eb2aae71 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -28321,6 +28321,19 @@ TEST_F(FormatTest, BreakAfterAttributes) {
   EXPECT_EQ(Style.BreakAfterAttributes, FormatStyle::ABS_Leave);
   verifyNoChange(Code, Style);
 
+  Style.BreakAfterAttributes = FormatStyle::ABS_LeaveAll;
+  verifyNoChange("[[deprecated(\"Don't use this version\")]]\n"
+                 "[[nodiscard]]\n"
+                 "bool foo() {\n"
+                 "  return true;\n"
+                 "}\n"
+                 "\n"
+                 "[[deprecated(\"Don't use this version\")]]\n"
+                 "[[nodiscard]] bool bar() {\n"
+                 "  return true;\n"
+                 "}",
+                 Style);
+
   Style.BreakAfterAttributes = FormatStyle::ABS_Never;
   verifyFormat("[[maybe_unused]] const int i;\n"
                "[[foo([[]])]] [[maybe_unused]] int j;\n"


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to