Skip to content

Commit d033799

Browse files
authored
[clang-format] Add Leave to AlwaysBreakTemplateDeclarations (#80569)
Closes #78067.
1 parent 05091aa commit d033799

File tree

7 files changed

+105
-3
lines changed

7 files changed

+105
-3
lines changed

clang/docs/ClangFormatStyleOptions.rst

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

16651665
Possible values:
16661666

1667+
* ``BTDS_Leave`` (in configuration: ``Leave``)
1668+
Do not change the line breaking before the declaration.
1669+
1670+
.. code-block:: c++
1671+
1672+
template <typename T>
1673+
T foo() {
1674+
}
1675+
template <typename T> T foo(int aaaaaaaaaaaaaaaaaaaaa,
1676+
int bbbbbbbbbbbbbbbbbbbbb) {
1677+
}
1678+
16671679
* ``BTDS_No`` (in configuration: ``No``)
16681680
Do not force break before declaration.
16691681
``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
@@ -1031,6 +1031,16 @@ struct FormatStyle {
10311031

10321032
/// Different ways to break after the template declaration.
10331033
enum BreakTemplateDeclarationsStyle : int8_t {
1034+
/// Do not change the line breaking before the declaration.
1035+
/// \code
1036+
/// template <typename T>
1037+
/// T foo() {
1038+
/// }
1039+
/// template <typename T> T foo(int aaaaaaaaaaaaaaaaaaaaa,
1040+
/// int bbbbbbbbbbbbbbbbbbbbb) {
1041+
/// }
1042+
/// \endcode
1043+
BTDS_Leave,
10341044
/// Do not force break before declaration.
10351045
/// ``PenaltyBreakTemplateDeclaration`` is taken into account.
10361046
/// \code

clang/lib/Format/ContinuationIndenter.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,10 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
569569
return true;
570570
}
571571
}
572-
return Style.AlwaysBreakTemplateDeclarations != FormatStyle::BTDS_No;
572+
return Style.AlwaysBreakTemplateDeclarations != FormatStyle::BTDS_No &&
573+
(Style.AlwaysBreakTemplateDeclarations !=
574+
FormatStyle::BTDS_Leave ||
575+
Current.NewlinesBefore > 0);
573576
}
574577
if (Previous.is(TT_FunctionAnnotationRParen) &&
575578
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: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5184,7 +5184,9 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
51845184
// concept ...
51855185
if (Right.is(tok::kw_concept))
51865186
return Style.BreakBeforeConceptDeclarations == FormatStyle::BBCDS_Always;
5187-
return Style.AlwaysBreakTemplateDeclarations == FormatStyle::BTDS_Yes;
5187+
return Style.AlwaysBreakTemplateDeclarations == FormatStyle::BTDS_Yes ||
5188+
(Style.AlwaysBreakTemplateDeclarations == FormatStyle::BTDS_Leave &&
5189+
Right.NewlinesBefore > 0);
51885190
}
51895191
if (Left.ClosesRequiresClause && Right.isNot(tok::semi)) {
51905192
switch (Style.RequiresClausePosition) {
@@ -5617,7 +5619,11 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
56175619
return Style.BreakBeforeConceptDeclarations != FormatStyle::BBCDS_Never;
56185620
if (Right.is(TT_RequiresClause))
56195621
return true;
5620-
if (Left.ClosesTemplateDeclaration || Left.is(TT_FunctionAnnotationRParen))
5622+
if (Left.ClosesTemplateDeclaration) {
5623+
return Style.AlwaysBreakTemplateDeclarations != FormatStyle::BTDS_Leave ||
5624+
Right.NewlinesBefore > 0;
5625+
}
5626+
if (Left.is(TT_FunctionAnnotationRParen))
56215627
return true;
56225628
if (Left.ClosesRequiresClause)
56235629
return true;

clang/unittests/Format/ConfigParseTest.cpp

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

697697
Style.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Yes;
698+
CHECK_PARSE("AlwaysBreakTemplateDeclarations: Leave",
699+
AlwaysBreakTemplateDeclarations, FormatStyle::BTDS_Leave);
698700
CHECK_PARSE("AlwaysBreakTemplateDeclarations: No",
699701
AlwaysBreakTemplateDeclarations, FormatStyle::BTDS_No);
700702
CHECK_PARSE("AlwaysBreakTemplateDeclarations: MultiLine",

clang/unittests/Format/FormatTest.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10697,6 +10697,74 @@ TEST_F(FormatTest, WrapsTemplateDeclarations) {
1069710697
verifyFormat("template <typename T> void\nfoo(aaaaaaaaaaaaaaaaaaaaaaaaaa "
1069810698
"bbbbbbbbbbbbbbbbbbbb) {}",
1069910699
NeverBreak);
10700+
10701+
auto Style = getLLVMStyle();
10702+
Style.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Leave;
10703+
10704+
verifyNoChange("template <typename T>\n"
10705+
"class C {};",
10706+
Style);
10707+
verifyFormat("template <typename T> class C {};", Style);
10708+
10709+
verifyNoChange("template <typename T>\n"
10710+
"void f();",
10711+
Style);
10712+
verifyFormat("template <typename T> void f();", Style);
10713+
10714+
verifyNoChange("template <typename T>\n"
10715+
"void f() {}",
10716+
Style);
10717+
verifyFormat("template <typename T> void f() {}", Style);
10718+
10719+
verifyNoChange("template <typename T>\n"
10720+
"// T can be A, B or C.\n"
10721+
"struct C {};",
10722+
Style);
10723+
verifyFormat("template <typename T> // T can be A, B or C.\n"
10724+
"struct C {};",
10725+
Style);
10726+
10727+
verifyNoChange("template <typename T>\n"
10728+
"C(T) noexcept;",
10729+
Style);
10730+
verifyFormat("template <typename T> C(T) noexcept;", Style);
10731+
10732+
verifyNoChange("template <enum E>\n"
10733+
"class A {\n"
10734+
"public:\n"
10735+
" E *f();\n"
10736+
"};",
10737+
Style);
10738+
verifyFormat("template <enum E> class A {\n"
10739+
"public:\n"
10740+
" E *f();\n"
10741+
"};",
10742+
Style);
10743+
10744+
verifyNoChange("template <auto x>\n"
10745+
"constexpr int simple(int) {\n"
10746+
" char c;\n"
10747+
" return 1;\n"
10748+
"}",
10749+
Style);
10750+
verifyFormat("template <auto x> constexpr int simple(int) {\n"
10751+
" char c;\n"
10752+
" return 1;\n"
10753+
"}",
10754+
Style);
10755+
10756+
Style.RequiresClausePosition = FormatStyle::RCPS_WithPreceding;
10757+
verifyNoChange("template <auto x>\n"
10758+
"requires(x > 1)\n"
10759+
"constexpr int with_req(int) {\n"
10760+
" return 1;\n"
10761+
"}",
10762+
Style);
10763+
verifyFormat("template <auto x> requires(x > 1)\n"
10764+
"constexpr int with_req(int) {\n"
10765+
" return 1;\n"
10766+
"}",
10767+
Style);
1070010768
}
1070110769

1070210770
TEST_F(FormatTest, WrapsTemplateDeclarationsWithComments) {

0 commit comments

Comments
 (0)