[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.
This commit is contained in:
Björn Schäpers
2023-09-09 22:31:58 +02:00
committed by GitHub
parent 6a08cf12d9
commit 84e3fdfc65
7 changed files with 171 additions and 0 deletions

View File

@@ -1108,6 +1108,54 @@ the configuration (without a prefix: ``Auto``).
int d,
int e);
.. _AllowBreakBeforeNoexceptSpecifier:
**AllowBreakBeforeNoexceptSpecifier** (``BreakBeforeNoexceptSpecifierStyle``) :versionbadge:`clang-format 18` :ref:`¶ <AllowBreakBeforeNoexceptSpecifier>`
Controls if there could be a line break before a ``noexcept`` specifier.
Possible values:
* ``BBNSS_Never`` (in configuration: ``Never``)
No line break allowed.
.. code-block:: c++
void foo(int arg1,
double arg2) noexcept;
void bar(int arg1, double arg2) noexcept(
noexcept(baz(arg1)) &&
noexcept(baz(arg2)));
* ``BBNSS_OnlyWithParen`` (in configuration: ``OnlyWithParen``)
For a simple ``noexcept`` there is no line break allowed, but when we
have a condition it is.
.. code-block:: c++
void foo(int arg1,
double arg2) noexcept;
void bar(int arg1, double arg2)
noexcept(noexcept(baz(arg1)) &&
noexcept(baz(arg2)));
* ``BBNSS_Always`` (in configuration: ``Always``)
Line breaks are allowed. But note that because of the associated
penalties ``clang-format`` often prefers not to break before the
``noexcept``.
.. code-block:: c++
void foo(int arg1,
double arg2) noexcept;
void bar(int arg1, double arg2)
noexcept(noexcept(baz(arg1)) &&
noexcept(baz(arg2)));
.. _AllowShortBlocksOnASingleLine:
**AllowShortBlocksOnASingleLine** (``ShortBlockStyle``) :versionbadge:`clang-format 3.5` :ref:`¶ <AllowShortBlocksOnASingleLine>`

View File

@@ -389,6 +389,7 @@ AST Matchers
clang-format
------------
- Add ``AllowBreakBeforeNoexceptSpecifier`` option.
libclang
--------

View File

@@ -593,6 +593,47 @@ struct FormatStyle {
/// \version 3.3
bool AllowAllParametersOfDeclarationOnNextLine;
/// Different ways to break before a noexcept specifier.
enum BreakBeforeNoexceptSpecifierStyle : int8_t {
/// No line break allowed.
/// \code
/// void foo(int arg1,
/// double arg2) noexcept;
///
/// void bar(int arg1, double arg2) noexcept(
/// noexcept(baz(arg1)) &&
/// noexcept(baz(arg2)));
/// \endcode
BBNSS_Never,
/// For a simple ``noexcept`` there is no line break allowed, but when we
/// have a condition it is.
/// \code
/// void foo(int arg1,
/// double arg2) noexcept;
///
/// void bar(int arg1, double arg2)
/// noexcept(noexcept(baz(arg1)) &&
/// noexcept(baz(arg2)));
/// \endcode
BBNSS_OnlyWithParen,
/// Line breaks are allowed. But note that because of the associated
/// penalties ``clang-format`` often prefers not to break before the
/// ``noexcept``.
/// \code
/// void foo(int arg1,
/// double arg2) noexcept;
///
/// void bar(int arg1, double arg2)
/// noexcept(noexcept(baz(arg1)) &&
/// noexcept(baz(arg2)));
/// \endcode
BBNSS_Always,
};
/// Controls if there could be a line break before a ``noexcept`` specifier.
/// \version 18
BreakBeforeNoexceptSpecifierStyle AllowBreakBeforeNoexceptSpecifier;
/// Different styles for merging short blocks containing at most one
/// statement.
enum ShortBlockStyle : int8_t {
@@ -4576,6 +4617,8 @@ struct FormatStyle {
AllowAllArgumentsOnNextLine == R.AllowAllArgumentsOnNextLine &&
AllowAllParametersOfDeclarationOnNextLine ==
R.AllowAllParametersOfDeclarationOnNextLine &&
AllowBreakBeforeNoexceptSpecifier ==
R.AllowBreakBeforeNoexceptSpecifier &&
AllowShortBlocksOnASingleLine == R.AllowShortBlocksOnASingleLine &&
AllowShortCaseLabelsOnASingleLine ==
R.AllowShortCaseLabelsOnASingleLine &&

View File

@@ -59,6 +59,16 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(clang::format::FormatStyle::RawStringFormat)
namespace llvm {
namespace yaml {
template <>
struct ScalarEnumerationTraits<FormatStyle::BreakBeforeNoexceptSpecifierStyle> {
static void enumeration(IO &IO,
FormatStyle::BreakBeforeNoexceptSpecifierStyle &Value) {
IO.enumCase(Value, "Never", FormatStyle::BBNSS_Never);
IO.enumCase(Value, "OnlyWithParen", FormatStyle::BBNSS_OnlyWithParen);
IO.enumCase(Value, "Always", FormatStyle::BBNSS_Always);
}
};
template <> struct MappingTraits<FormatStyle::AlignConsecutiveStyle> {
static void enumInput(IO &IO, FormatStyle::AlignConsecutiveStyle &Value) {
IO.enumCase(Value, "None",
@@ -260,6 +270,7 @@ struct ScalarEnumerationTraits<FormatStyle::BreakBeforeInlineASMColonStyle> {
IO.enumCase(Value, "Always", FormatStyle::BBIAS_Always);
}
};
template <>
struct ScalarEnumerationTraits<FormatStyle::BreakConstructorInitializersStyle> {
static void
@@ -904,6 +915,8 @@ template <> struct MappingTraits<FormatStyle> {
Style.AllowAllArgumentsOnNextLine);
IO.mapOptional("AllowAllParametersOfDeclarationOnNextLine",
Style.AllowAllParametersOfDeclarationOnNextLine);
IO.mapOptional("AllowBreakBeforeNoexceptSpecifier",
Style.AllowBreakBeforeNoexceptSpecifier);
IO.mapOptional("AllowShortBlocksOnASingleLine",
Style.AllowShortBlocksOnASingleLine);
IO.mapOptional("AllowShortCaseLabelsOnASingleLine",
@@ -1448,6 +1461,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
LLVMStyle.BreakBeforeConceptDeclarations = FormatStyle::BBCDS_Always;
LLVMStyle.BreakBeforeInlineASMColon = FormatStyle::BBIAS_OnlyMultiline;
LLVMStyle.AllowBreakBeforeNoexceptSpecifier = FormatStyle::BBNSS_Never;
LLVMStyle.BreakBeforeTernaryOperators = true;
LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
LLVMStyle.BreakInheritanceList = FormatStyle::BILS_BeforeColon;

View File

@@ -5654,6 +5654,17 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
return !isItAnEmptyLambdaAllowed(Right, ShortLambdaOption);
}
if (Right.is(tok::kw_noexcept) && Right.is(TT_TrailingAnnotation)) {
switch (Style.AllowBreakBeforeNoexceptSpecifier) {
case FormatStyle::BBNSS_Never:
return false;
case FormatStyle::BBNSS_Always:
return true;
case FormatStyle::BBNSS_OnlyWithParen:
return Right.Next && Right.Next->is(tok::l_paren);
}
}
return Left.isOneOf(tok::comma, tok::coloncolon, tok::semi, tok::l_brace,
tok::kw_class, tok::kw_struct, tok::comment) ||
Right.isMemberAccess() ||

View File

@@ -953,6 +953,14 @@ TEST(ConfigParseTest, ParsesConfiguration) {
FormatStyle::RPS_ReturnStatement);
CHECK_PARSE("RemoveParentheses: Leave", RemoveParentheses,
FormatStyle::RPS_Leave);
CHECK_PARSE("AllowBreakBeforeNoexceptSpecifier: Always",
AllowBreakBeforeNoexceptSpecifier, FormatStyle::BBNSS_Always);
CHECK_PARSE("AllowBreakBeforeNoexceptSpecifier: OnlyWithParen",
AllowBreakBeforeNoexceptSpecifier,
FormatStyle::BBNSS_OnlyWithParen);
CHECK_PARSE("AllowBreakBeforeNoexceptSpecifier: Never",
AllowBreakBeforeNoexceptSpecifier, FormatStyle::BBNSS_Never);
}
TEST(ConfigParseTest, ParsesConfigurationWithLanguages) {

View File

@@ -26239,6 +26239,52 @@ TEST_F(FormatTest, RemoveParentheses) {
Style);
}
TEST_F(FormatTest, AllowBreakBeforeNoexceptSpecifier) {
auto Style = getLLVMStyleWithColumns(35);
EXPECT_EQ(Style.AllowBreakBeforeNoexceptSpecifier, FormatStyle::BBNSS_Never);
verifyFormat("void foo(int arg1,\n"
" double arg2) noexcept;",
Style);
// The following line does not fit within the 35 column limit, but that's what
// happens with no break allowed.
verifyFormat("void bar(int arg1, double arg2) noexcept(\n"
" noexcept(baz(arg1)) &&\n"
" noexcept(baz(arg2)));",
Style);
verifyFormat("void aVeryLongFunctionNameWithoutAnyArguments() noexcept;",
Style);
Style.AllowBreakBeforeNoexceptSpecifier = FormatStyle::BBNSS_Always;
verifyFormat("void foo(int arg1,\n"
" double arg2) noexcept;",
Style);
verifyFormat("void bar(int arg1, double arg2)\n"
" noexcept(noexcept(baz(arg1)) &&\n"
" noexcept(baz(arg2)));",
Style);
verifyFormat("void aVeryLongFunctionNameWithoutAnyArguments()\n"
" noexcept;",
Style);
Style.AllowBreakBeforeNoexceptSpecifier = FormatStyle::BBNSS_OnlyWithParen;
verifyFormat("void foo(int arg1,\n"
" double arg2) noexcept;",
Style);
verifyFormat("void bar(int arg1, double arg2)\n"
" noexcept(noexcept(baz(arg1)) &&\n"
" noexcept(baz(arg2)));",
Style);
verifyFormat("void aVeryLongFunctionNameWithoutAnyArguments() noexcept;",
Style);
}
} // namespace
} // namespace test
} // namespace format