Skip to content

Commit 84e3fdf

Browse files
[clang-format] BreakBeforeNoexceptSpecifier option added (#65808)
It really bugs me that it breaks to ``` c++ ...) noexcept( noexcept(condition)... ``` This is a fix for people like me.
1 parent 6a08cf1 commit 84e3fdf

File tree

7 files changed

+171
-0
lines changed

7 files changed

+171
-0
lines changed

clang/docs/ClangFormatStyleOptions.rst

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,6 +1108,54 @@ the configuration (without a prefix: ``Auto``).
11081108
int d,
11091109
int e);
11101110

1111+
.. _AllowBreakBeforeNoexceptSpecifier:
1112+
1113+
**AllowBreakBeforeNoexceptSpecifier** (``BreakBeforeNoexceptSpecifierStyle``) :versionbadge:`clang-format 18` :ref:`<AllowBreakBeforeNoexceptSpecifier>`
1114+
Controls if there could be a line break before a ``noexcept`` specifier.
1115+
1116+
Possible values:
1117+
1118+
* ``BBNSS_Never`` (in configuration: ``Never``)
1119+
No line break allowed.
1120+
1121+
.. code-block:: c++
1122+
1123+
void foo(int arg1,
1124+
double arg2) noexcept;
1125+
1126+
void bar(int arg1, double arg2) noexcept(
1127+
noexcept(baz(arg1)) &&
1128+
noexcept(baz(arg2)));
1129+
1130+
* ``BBNSS_OnlyWithParen`` (in configuration: ``OnlyWithParen``)
1131+
For a simple ``noexcept`` there is no line break allowed, but when we
1132+
have a condition it is.
1133+
1134+
.. code-block:: c++
1135+
1136+
void foo(int arg1,
1137+
double arg2) noexcept;
1138+
1139+
void bar(int arg1, double arg2)
1140+
noexcept(noexcept(baz(arg1)) &&
1141+
noexcept(baz(arg2)));
1142+
1143+
* ``BBNSS_Always`` (in configuration: ``Always``)
1144+
Line breaks are allowed. But note that because of the associated
1145+
penalties ``clang-format`` often prefers not to break before the
1146+
``noexcept``.
1147+
1148+
.. code-block:: c++
1149+
1150+
void foo(int arg1,
1151+
double arg2) noexcept;
1152+
1153+
void bar(int arg1, double arg2)
1154+
noexcept(noexcept(baz(arg1)) &&
1155+
noexcept(baz(arg2)));
1156+
1157+
1158+
11111159
.. _AllowShortBlocksOnASingleLine:
11121160

11131161
**AllowShortBlocksOnASingleLine** (``ShortBlockStyle``) :versionbadge:`clang-format 3.5` :ref:`<AllowShortBlocksOnASingleLine>`

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ AST Matchers
389389

390390
clang-format
391391
------------
392+
- Add ``AllowBreakBeforeNoexceptSpecifier`` option.
392393

393394
libclang
394395
--------

clang/include/clang/Format/Format.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,47 @@ struct FormatStyle {
593593
/// \version 3.3
594594
bool AllowAllParametersOfDeclarationOnNextLine;
595595

596+
/// Different ways to break before a noexcept specifier.
597+
enum BreakBeforeNoexceptSpecifierStyle : int8_t {
598+
/// No line break allowed.
599+
/// \code
600+
/// void foo(int arg1,
601+
/// double arg2) noexcept;
602+
///
603+
/// void bar(int arg1, double arg2) noexcept(
604+
/// noexcept(baz(arg1)) &&
605+
/// noexcept(baz(arg2)));
606+
/// \endcode
607+
BBNSS_Never,
608+
/// For a simple ``noexcept`` there is no line break allowed, but when we
609+
/// have a condition it is.
610+
/// \code
611+
/// void foo(int arg1,
612+
/// double arg2) noexcept;
613+
///
614+
/// void bar(int arg1, double arg2)
615+
/// noexcept(noexcept(baz(arg1)) &&
616+
/// noexcept(baz(arg2)));
617+
/// \endcode
618+
BBNSS_OnlyWithParen,
619+
/// Line breaks are allowed. But note that because of the associated
620+
/// penalties ``clang-format`` often prefers not to break before the
621+
/// ``noexcept``.
622+
/// \code
623+
/// void foo(int arg1,
624+
/// double arg2) noexcept;
625+
///
626+
/// void bar(int arg1, double arg2)
627+
/// noexcept(noexcept(baz(arg1)) &&
628+
/// noexcept(baz(arg2)));
629+
/// \endcode
630+
BBNSS_Always,
631+
};
632+
633+
/// Controls if there could be a line break before a ``noexcept`` specifier.
634+
/// \version 18
635+
BreakBeforeNoexceptSpecifierStyle AllowBreakBeforeNoexceptSpecifier;
636+
596637
/// Different styles for merging short blocks containing at most one
597638
/// statement.
598639
enum ShortBlockStyle : int8_t {
@@ -4576,6 +4617,8 @@ struct FormatStyle {
45764617
AllowAllArgumentsOnNextLine == R.AllowAllArgumentsOnNextLine &&
45774618
AllowAllParametersOfDeclarationOnNextLine ==
45784619
R.AllowAllParametersOfDeclarationOnNextLine &&
4620+
AllowBreakBeforeNoexceptSpecifier ==
4621+
R.AllowBreakBeforeNoexceptSpecifier &&
45794622
AllowShortBlocksOnASingleLine == R.AllowShortBlocksOnASingleLine &&
45804623
AllowShortCaseLabelsOnASingleLine ==
45814624
R.AllowShortCaseLabelsOnASingleLine &&

clang/lib/Format/Format.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,16 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::RawStringFormat)
5959

6060
namespace llvm {
6161
namespace yaml {
62+
template <>
63+
struct ScalarEnumerationTraits<FormatStyle::BreakBeforeNoexceptSpecifierStyle> {
64+
static void enumeration(IO &IO,
65+
FormatStyle::BreakBeforeNoexceptSpecifierStyle &Value) {
66+
IO.enumCase(Value, "Never", FormatStyle::BBNSS_Never);
67+
IO.enumCase(Value, "OnlyWithParen", FormatStyle::BBNSS_OnlyWithParen);
68+
IO.enumCase(Value, "Always", FormatStyle::BBNSS_Always);
69+
}
70+
};
71+
6272
template <> struct MappingTraits<FormatStyle::AlignConsecutiveStyle> {
6373
static void enumInput(IO &IO, FormatStyle::AlignConsecutiveStyle &Value) {
6474
IO.enumCase(Value, "None",
@@ -260,6 +270,7 @@ struct ScalarEnumerationTraits<FormatStyle::BreakBeforeInlineASMColonStyle> {
260270
IO.enumCase(Value, "Always", FormatStyle::BBIAS_Always);
261271
}
262272
};
273+
263274
template <>
264275
struct ScalarEnumerationTraits<FormatStyle::BreakConstructorInitializersStyle> {
265276
static void
@@ -904,6 +915,8 @@ template <> struct MappingTraits<FormatStyle> {
904915
Style.AllowAllArgumentsOnNextLine);
905916
IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine",
906917
Style.AllowAllParametersOfDeclarationOnNextLine);
918+
IO.mapOptional("AllowBreakBeforeNoexceptSpecifier",
919+
Style.AllowBreakBeforeNoexceptSpecifier);
907920
IO.mapOptional("AllowShortBlocksOnASingleLine",
908921
Style.AllowShortBlocksOnASingleLine);
909922
IO.mapOptional("AllowShortCaseLabelsOnASingleLine",
@@ -1448,6 +1461,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
14481461
LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
14491462
LLVMStyle.BreakBeforeConceptDeclarations = FormatStyle::BBCDS_Always;
14501463
LLVMStyle.BreakBeforeInlineASMColon = FormatStyle::BBIAS_OnlyMultiline;
1464+
LLVMStyle.AllowBreakBeforeNoexceptSpecifier = FormatStyle::BBNSS_Never;
14511465
LLVMStyle.BreakBeforeTernaryOperators = true;
14521466
LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
14531467
LLVMStyle.BreakInheritanceList = FormatStyle::BILS_BeforeColon;

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5654,6 +5654,17 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
56545654
return !isItAnEmptyLambdaAllowed(Right, ShortLambdaOption);
56555655
}
56565656

5657+
if (Right.is(tok::kw_noexcept) && Right.is(TT_TrailingAnnotation)) {
5658+
switch (Style.AllowBreakBeforeNoexceptSpecifier) {
5659+
case FormatStyle::BBNSS_Never:
5660+
return false;
5661+
case FormatStyle::BBNSS_Always:
5662+
return true;
5663+
case FormatStyle::BBNSS_OnlyWithParen:
5664+
return Right.Next && Right.Next->is(tok::l_paren);
5665+
}
5666+
}
5667+
56575668
return Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace,
56585669
tok::kw_class, tok::kw_struct, tok::comment) ||
56595670
Right.isMemberAccess() ||

clang/unittests/Format/ConfigParseTest.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,14 @@ TEST(ConfigParseTest, ParsesConfiguration) {
953953
FormatStyle::RPS_ReturnStatement);
954954
CHECK_PARSE("RemoveParentheses: Leave", RemoveParentheses,
955955
FormatStyle::RPS_Leave);
956+
957+
CHECK_PARSE("AllowBreakBeforeNoexceptSpecifier: Always",
958+
AllowBreakBeforeNoexceptSpecifier, FormatStyle::BBNSS_Always);
959+
CHECK_PARSE("AllowBreakBeforeNoexceptSpecifier: OnlyWithParen",
960+
AllowBreakBeforeNoexceptSpecifier,
961+
FormatStyle::BBNSS_OnlyWithParen);
962+
CHECK_PARSE("AllowBreakBeforeNoexceptSpecifier: Never",
963+
AllowBreakBeforeNoexceptSpecifier, FormatStyle::BBNSS_Never);
956964
}
957965

958966
TEST(ConfigParseTest, ParsesConfigurationWithLanguages) {

clang/unittests/Format/FormatTest.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26239,6 +26239,52 @@ TEST_F(FormatTest, RemoveParentheses) {
2623926239
Style);
2624026240
}
2624126241

26242+
TEST_F(FormatTest, AllowBreakBeforeNoexceptSpecifier) {
26243+
auto Style = getLLVMStyleWithColumns(35);
26244+
26245+
EXPECT_EQ(Style.AllowBreakBeforeNoexceptSpecifier, FormatStyle::BBNSS_Never);
26246+
verifyFormat("void foo(int arg1,\n"
26247+
" double arg2) noexcept;",
26248+
Style);
26249+
26250+
// The following line does not fit within the 35 column limit, but that's what
26251+
// happens with no break allowed.
26252+
verifyFormat("void bar(int arg1, double arg2) noexcept(\n"
26253+
" noexcept(baz(arg1)) &&\n"
26254+
" noexcept(baz(arg2)));",
26255+
Style);
26256+
26257+
verifyFormat("void aVeryLongFunctionNameWithoutAnyArguments() noexcept;",
26258+
Style);
26259+
26260+
Style.AllowBreakBeforeNoexceptSpecifier = FormatStyle::BBNSS_Always;
26261+
verifyFormat("void foo(int arg1,\n"
26262+
" double arg2) noexcept;",
26263+
Style);
26264+
26265+
verifyFormat("void bar(int arg1, double arg2)\n"
26266+
" noexcept(noexcept(baz(arg1)) &&\n"
26267+
" noexcept(baz(arg2)));",
26268+
Style);
26269+
26270+
verifyFormat("void aVeryLongFunctionNameWithoutAnyArguments()\n"
26271+
" noexcept;",
26272+
Style);
26273+
26274+
Style.AllowBreakBeforeNoexceptSpecifier = FormatStyle::BBNSS_OnlyWithParen;
26275+
verifyFormat("void foo(int arg1,\n"
26276+
" double arg2) noexcept;",
26277+
Style);
26278+
26279+
verifyFormat("void bar(int arg1, double arg2)\n"
26280+
" noexcept(noexcept(baz(arg1)) &&\n"
26281+
" noexcept(baz(arg2)));",
26282+
Style);
26283+
26284+
verifyFormat("void aVeryLongFunctionNameWithoutAnyArguments() noexcept;",
26285+
Style);
26286+
}
26287+
2624226288
} // namespace
2624326289
} // namespace test
2624426290
} // namespace format

0 commit comments

Comments
 (0)