aboutsummaryrefslogtreecommitdiff
path: root/clang
diff options
context:
space:
mode:
authorOwen Pan <owenpiano@gmail.com>2024-02-07 20:24:44 -0800
committerGitHub <noreply@github.com>2024-02-07 20:24:44 -0800
commitd033799050b7bda70d80a933d5d99b7088a72a95 (patch)
tree086c70ef55d2f6736a73aa443451a2724dc901f6 /clang
parent05091aa3ac53a13d08c78882c0c2035e58a1b4c4 (diff)
downloadllvm-d033799050b7bda70d80a933d5d99b7088a72a95.zip
llvm-d033799050b7bda70d80a933d5d99b7088a72a95.tar.gz
llvm-d033799050b7bda70d80a933d5d99b7088a72a95.tar.bz2
[clang-format] Add Leave to AlwaysBreakTemplateDeclarations (#80569)
Closes #78067.
Diffstat (limited to 'clang')
-rw-r--r--clang/docs/ClangFormatStyleOptions.rst12
-rw-r--r--clang/include/clang/Format/Format.h10
-rw-r--r--clang/lib/Format/ContinuationIndenter.cpp5
-rw-r--r--clang/lib/Format/Format.cpp1
-rw-r--r--clang/lib/Format/TokenAnnotator.cpp10
-rw-r--r--clang/unittests/Format/ConfigParseTest.cpp2
-rw-r--r--clang/unittests/Format/FormatTest.cpp68
7 files changed, 105 insertions, 3 deletions
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index f86be2c..0a8cc18 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -1664,6 +1664,18 @@ the configuration (without a prefix: ``Auto``).
Possible values:
+ * ``BTDS_Leave`` (in configuration: ``Leave``)
+ Do not change the line breaking before the declaration.
+
+ .. code-block:: c++
+
+ template <typename T>
+ T foo() {
+ }
+ template <typename T> T foo(int aaaaaaaaaaaaaaaaaaaaa,
+ int bbbbbbbbbbbbbbbbbbbbb) {
+ }
+
* ``BTDS_No`` (in configuration: ``No``)
Do not force break before declaration.
``PenaltyBreakTemplateDeclaration`` is taken into account.
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 4153213..cb14d98 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -1031,6 +1031,16 @@ struct FormatStyle {
/// Different ways to break after the template declaration.
enum BreakTemplateDeclarationsStyle : int8_t {
+ /// Do not change the line breaking before the declaration.
+ /// \code
+ /// template <typename T>
+ /// T foo() {
+ /// }
+ /// template <typename T> T foo(int aaaaaaaaaaaaaaaaaaaaa,
+ /// int bbbbbbbbbbbbbbbbbbbbb) {
+ /// }
+ /// \endcode
+ BTDS_Leave,
/// Do not force break before declaration.
/// ``PenaltyBreakTemplateDeclaration`` is taken into account.
/// \code
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 671ae54..7fd04b2 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -569,7 +569,10 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
return true;
}
}
- return Style.AlwaysBreakTemplateDeclarations != FormatStyle::BTDS_No;
+ return Style.AlwaysBreakTemplateDeclarations != FormatStyle::BTDS_No &&
+ (Style.AlwaysBreakTemplateDeclarations !=
+ FormatStyle::BTDS_Leave ||
+ Current.NewlinesBefore > 0);
}
if (Previous.is(TT_FunctionAnnotationRParen) &&
State.Line->Type != LT_PreprocessorDirective) {
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 9c780cd..c5714af 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -296,6 +296,7 @@ template <>
struct ScalarEnumerationTraits<FormatStyle::BreakTemplateDeclarationsStyle> {
static void enumeration(IO &IO,
FormatStyle::BreakTemplateDeclarationsStyle &Value) {
+ IO.enumCase(Value, "Leave", FormatStyle::BTDS_Leave);
IO.enumCase(Value, "No", FormatStyle::BTDS_No);
IO.enumCase(Value, "MultiLine", FormatStyle::BTDS_MultiLine);
IO.enumCase(Value, "Yes", FormatStyle::BTDS_Yes);
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 7a62f5f..cec56fa 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -5184,7 +5184,9 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
// concept ...
if (Right.is(tok::kw_concept))
return Style.BreakBeforeConceptDeclarations == FormatStyle::BBCDS_Always;
- return Style.AlwaysBreakTemplateDeclarations == FormatStyle::BTDS_Yes;
+ return Style.AlwaysBreakTemplateDeclarations == FormatStyle::BTDS_Yes ||
+ (Style.AlwaysBreakTemplateDeclarations == FormatStyle::BTDS_Leave &&
+ Right.NewlinesBefore > 0);
}
if (Left.ClosesRequiresClause && Right.isNot(tok::semi)) {
switch (Style.RequiresClausePosition) {
@@ -5617,7 +5619,11 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
return Style.BreakBeforeConceptDeclarations != FormatStyle::BBCDS_Never;
if (Right.is(TT_RequiresClause))
return true;
- if (Left.ClosesTemplateDeclaration || Left.is(TT_FunctionAnnotationRParen))
+ if (Left.ClosesTemplateDeclaration) {
+ return Style.AlwaysBreakTemplateDeclarations != FormatStyle::BTDS_Leave ||
+ Right.NewlinesBefore > 0;
+ }
+ if (Left.is(TT_FunctionAnnotationRParen))
return true;
if (Left.ClosesRequiresClause)
return true;
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index 3f1fc893..7493b0a 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -695,6 +695,8 @@ TEST(ConfigParseTest, ParsesConfiguration) {
FormatStyle::RTBS_TopLevelDefinitions);
Style.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Yes;
+ CHECK_PARSE("AlwaysBreakTemplateDeclarations: Leave",
+ AlwaysBreakTemplateDeclarations, FormatStyle::BTDS_Leave);
CHECK_PARSE("AlwaysBreakTemplateDeclarations: No",
AlwaysBreakTemplateDeclarations, FormatStyle::BTDS_No);
CHECK_PARSE("AlwaysBreakTemplateDeclarations: MultiLine",
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 87a02a4..b1a2247 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -10697,6 +10697,74 @@ TEST_F(FormatTest, WrapsTemplateDeclarations) {
verifyFormat("template <typename T> void\nfoo(aaaaaaaaaaaaaaaaaaaaaaaaaa "
"bbbbbbbbbbbbbbbbbbbb) {}",
NeverBreak);
+
+ auto Style = getLLVMStyle();
+ Style.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Leave;
+
+ verifyNoChange("template <typename T>\n"
+ "class C {};",
+ Style);
+ verifyFormat("template <typename T> class C {};", Style);
+
+ verifyNoChange("template <typename T>\n"
+ "void f();",
+ Style);
+ verifyFormat("template <typename T> void f();", Style);
+
+ verifyNoChange("template <typename T>\n"
+ "void f() {}",
+ Style);
+ verifyFormat("template <typename T> void f() {}", Style);
+
+ verifyNoChange("template <typename T>\n"
+ "// T can be A, B or C.\n"
+ "struct C {};",
+ Style);
+ verifyFormat("template <typename T> // T can be A, B or C.\n"
+ "struct C {};",
+ Style);
+
+ verifyNoChange("template <typename T>\n"
+ "C(T) noexcept;",
+ Style);
+ verifyFormat("template <typename T> C(T) noexcept;", Style);
+
+ verifyNoChange("template <enum E>\n"
+ "class A {\n"
+ "public:\n"
+ " E *f();\n"
+ "};",
+ Style);
+ verifyFormat("template <enum E> class A {\n"
+ "public:\n"
+ " E *f();\n"
+ "};",
+ Style);
+
+ verifyNoChange("template <auto x>\n"
+ "constexpr int simple(int) {\n"
+ " char c;\n"
+ " return 1;\n"
+ "}",
+ Style);
+ verifyFormat("template <auto x> constexpr int simple(int) {\n"
+ " char c;\n"
+ " return 1;\n"
+ "}",
+ Style);
+
+ Style.RequiresClausePosition = FormatStyle::RCPS_WithPreceding;
+ verifyNoChange("template <auto x>\n"
+ "requires(x > 1)\n"
+ "constexpr int with_req(int) {\n"
+ " return 1;\n"
+ "}",
+ Style);
+ verifyFormat("template <auto x> requires(x > 1)\n"
+ "constexpr int with_req(int) {\n"
+ " return 1;\n"
+ "}",
+ Style);
}
TEST_F(FormatTest, WrapsTemplateDeclarationsWithComments) {