diff options
author | leijurv <leijurv@gmail.com> | 2025-02-06 01:15:47 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-02-06 01:15:47 -0800 |
commit | d2b45ce100d641a8f1690e30843bb9c5ea71ab86 (patch) | |
tree | ce6d7d8789e85d82656f19a99116801a58dcc2ac /clang/lib | |
parent | 7ef33e609c45515de9db1b5222fe6e05edd76c94 (diff) | |
download | llvm-d2b45ce100d641a8f1690e30843bb9c5ea71ab86.zip llvm-d2b45ce100d641a8f1690e30843bb9c5ea71ab86.tar.gz llvm-d2b45ce100d641a8f1690e30843bb9c5ea71ab86.tar.bz2 |
[clang-format] Add BreakBeforeTemplateCloser option (#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 <owenpiano@gmail.com>
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Format/ContinuationIndenter.cpp | 24 | ||||
-rw-r--r-- | clang/lib/Format/ContinuationIndenter.h | 22 | ||||
-rw-r--r-- | clang/lib/Format/Format.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Format/TokenAnnotator.cpp | 5 |
4 files changed, 38 insertions, 16 deletions
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index 6f7d213..3e51b4aa 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -349,6 +349,13 @@ bool ContinuationIndenter::canBreak(const LineState &State) { } } + // Don't allow breaking before a closing brace of a block-indented braced list + // initializer if there isn't already a break. + if (Current.is(tok::r_brace) && Current.MatchingParen && + Current.isBlockIndentedInitRBrace(Style)) { + return CurrentState.BreakBeforeClosingBrace; + } + // Allow breaking before the right parens with block indentation if there was // a break after the left parens, which is tracked by BreakBeforeClosingParen. if (Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent && @@ -356,12 +363,8 @@ bool ContinuationIndenter::canBreak(const LineState &State) { return CurrentState.BreakBeforeClosingParen; } - // Don't allow breaking before a closing brace of a block-indented braced list - // initializer if there isn't already a break. - if (Current.is(tok::r_brace) && Current.MatchingParen && - Current.isBlockIndentedInitRBrace(Style)) { - return CurrentState.BreakBeforeClosingBrace; - } + if (Style.BreakBeforeTemplateCloser && Current.is(TT_TemplateCloser)) + return CurrentState.BreakBeforeClosingAngle; // If binary operators are moved to the next line (including commas for some // styles of constructor initializers), that's always ok. @@ -414,6 +417,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { } if (CurrentState.BreakBeforeClosingParen && Current.is(tok::r_paren)) return true; + if (CurrentState.BreakBeforeClosingAngle && Current.is(TT_TemplateCloser)) + return true; if (Style.Language == FormatStyle::LK_ObjC && Style.ObjCBreakBeforeNestedBlockParam && Current.ObjCSelectorNameParts > 1 && @@ -1243,6 +1248,9 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent; } + if (PreviousNonComment && PreviousNonComment->is(TT_TemplateOpener)) + CurrentState.BreakBeforeClosingAngle = Style.BreakBeforeTemplateCloser; + if (CurrentState.AvoidBinPacking) { // If we are breaking after '(', '{', '<', or this is the break after a ':' // to start a member initializer list in a constructor, this should not @@ -1379,6 +1387,10 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { State.Stack.size() > 1) { return State.Stack[State.Stack.size() - 2].LastSpace; } + if (Style.BreakBeforeTemplateCloser && Current.is(TT_TemplateCloser) && + State.Stack.size() > 1) { + return State.Stack[State.Stack.size() - 2].LastSpace; + } if (NextNonComment->is(TT_TemplateString) && NextNonComment->closesScope()) return State.Stack[State.Stack.size() - 2].LastSpace; // Field labels in a nested type should be aligned to the brace. For example diff --git a/clang/lib/Format/ContinuationIndenter.h b/clang/lib/Format/ContinuationIndenter.h index 18441e1..ac354aa 100644 --- a/clang/lib/Format/ContinuationIndenter.h +++ b/clang/lib/Format/ContinuationIndenter.h @@ -200,14 +200,15 @@ struct ParenState { : Tok(Tok), Indent(Indent), LastSpace(LastSpace), NestedBlockIndent(Indent), IsAligned(false), BreakBeforeClosingBrace(false), BreakBeforeClosingParen(false), - AvoidBinPacking(AvoidBinPacking), BreakBeforeParameter(false), - NoLineBreak(NoLineBreak), NoLineBreakInOperand(false), - LastOperatorWrapped(true), ContainsLineBreak(false), - ContainsUnwrappedBuilder(false), AlignColons(true), - ObjCSelectorNameFound(false), HasMultipleNestedBlocks(false), - NestedBlockInlined(false), IsInsideObjCArrayLiteral(false), - IsCSharpGenericTypeConstraint(false), IsChainedConditional(false), - IsWrappedConditional(false), UnindentOperator(false) {} + BreakBeforeClosingAngle(false), AvoidBinPacking(AvoidBinPacking), + BreakBeforeParameter(false), NoLineBreak(NoLineBreak), + NoLineBreakInOperand(false), LastOperatorWrapped(true), + ContainsLineBreak(false), ContainsUnwrappedBuilder(false), + AlignColons(true), ObjCSelectorNameFound(false), + HasMultipleNestedBlocks(false), NestedBlockInlined(false), + IsInsideObjCArrayLiteral(false), IsCSharpGenericTypeConstraint(false), + IsChainedConditional(false), IsWrappedConditional(false), + UnindentOperator(false) {} /// \brief The token opening this parenthesis level, or nullptr if this level /// is opened by fake parenthesis. @@ -280,6 +281,9 @@ struct ParenState { /// was a newline after the beginning left paren. bool BreakBeforeClosingParen : 1; + /// Whether a newline needs to be inserted before a closing angle `>`. + bool BreakBeforeClosingAngle : 1; + /// Avoid bin packing, i.e. multiple parameters/elements on multiple /// lines, in this context. bool AvoidBinPacking : 1; @@ -367,6 +371,8 @@ struct ParenState { return BreakBeforeClosingBrace; if (BreakBeforeClosingParen != Other.BreakBeforeClosingParen) return BreakBeforeClosingParen; + if (BreakBeforeClosingAngle != Other.BreakBeforeClosingAngle) + return BreakBeforeClosingAngle; if (QuestionColumn != Other.QuestionColumn) return QuestionColumn < Other.QuestionColumn; if (AvoidBinPacking != Other.AvoidBinPacking) diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index f02bf95..387daad 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -1014,6 +1014,8 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces); IO.mapOptional("BreakBeforeInlineASMColon", Style.BreakBeforeInlineASMColon); + IO.mapOptional("BreakBeforeTemplateCloser", + Style.BreakBeforeTemplateCloser); IO.mapOptional("BreakBeforeTernaryOperators", Style.BreakBeforeTernaryOperators); IO.mapOptional("BreakBinaryOperations", Style.BreakBinaryOperations); @@ -1535,6 +1537,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach; LLVMStyle.BreakBeforeConceptDeclarations = FormatStyle::BBCDS_Always; LLVMStyle.BreakBeforeInlineASMColon = FormatStyle::BBIAS_OnlyMultiline; + LLVMStyle.BreakBeforeTemplateCloser = false; LLVMStyle.BreakBeforeTernaryOperators = true; LLVMStyle.BreakBinaryOperations = FormatStyle::BBO_Never; LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index f25332e..94fd7ba 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -6180,6 +6180,9 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, return false; } + if (Right.is(TT_TemplateCloser)) + return Style.BreakBeforeTemplateCloser; + if (Left.is(tok::at)) return false; if (Left.Tok.getObjCKeywordID() == tok::objc_interface) @@ -6328,8 +6331,6 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, if (Right.is(TT_ImplicitStringLiteral)) return false; - if (Right.is(TT_TemplateCloser)) - return false; if (Right.is(tok::r_square) && Right.MatchingParen && Right.MatchingParen->is(TT_LambdaLSquare)) { return false; |