Skip to content

Commit d2b45ce

Browse files
leijurvowenca
andauthored
[clang-format] Add BreakBeforeTemplateCloser option (llvm#118046)
In clang-format, multiline templates have the `>` on the same line as the last parameter: ```c++ template < typename Foo, typename Bar> void foo() { ``` I would like to add an option to put the `>` on the next line, like this: ```c++ template < typename Foo, typename Bar > void foo() { ``` An example of a large project that uses this style is NVIDIA's CUTLASS, here is an example: https://github.com/NVIDIA/cutlass/blob/main/include/cutlass/epilogue/dispatch_policy.hpp#L149-L156 My reasoning is that it reminds me of this style of braces: ```c++ if (foo()) { bar(); baz();} ``` Most people agree this is better: ```c++ if (foo()) { bar(); baz(); } ``` --------- Co-authored-by: Owen Pan <[email protected]>
1 parent 7ef33e6 commit d2b45ce

File tree

9 files changed

+328
-16
lines changed

9 files changed

+328
-16
lines changed

clang/docs/ClangFormatStyleOptions.rst

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3421,6 +3421,35 @@ the configuration (without a prefix: ``Auto``).
34213421

34223422

34233423

3424+
.. _BreakBeforeTemplateCloser:
3425+
3426+
**BreakBeforeTemplateCloser** (``Boolean``) :versionbadge:`clang-format 21` :ref:`<BreakBeforeTemplateCloser>`
3427+
If ``true``, break before a template closing bracket (``>``) when there is
3428+
a line break after the matching opening bracket (``<``).
3429+
3430+
.. code-block:: c++
3431+
3432+
true:
3433+
template <typename Foo, typename Bar>
3434+
3435+
template <typename Foo,
3436+
typename Bar>
3437+
3438+
template <
3439+
typename Foo,
3440+
typename Bar
3441+
>
3442+
3443+
false:
3444+
template <typename Foo, typename Bar>
3445+
3446+
template <typename Foo,
3447+
typename Bar>
3448+
3449+
template <
3450+
typename Foo,
3451+
typename Bar>
3452+
34243453
.. _BreakBeforeTernaryOperators:
34253454

34263455
**BreakBeforeTernaryOperators** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`<BreakBeforeTernaryOperators>`

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,8 @@ AST Matchers
231231
clang-format
232232
------------
233233

234+
- Adds ``BreakBeforeTemplateCloser`` option.
235+
234236
libclang
235237
--------
236238

clang/include/clang/Format/Format.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2252,6 +2252,33 @@ struct FormatStyle {
22522252
/// \version 16
22532253
BreakBeforeInlineASMColonStyle BreakBeforeInlineASMColon;
22542254

2255+
/// If ``true``, break before a template closing bracket (``>``) when there is
2256+
/// a line break after the matching opening bracket (``<``).
2257+
/// \code
2258+
/// true:
2259+
/// template <typename Foo, typename Bar>
2260+
///
2261+
/// template <typename Foo,
2262+
/// typename Bar>
2263+
///
2264+
/// template <
2265+
/// typename Foo,
2266+
/// typename Bar
2267+
/// >
2268+
///
2269+
/// false:
2270+
/// template <typename Foo, typename Bar>
2271+
///
2272+
/// template <typename Foo,
2273+
/// typename Bar>
2274+
///
2275+
/// template <
2276+
/// typename Foo,
2277+
/// typename Bar>
2278+
/// \endcode
2279+
/// \version 21
2280+
bool BreakBeforeTemplateCloser;
2281+
22552282
/// If ``true``, ternary operators will be placed after line breaks.
22562283
/// \code
22572284
/// true:
@@ -5251,6 +5278,7 @@ struct FormatStyle {
52515278
BreakBeforeBraces == R.BreakBeforeBraces &&
52525279
BreakBeforeConceptDeclarations == R.BreakBeforeConceptDeclarations &&
52535280
BreakBeforeInlineASMColon == R.BreakBeforeInlineASMColon &&
5281+
BreakBeforeTemplateCloser == R.BreakBeforeTemplateCloser &&
52545282
BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators &&
52555283
BreakBinaryOperations == R.BreakBinaryOperations &&
52565284
BreakConstructorInitializers == R.BreakConstructorInitializers &&

clang/lib/Format/ContinuationIndenter.cpp

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -349,19 +349,22 @@ bool ContinuationIndenter::canBreak(const LineState &State) {
349349
}
350350
}
351351

352+
// Don't allow breaking before a closing brace of a block-indented braced list
353+
// initializer if there isn't already a break.
354+
if (Current.is(tok::r_brace) && Current.MatchingParen &&
355+
Current.isBlockIndentedInitRBrace(Style)) {
356+
return CurrentState.BreakBeforeClosingBrace;
357+
}
358+
352359
// Allow breaking before the right parens with block indentation if there was
353360
// a break after the left parens, which is tracked by BreakBeforeClosingParen.
354361
if (Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent &&
355362
Current.is(tok::r_paren)) {
356363
return CurrentState.BreakBeforeClosingParen;
357364
}
358365

359-
// Don't allow breaking before a closing brace of a block-indented braced list
360-
// initializer if there isn't already a break.
361-
if (Current.is(tok::r_brace) && Current.MatchingParen &&
362-
Current.isBlockIndentedInitRBrace(Style)) {
363-
return CurrentState.BreakBeforeClosingBrace;
364-
}
366+
if (Style.BreakBeforeTemplateCloser && Current.is(TT_TemplateCloser))
367+
return CurrentState.BreakBeforeClosingAngle;
365368

366369
// If binary operators are moved to the next line (including commas for some
367370
// styles of constructor initializers), that's always ok.
@@ -414,6 +417,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
414417
}
415418
if (CurrentState.BreakBeforeClosingParen && Current.is(tok::r_paren))
416419
return true;
420+
if (CurrentState.BreakBeforeClosingAngle && Current.is(TT_TemplateCloser))
421+
return true;
417422
if (Style.Language == FormatStyle::LK_ObjC &&
418423
Style.ObjCBreakBeforeNestedBlockParam &&
419424
Current.ObjCSelectorNameParts > 1 &&
@@ -1243,6 +1248,9 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
12431248
Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent;
12441249
}
12451250

1251+
if (PreviousNonComment && PreviousNonComment->is(TT_TemplateOpener))
1252+
CurrentState.BreakBeforeClosingAngle = Style.BreakBeforeTemplateCloser;
1253+
12461254
if (CurrentState.AvoidBinPacking) {
12471255
// If we are breaking after '(', '{', '<', or this is the break after a ':'
12481256
// to start a member initializer list in a constructor, this should not
@@ -1379,6 +1387,10 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
13791387
State.Stack.size() > 1) {
13801388
return State.Stack[State.Stack.size() - 2].LastSpace;
13811389
}
1390+
if (Style.BreakBeforeTemplateCloser && Current.is(TT_TemplateCloser) &&
1391+
State.Stack.size() > 1) {
1392+
return State.Stack[State.Stack.size() - 2].LastSpace;
1393+
}
13821394
if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope())
13831395
return State.Stack[State.Stack.size() - 2].LastSpace;
13841396
// Field labels in a nested type should be aligned to the brace. For example

clang/lib/Format/ContinuationIndenter.h

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -200,14 +200,15 @@ struct ParenState {
200200
: Tok(Tok), Indent(Indent), LastSpace(LastSpace),
201201
NestedBlockIndent(Indent), IsAligned(false),
202202
BreakBeforeClosingBrace(false), BreakBeforeClosingParen(false),
203-
AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false),
204-
NoLineBreak(NoLineBreak), NoLineBreakInOperand(false),
205-
LastOperatorWrapped(true), ContainsLineBreak(false),
206-
ContainsUnwrappedBuilder(false), AlignColons(true),
207-
ObjCSelectorNameFound(false), HasMultipleNestedBlocks(false),
208-
NestedBlockInlined(false), IsInsideObjCArrayLiteral(false),
209-
IsCSharpGenericTypeConstraint(false), IsChainedConditional(false),
210-
IsWrappedConditional(false), UnindentOperator(false) {}
203+
BreakBeforeClosingAngle(false), AvoidBinPacking(AvoidBinPacking),
204+
BreakBeforeParameter(false), NoLineBreak(NoLineBreak),
205+
NoLineBreakInOperand(false), LastOperatorWrapped(true),
206+
ContainsLineBreak(false), ContainsUnwrappedBuilder(false),
207+
AlignColons(true), ObjCSelectorNameFound(false),
208+
HasMultipleNestedBlocks(false), NestedBlockInlined(false),
209+
IsInsideObjCArrayLiteral(false), IsCSharpGenericTypeConstraint(false),
210+
IsChainedConditional(false), IsWrappedConditional(false),
211+
UnindentOperator(false) {}
211212

212213
/// \brief The token opening this parenthesis level, or nullptr if this level
213214
/// is opened by fake parenthesis.
@@ -280,6 +281,9 @@ struct ParenState {
280281
/// was a newline after the beginning left paren.
281282
bool BreakBeforeClosingParen : 1;
282283

284+
/// Whether a newline needs to be inserted before a closing angle `>`.
285+
bool BreakBeforeClosingAngle : 1;
286+
283287
/// Avoid bin packing, i.e. multiple parameters/elements on multiple
284288
/// lines, in this context.
285289
bool AvoidBinPacking : 1;
@@ -367,6 +371,8 @@ struct ParenState {
367371
return BreakBeforeClosingBrace;
368372
if (BreakBeforeClosingParen != Other.BreakBeforeClosingParen)
369373
return BreakBeforeClosingParen;
374+
if (BreakBeforeClosingAngle != Other.BreakBeforeClosingAngle)
375+
return BreakBeforeClosingAngle;
370376
if (QuestionColumn != Other.QuestionColumn)
371377
return QuestionColumn < Other.QuestionColumn;
372378
if (AvoidBinPacking != Other.AvoidBinPacking)

clang/lib/Format/Format.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,6 +1014,8 @@ template <> struct MappingTraits<FormatStyle> {
10141014
IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
10151015
IO.mapOptional("BreakBeforeInlineASMColon",
10161016
Style.BreakBeforeInlineASMColon);
1017+
IO.mapOptional("BreakBeforeTemplateCloser",
1018+
Style.BreakBeforeTemplateCloser);
10171019
IO.mapOptional("BreakBeforeTernaryOperators",
10181020
Style.BreakBeforeTernaryOperators);
10191021
IO.mapOptional("BreakBinaryOperations", Style.BreakBinaryOperations);
@@ -1535,6 +1537,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
15351537
LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
15361538
LLVMStyle.BreakBeforeConceptDeclarations = FormatStyle::BBCDS_Always;
15371539
LLVMStyle.BreakBeforeInlineASMColon = FormatStyle::BBIAS_OnlyMultiline;
1540+
LLVMStyle.BreakBeforeTemplateCloser = false;
15381541
LLVMStyle.BreakBeforeTernaryOperators = true;
15391542
LLVMStyle.BreakBinaryOperations = FormatStyle::BBO_Never;
15401543
LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6180,6 +6180,9 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
61806180
return false;
61816181
}
61826182

6183+
if (Right.is(TT_TemplateCloser))
6184+
return Style.BreakBeforeTemplateCloser;
6185+
61836186
if (Left.is(tok::at))
61846187
return false;
61856188
if (Left.Tok.getObjCKeywordID() == tok::objc_interface)
@@ -6328,8 +6331,6 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
63286331
if (Right.is(TT_ImplicitStringLiteral))
63296332
return false;
63306333

6331-
if (Right.is(TT_TemplateCloser))
6332-
return false;
63336334
if (Right.is(tok::r_square) && Right.MatchingParen &&
63346335
Right.MatchingParen->is(TT_LambdaLSquare)) {
63356336
return false;

clang/unittests/Format/ConfigParseTest.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
170170
CHECK_PARSE_BOOL(BinPackArguments);
171171
CHECK_PARSE_BOOL(BreakAdjacentStringLiterals);
172172
CHECK_PARSE_BOOL(BreakAfterJavaFieldAnnotations);
173+
CHECK_PARSE_BOOL(BreakBeforeTemplateCloser);
173174
CHECK_PARSE_BOOL(BreakBeforeTernaryOperators);
174175
CHECK_PARSE_BOOL(BreakStringLiterals);
175176
CHECK_PARSE_BOOL(CompactNamespaces);

0 commit comments

Comments
 (0)