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
