aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
authorleijurv <leijurv@gmail.com>2025-02-06 01:15:47 -0800
committerGitHub <noreply@github.com>2025-02-06 01:15:47 -0800
commitd2b45ce100d641a8f1690e30843bb9c5ea71ab86 (patch)
treece6d7d8789e85d82656f19a99116801a58dcc2ac /clang/lib
parent7ef33e609c45515de9db1b5222fe6e05edd76c94 (diff)
downloadllvm-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.cpp24
-rw-r--r--clang/lib/Format/ContinuationIndenter.h22
-rw-r--r--clang/lib/Format/Format.cpp3
-rw-r--r--clang/lib/Format/TokenAnnotator.cpp5
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;