Skip to content

[clang-format] BreakBeforeNoexceptSpecifier option added #65808

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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>`
Expand Down
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ AST Matchers

clang-format
------------
- Add ``AllowBreakBeforeNoexceptSpecifier`` option.

libclang
--------
Expand Down
43 changes: 43 additions & 0 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -4576,6 +4617,8 @@ struct FormatStyle {
AllowAllArgumentsOnNextLine == R.AllowAllArgumentsOnNextLine &&
AllowAllParametersOfDeclarationOnNextLine ==
R.AllowAllParametersOfDeclarationOnNextLine &&
AllowBreakBeforeNoexceptSpecifier ==
R.AllowBreakBeforeNoexceptSpecifier &&
AllowShortBlocksOnASingleLine == R.AllowShortBlocksOnASingleLine &&
AllowShortCaseLabelsOnASingleLine ==
R.AllowShortCaseLabelsOnASingleLine &&
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -260,6 +270,7 @@ struct ScalarEnumerationTraits<FormatStyle::BreakBeforeInlineASMColonStyle> {
IO.enumCase(Value, "Always", FormatStyle::BBIAS_Always);
}
};

template <>
struct ScalarEnumerationTraits<FormatStyle::BreakConstructorInitializersStyle> {
static void
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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;
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() ||
Expand Down
8 changes: 8 additions & 0 deletions clang/unittests/Format/ConfigParseTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
46 changes: 46 additions & 0 deletions clang/unittests/Format/FormatTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26211,6 +26211,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
Expand Down