[clang] [clang-format] BreakBeforeNoexceptSpecifier option added (PR #65808)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Sep 9 06:40:59 PDT 2023
=?utf-8?q?Björn_Schäpers?= <github at hazardy.de>
llvmbot wrote:
@llvm/pr-subscribers-clang-format
<details>
<summary>Changes</summary>
It really bugs me that it breaks to
``` c++
...) noexcept(
noexcept(condition)...
```
This is a fix for people like me.
--
Full diff: https://github.com/llvm/llvm-project/pull/65808.diff
7 Files Affected:
- (modified) clang/docs/ClangFormatStyleOptions.rst (+48)
- (modified) clang/docs/ReleaseNotes.rst (+1)
- (modified) clang/include/clang/Format/Format.h (+43)
- (modified) clang/lib/Format/Format.cpp (+14)
- (modified) clang/lib/Format/TokenAnnotator.cpp (+11)
- (modified) clang/unittests/Format/ConfigParseTest.cpp (+8)
- (modified) clang/unittests/Format/FormatTest.cpp (+46)
<pre>
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index df27f6166d37105..51e4b2661a9ea84 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -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. Bute note that because of the associtated
+ 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>`
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 28a6ec0acd409b0..5c1f7ae54ffe09d 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -374,6 +374,7 @@ AST Matchers
clang-format
------------
+- Add ``AllowBreakBeforeNoexceptSpecifier`` option.
libclang
--------
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 7ebde3c174d2640..e0444966b3eabc7 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -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 &&
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 339af30e38a7a8f..8e9be6752ce5870 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -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;
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 3e0599eb540a95f..2bb6565193cec83 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -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() ||
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index b3b6755cadee4ba..dedaf546ea5ff4f 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -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) {
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 721cf29e0db474f..642459b3a0e60f8 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -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
</pre>
</details>
https://github.com/llvm/llvm-project/pull/65808
More information about the cfe-commits
mailing list