Skip to content

Commit 45b720c

Browse files
committed
[clang-format] Add Leave to AlwaysBreakTemplateDeclarations
Closes #78067.
1 parent 908fd09 commit 45b720c

File tree

7 files changed

+110
-2
lines changed

7 files changed

+110
-2
lines changed

clang/docs/ClangFormatStyleOptions.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1638,6 +1638,18 @@ the configuration (without a prefix: ``Auto``).
16381638

16391639
Possible values:
16401640

1641+
* ``BTDS_Leave`` (in configuration: ``Leave``)
1642+
Do not change the line breaking before the declaration.
1643+
1644+
.. code-block:: c++
1645+
1646+
template <typename T>
1647+
T foo() {
1648+
}
1649+
template <typename T> T foo(int aaaaaaaaaaaaaaaaaaaaa,
1650+
int bbbbbbbbbbbbbbbbbbbbb) {
1651+
}
1652+
16411653
* ``BTDS_No`` (in configuration: ``No``)
16421654
Do not force break before declaration.
16431655
``PenaltyBreakTemplateDeclaration`` is taken into account.

clang/include/clang/Format/Format.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,16 @@ struct FormatStyle {
10081008

10091009
/// Different ways to break after the template declaration.
10101010
enum BreakTemplateDeclarationsStyle : int8_t {
1011+
/// Do not change the line breaking before the declaration.
1012+
/// \code
1013+
/// template <typename T>
1014+
/// T foo() {
1015+
/// }
1016+
/// template <typename T> T foo(int aaaaaaaaaaaaaaaaaaaaa,
1017+
/// int bbbbbbbbbbbbbbbbbbbbb) {
1018+
/// }
1019+
/// \endcode
1020+
BTDS_Leave,
10111021
/// Do not force break before declaration.
10121022
/// ``PenaltyBreakTemplateDeclaration`` is taken into account.
10131023
/// \code

clang/lib/Format/ContinuationIndenter.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,10 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
561561
return true;
562562
}
563563
}
564-
return Style.AlwaysBreakTemplateDeclarations != FormatStyle::BTDS_No;
564+
return Style.AlwaysBreakTemplateDeclarations != FormatStyle::BTDS_No &&
565+
(Style.AlwaysBreakTemplateDeclarations !=
566+
FormatStyle::BTDS_Leave ||
567+
Current.NewlinesBefore > 0);
565568
}
566569
if (Previous.is(TT_FunctionAnnotationRParen) &&
567570
State.Line->Type != LT_PreprocessorDirective) {

clang/lib/Format/Format.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ template <>
296296
struct ScalarEnumerationTraits<FormatStyle::BreakTemplateDeclarationsStyle> {
297297
static void enumeration(IO &IO,
298298
FormatStyle::BreakTemplateDeclarationsStyle &Value) {
299+
IO.enumCase(Value, "Leave", FormatStyle::BTDS_Leave);
299300
IO.enumCase(Value, "No", FormatStyle::BTDS_No);
300301
IO.enumCase(Value, "MultiLine", FormatStyle::BTDS_MultiLine);
301302
IO.enumCase(Value, "Yes", FormatStyle::BTDS_Yes);

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5182,7 +5182,9 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
51825182
// concept ...
51835183
if (Right.is(tok::kw_concept))
51845184
return Style.BreakBeforeConceptDeclarations == FormatStyle::BBCDS_Always;
5185-
return Style.AlwaysBreakTemplateDeclarations == FormatStyle::BTDS_Yes;
5185+
return Style.AlwaysBreakTemplateDeclarations == FormatStyle::BTDS_Yes ||
5186+
(Style.AlwaysBreakTemplateDeclarations == FormatStyle::BTDS_Leave &&
5187+
Right.NewlinesBefore > 0);
51865188
}
51875189
if (Left.ClosesRequiresClause && Right.isNot(tok::semi)) {
51885190
switch (Style.RequiresClausePosition) {

clang/unittests/Format/ConfigParseTest.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,8 @@ TEST(ConfigParseTest, ParsesConfiguration) {
691691
FormatStyle::RTBS_TopLevelDefinitions);
692692

693693
Style.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Yes;
694+
CHECK_PARSE("AlwaysBreakTemplateDeclarations: Leave",
695+
AlwaysBreakTemplateDeclarations, FormatStyle::BTDS_Leave);
694696
CHECK_PARSE("AlwaysBreakTemplateDeclarations: No",
695697
AlwaysBreakTemplateDeclarations, FormatStyle::BTDS_No);
696698
CHECK_PARSE("AlwaysBreakTemplateDeclarations: MultiLine",

clang/unittests/Format/FormatTest.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10657,6 +10657,84 @@ TEST_F(FormatTest, WrapsTemplateDeclarations) {
1065710657
verifyFormat("template <typename T> void\nfoo(aaaaaaaaaaaaaaaaaaaaaaaaaa "
1065810658
"bbbbbbbbbbbbbbbbbbbb) {}",
1065910659
NeverBreak);
10660+
10661+
auto Style = getLLVMStyle();
10662+
Style.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Leave;
10663+
10664+
verifyNoChange("template <typename T>\n"
10665+
"class C {};",
10666+
Style);
10667+
verifyFormat("template <typename T> class C {};", Style);
10668+
10669+
verifyNoChange("template <typename T>\n"
10670+
"void f();",
10671+
Style);
10672+
verifyFormat("template <typename T> void f();", Style);
10673+
10674+
verifyNoChange("template <typename T>\n"
10675+
"void f() {}",
10676+
Style);
10677+
verifyFormat("template <typename T> void f() {}", Style);
10678+
10679+
verifyNoChange("template <typename T>\n"
10680+
"// T can be A, B or C.\n"
10681+
"struct C {};",
10682+
Style);
10683+
verifyFormat("template <typename T> // T can be A, B or C.\n"
10684+
"struct C {};",
10685+
Style);
10686+
10687+
verifyNoChange("template <typename T>\n"
10688+
"C(T) noexcept;",
10689+
Style);
10690+
verifyFormat("template <typename T> C(T) noexcept;", Style);
10691+
10692+
verifyNoChange("template <typename T>\n"
10693+
"ClassName(T) noexcept;",
10694+
Style);
10695+
verifyFormat("template <typename T> ClassName(T) noexcept;", Style);
10696+
10697+
verifyNoChange("template <typename T>\n"
10698+
"POOR_NAME(T) noexcept;",
10699+
Style);
10700+
verifyFormat("template <typename T> POOR_NAME(T) noexcept;", Style);
10701+
10702+
verifyNoChange("template <enum E>\n"
10703+
"class A {\n"
10704+
"public:\n"
10705+
" E *f();\n"
10706+
"};",
10707+
Style);
10708+
verifyFormat("template <enum E> class A {\n"
10709+
"public:\n"
10710+
" E *f();\n"
10711+
"};",
10712+
Style);
10713+
10714+
verifyNoChange("template <auto x>\n"
10715+
"constexpr int simple(int) {\n"
10716+
" char c;\n"
10717+
" return 1;\n"
10718+
"}",
10719+
Style);
10720+
verifyFormat("template <auto x> constexpr int simple(int) {\n"
10721+
" char c;\n"
10722+
" return 1;\n"
10723+
"}",
10724+
Style);
10725+
10726+
Style.RequiresClausePosition = FormatStyle::RCPS_WithPreceding;
10727+
verifyNoChange("template <auto x>\n"
10728+
"requires(x > 1)\n"
10729+
"constexpr int with_req(int) {\n"
10730+
" return 1;\n"
10731+
"}",
10732+
Style);
10733+
verifyFormat("template <auto x> requires(x > 1)\n"
10734+
"constexpr int with_req(int) {\n"
10735+
" return 1;\n"
10736+
"}",
10737+
Style);
1066010738
}
1066110739

1066210740
TEST_F(FormatTest, WrapsTemplateDeclarationsWithComments) {

0 commit comments

Comments
 (0)