[clang] 79042e7 - [clang-format] Add LeaveAll to the BreakAfterAttributes option (#187204)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Mar 18 23:14:43 PDT 2026
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"
More information about the cfe-commits
mailing list