[clang] [clang-format] Add BreakBeforeTemplateClose option (PR #118046)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Jan 12 12:08:32 PST 2025
https://github.com/leijurv updated https://github.com/llvm/llvm-project/pull/118046
>From 1caf823165b16f6701993d586df51d5cdbf0885e Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Fri, 29 Nov 2024 21:54:36 -0600
Subject: [PATCH 1/8] [clang-format] Add BreakBeforeTemplateClose option
---
clang/docs/ClangFormatStyleOptions.rst | 21 ++++
clang/docs/ReleaseNotes.rst | 1 +
clang/include/clang/Format/Format.h | 20 ++++
clang/lib/Format/ContinuationIndenter.cpp | 11 ++
clang/lib/Format/ContinuationIndenter.h | 26 ++--
clang/lib/Format/Format.cpp | 2 +
clang/lib/Format/TokenAnnotator.cpp | 2 +-
clang/unittests/Format/ConfigParseTest.cpp | 1 +
clang/unittests/Format/FormatTest.cpp | 131 +++++++++++++++++++++
9 files changed, 206 insertions(+), 9 deletions(-)
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 4be448171699ca..84ab1b0a2eff61 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -3416,6 +3416,27 @@ the configuration (without a prefix: ``Auto``).
+.. _BreakBeforeTemplateClose:
+
+**BreakBeforeTemplateClose** (``Boolean``) :versionbadge:`clang-format 20` :ref:`¶ <BreakBeforeTemplateClose>`
+ If ``true``, a line break will be placed before the ``>`` in a multiline
+ template declaration.
+
+ .. code-block:: c++
+
+ true:
+ template <
+ typename Foo,
+ typename Bar,
+ typename Baz
+ >
+
+ false:
+ template <
+ typename Foo,
+ typename Bar,
+ typename Baz>
+
.. _BreakBeforeTernaryOperators:
**BreakBeforeTernaryOperators** (``Boolean``) :versionbadge:`clang-format 3.7` :ref:`¶ <BreakBeforeTernaryOperators>`
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index e44aefa90ab386..867d4b5d8c3f18 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -976,6 +976,7 @@ clang-format
``Never``, and ``true`` to ``Always``.
- Adds ``RemoveEmptyLinesInUnwrappedLines`` option.
- Adds ``KeepFormFeed`` option and set it to ``true`` for ``GNU`` style.
+- Adds ``BreakBeforeTemplateClose`` option.
libclang
--------
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 6383934afa2c40..bffd964f6aa8aa 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -2248,6 +2248,25 @@ struct FormatStyle {
/// \version 16
BreakBeforeInlineASMColonStyle BreakBeforeInlineASMColon;
+ /// If ``true``, a line break will be placed before the ``>`` in a multiline
+ /// template declaration.
+ /// \code
+ /// true:
+ /// template <
+ /// typename Foo,
+ /// typename Bar,
+ /// typename Baz
+ /// >
+ ///
+ /// false:
+ /// template <
+ /// typename Foo,
+ /// typename Bar,
+ /// typename Baz>
+ /// \endcode
+ /// \version 20
+ bool BreakBeforeTemplateClose;
+
/// If ``true``, ternary operators will be placed after line breaks.
/// \code
/// true:
@@ -5184,6 +5203,7 @@ struct FormatStyle {
BreakBeforeBraces == R.BreakBeforeBraces &&
BreakBeforeConceptDeclarations == R.BreakBeforeConceptDeclarations &&
BreakBeforeInlineASMColon == R.BreakBeforeInlineASMColon &&
+ BreakBeforeTemplateClose == R.BreakBeforeTemplateClose &&
BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators &&
BreakBinaryOperations == R.BreakBinaryOperations &&
BreakConstructorInitializers == R.BreakConstructorInitializers &&
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index aed86c1fb99551..4c783623afc535 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -406,6 +406,10 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
}
if (CurrentState.BreakBeforeClosingParen && Current.is(tok::r_paren))
return true;
+ if (CurrentState.BreakBeforeClosingAngle &&
+ Current.ClosesTemplateDeclaration && Style.BreakBeforeTemplateClose) {
+ return true;
+ }
if (Style.Language == FormatStyle::LK_ObjC &&
Style.ObjCBreakBeforeNestedBlockParam &&
Current.ObjCSelectorNameParts > 1 &&
@@ -1234,6 +1238,9 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
Style.AlignAfterOpenBracket == FormatStyle::BAS_BlockIndent;
}
+ if (PreviousNonComment && PreviousNonComment->is(tok::less))
+ CurrentState.BreakBeforeClosingAngle = true;
+
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
@@ -1370,6 +1377,10 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
State.Stack.size() > 1) {
return State.Stack[State.Stack.size() - 2].LastSpace;
}
+ if (Current.ClosesTemplateDeclaration && Style.BreakBeforeTemplateClose &&
+ 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 18441e10a12492..88d214473396a8 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,13 @@ struct ParenState {
/// was a newline after the beginning left paren.
bool BreakBeforeClosingParen : 1;
+ /// Whether a newline needs to be inserted before the block's closing
+ /// angle < >.
+ ///
+ /// We only want to insert a newline before the closing angle if there also
+ /// was a newline after the beginning left angle.
+ bool BreakBeforeClosingAngle : 1;
+
/// Avoid bin packing, i.e. multiple parameters/elements on multiple
/// lines, in this context.
bool AvoidBinPacking : 1;
@@ -367,6 +375,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 ee52972ce66f4a..d6aa80dd8e3aef 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1000,6 +1000,7 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
IO.mapOptional("BreakBeforeInlineASMColon",
Style.BreakBeforeInlineASMColon);
+ IO.mapOptional("BreakBeforeTemplateClose", Style.BreakBeforeTemplateClose);
IO.mapOptional("BreakBeforeTernaryOperators",
Style.BreakBeforeTernaryOperators);
IO.mapOptional("BreakBinaryOperations", Style.BreakBinaryOperations);
@@ -1514,6 +1515,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
LLVMStyle.BreakBeforeConceptDeclarations = FormatStyle::BBCDS_Always;
LLVMStyle.BreakBeforeInlineASMColon = FormatStyle::BBIAS_OnlyMultiline;
+ LLVMStyle.BreakBeforeTemplateClose = 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 bc5239209f3aab..c9908515833bad 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -6254,7 +6254,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
return false;
if (Right.is(TT_TemplateCloser))
- return false;
+ return Right.ClosesTemplateDeclaration && Style.BreakBeforeTemplateClose;
if (Right.is(tok::r_square) && Right.MatchingParen &&
Right.MatchingParen->is(TT_LambdaLSquare)) {
return false;
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index 7fc7492271668b..39f4ea49719600 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -162,6 +162,7 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
CHECK_PARSE_BOOL(BinPackArguments);
CHECK_PARSE_BOOL(BreakAdjacentStringLiterals);
CHECK_PARSE_BOOL(BreakAfterJavaFieldAnnotations);
+ CHECK_PARSE_BOOL(BreakBeforeTemplateClose);
CHECK_PARSE_BOOL(BreakBeforeTernaryOperators);
CHECK_PARSE_BOOL(BreakStringLiterals);
CHECK_PARSE_BOOL(CompactNamespaces);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 250e51b5421664..07205b010575de 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11077,6 +11077,137 @@ TEST_F(FormatTest, WrapsTemplateDeclarationsWithComments) {
Style);
}
+TEST_F(FormatTest, BreakBeforeTemplateClose) {
+ FormatStyle Style = getGoogleStyle(FormatStyle::LK_Cpp);
+ Style.ColumnLimit = 0;
+ verifyNoChange("template <typename Foo>\n"
+ "void foo() {}",
+ Style);
+ verifyNoChange("template <\n"
+ " typename Foo,\n"
+ " typename Bar>\n"
+ "void foo() {}",
+ Style);
+ // when BreakBeforeTemplateClose is off, this line break is removed:
+ verifyFormat("template <\n"
+ " typename Foo,\n"
+ " typename Bar>\n"
+ "void foo() {}",
+ "template <\n"
+ " typename Foo,\n"
+ " typename Bar\n"
+ ">\n"
+ "void foo() {}",
+ Style);
+ Style.BreakBeforeTemplateClose = true;
+ // BreakBeforeTemplateClose should NOT force multiline templates
+ verifyNoChange("template <typename Foo>\n"
+ "void foo() {}",
+ Style);
+ verifyNoChange("template <typename Foo, typename Bar>\n"
+ "void foo() {}",
+ Style);
+ // it should allow a line break:
+ verifyNoChange("template <\n"
+ " typename Foo\n"
+ ">\n"
+ "void foo() {}",
+ Style);
+ verifyNoChange("template <\n"
+ " typename Foo,\n"
+ " typename Bar\n"
+ ">\n"
+ "void foo() {}",
+ Style);
+ // it should add a line break if not already present:
+ verifyFormat("template <\n"
+ " typename Foo\n"
+ ">\n"
+ "void foo() {}",
+ "template <\n"
+ " typename Foo>\n"
+ "void foo() {}",
+ Style);
+ verifyFormat("template <\n"
+ " typename Foo,\n"
+ " typename Bar\n"
+ ">\n"
+ "void foo() {}",
+ "template <\n"
+ " typename Foo,\n"
+ " typename Bar>\n"
+ "void foo() {}",
+ Style);
+ // when within an indent scope, the > should be placed appropriately:
+ verifyFormat("struct Baz {\n"
+ " template <\n"
+ " typename Foo,\n"
+ " typename Bar\n"
+ " >\n"
+ " void foo() {}\n"
+ "};",
+ "struct Baz {\n"
+ " template <\n"
+ " typename Foo,\n"
+ " typename Bar>\n"
+ " void foo() {}\n"
+ "};",
+ Style);
+
+ // now test that it handles the cases when the column limit forces wrapping
+ Style.ColumnLimit = 40;
+ // when the column limit allows it, the template should be combined back into
+ // one line:
+ verifyFormat("template <typename Foo, typename Bar>\n"
+ "void foo() {}",
+ "template <\n"
+ " typename Foo,\n"
+ " typename Bar\n"
+ ">\n"
+ "void foo() {}",
+ Style);
+ // but not when the name is looong
+ verifyFormat("template <\n"
+ " typename Foo,\n"
+ " typename Barrrrrrrrrrrrrrrrrrrrrrrrrr\n"
+ ">\n"
+ "void foo() {}",
+ Style);
+ verifyFormat("template <\n"
+ " typename Fooooooooooooooooooooooooooo,\n"
+ " typename Bar\n"
+ ">\n"
+ "void foo() {}",
+ Style);
+ // additionally, long names should be split in one step:
+ verifyFormat(
+ "template <\n"
+ " typename Foo,\n"
+ " typename Barrrrrrrrrrrrrrrrrrrrrrrrrr\n"
+ ">\n"
+ "void foo() {}",
+ "template <typename Foo, typename Barrrrrrrrrrrrrrrrrrrrrrrrrr>\n"
+ "void foo() {}",
+ Style);
+ verifyFormat(
+ "template <\n"
+ " typename Fooooooooooooooooooooooooooo,\n"
+ " typename Bar\n"
+ ">\n"
+ "void foo() {}",
+ "template <typename Fooooooooooooooooooooooooooo, typename Bar>\n"
+ "void foo() {}",
+ Style);
+ // even when there is only one long name:
+ verifyFormat("template <\n"
+ " typename Fooooooooooooooooooooooooooo\n"
+ ">\n"
+ "void foo() {}",
+ "template <typename Fooooooooooooooooooooooooooo>\n"
+ "void foo() {}",
+ Style);
+}
+
TEST_F(FormatTest, WrapsTemplateParameters) {
FormatStyle Style = getLLVMStyle();
Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
>From 212e444426a2d194df996909a40ad0e0fc681d98 Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Fri, 6 Dec 2024 20:36:41 -0700
Subject: [PATCH 2/8] add test case
---
clang/lib/Format/ContinuationIndenter.cpp | 6 +++---
clang/lib/Format/TokenAnnotator.cpp | 2 +-
clang/unittests/Format/FormatTest.cpp | 20 ++++++++++++++++++++
3 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 4c783623afc535..377234e29d9ea4 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -406,8 +406,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
}
if (CurrentState.BreakBeforeClosingParen && Current.is(tok::r_paren))
return true;
- if (CurrentState.BreakBeforeClosingAngle &&
- Current.ClosesTemplateDeclaration && Style.BreakBeforeTemplateClose) {
+ if (CurrentState.BreakBeforeClosingAngle && Current.is(TT_TemplateCloser) &&
+ Style.BreakBeforeTemplateClose) {
return true;
}
if (Style.Language == FormatStyle::LK_ObjC &&
@@ -1377,7 +1377,7 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
State.Stack.size() > 1) {
return State.Stack[State.Stack.size() - 2].LastSpace;
}
- if (Current.ClosesTemplateDeclaration && Style.BreakBeforeTemplateClose &&
+ if (Current.is(TT_TemplateCloser) && Style.BreakBeforeTemplateClose &&
State.Stack.size() > 1) {
return State.Stack[State.Stack.size() - 2].LastSpace;
}
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index c9908515833bad..ecb41827cad48c 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -6254,7 +6254,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
return false;
if (Right.is(TT_TemplateCloser))
- return Right.ClosesTemplateDeclaration && Style.BreakBeforeTemplateClose;
+ return Style.BreakBeforeTemplateClose;
if (Right.is(tok::r_square) && Right.MatchingParen &&
Right.MatchingParen->is(TT_LambdaLSquare)) {
return false;
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 07205b010575de..ea00d95447bf8a 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11154,6 +11154,26 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
"};",
Style);
+ // test from issue #80049
+ verifyFormat(
+ "void foo() {\n"
+ " using type = std::remove_cv_t<\n"
+ " add_common_cv_reference<\n"
+ " std::common_type_t<std::decay_t<T0>, std::decay_t<T1>>,\n"
+ " T0,\n"
+ " T1\n"
+ " >\n"
+ " >;\n"
+ "}\n",
+ "void foo() {\n"
+ " using type = std::remove_cv_t<\n"
+ " add_common_cv_reference<\n"
+ " std::common_type_t<std::decay_t<T0>, std::decay_t<T1>>,\n"
+ " T0,\n"
+ " T1>>;\n"
+ "}\n",
+ Style);
+
// now test that it handles the cases when the column limit forces wrapping
Style.ColumnLimit = 40;
// when the column limit allows it, the template should be combined back into
>From 3927d411eeece27521e1a4034d01012c84beaf4b Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Sun, 8 Dec 2024 21:21:18 -0800
Subject: [PATCH 3/8] more tests
---
clang/unittests/Format/FormatTest.cpp | 64 +++++++++++++++++++++++++++
1 file changed, 64 insertions(+)
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index ea00d95447bf8a..4aabf13e9008f5 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11174,6 +11174,32 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
"}\n",
Style);
+ // test lambda goes to next line:
+ verifyFormat("void foo() {\n"
+ " auto lambda = []<\n"
+ " typename T\n"
+ " >(T t) {\n"
+ " };\n"
+ "}\n",
+ "void foo() {\n"
+ " auto lambda = []<\n"
+ " typename T>(T t){\n"
+ " };\n"
+ "}\n",
+ Style);
+
+ // test template usage goes to next line:
+ verifyFormat("void foo() {\n"
+ " myFunc<\n"
+ " T\n"
+ " >();\n"
+ "}\n",
+ "void foo() {\n"
+ " myFunc<\n"
+ " T>();\n"
+ "}\n",
+ Style);
+
// now test that it handles the cases when the column limit forces wrapping
Style.ColumnLimit = 40;
// when the column limit allows it, the template should be combined back into
@@ -11226,6 +11252,44 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
"template <typename Fooooooooooooooooooooooooooo>\n"
"void foo() {}",
Style);
+ // test lambda goes to next line if the type is looong:
+ verifyFormat(
+ "void foo() {\n"
+ // in this case, breaking "typename Looong" onto the next line would
+ // actually exceed the column limit by even more. same goes for "auto
+ // lambda = []<\n" because then the continuation indent would be all the
+ // way to the "[". therefore, this is correct for the column limited case:
+ " auto lambda =\n"
+ " []<typename Loooooooooooooooooooooooooooooooooong\n"
+ " >(T t) {};\n"
+ // for completeness, let's also make sure it's willing to break if and
+ // when doing so is helpful. if we put something long into the square
+ // brackets, now it's worth it:
+ " auto lambda =\n"
+ " [looooooooooooooong]<\n"
+ " typename Loooooooooooooooooooooooooooooooooong\n"
+ " >(T t) {};\n"
+ "}\n",
+ Style);
+ // test that if the type is NOT long, it pulls it back into one line:
+ verifyFormat("void foo() {\n"
+ " auto lambda = []<typename T>(T t) {};\n"
+ "}\n",
+ "void foo() {\n"
+ " auto lambda = []<\n"
+ " typename T\n"
+ " >(T t) {};\n"
+ "}\n",
+ Style);
+
+ // test template usage goes to next line only if the type is looong:
+ verifyFormat("void foo() { myFunc<T>(); }\n", Style);
+ verifyFormat("void foo() {\n"
+ " myFunc<\n"
+ " Loooooooooooooooooooooooooooooooooooooooong\n"
+ " >();\n"
+ "}\n",
+ Style);
}
TEST_F(FormatTest, WrapsTemplateParameters) {
>From 2c3a64c8f32a5c43887db4d107a4142490898c20 Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Sat, 21 Dec 2024 17:21:28 -0800
Subject: [PATCH 4/8] more tests
---
clang/unittests/Format/FormatTest.cpp | 60 +++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 4aabf13e9008f5..548bda4f774670 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11187,6 +11187,42 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
" };\n"
"}\n",
Style);
+ // with no column limit, two parameters can go on the same line:
+ verifyFormat("void foo() {\n"
+ " auto lambda = []<\n"
+ " typename T, typename Foo\n"
+ " >(T t) {\n"
+ " };\n"
+ "}\n",
+ "void foo() {\n"
+ " auto lambda = []<\n"
+ " typename T, typename Foo>(T t){\n"
+ " };\n"
+ "}\n",
+ Style);
+ // or on different lines:
+ verifyFormat("void foo() {\n"
+ " auto lambda = []<\n"
+ " typename T,\n"
+ " typename Foo\n"
+ " >(T t) {\n"
+ " };\n"
+ "}\n",
+ "void foo() {\n"
+ " auto lambda = []<\n"
+ " typename T,\n"
+ " typename Foo>(T t){\n"
+ " };\n"
+ "}\n",
+ Style);
+
+ // same line with no column limit
+ verifyFormat("void foo() {\n"
+ " auto lambda = []<typename "
+ "Looooooooooooooooooooooooooooong>("
+ "Looooooooooooooooooooooooooooong t) {};\n"
+ "}\n",
+ Style);
// test template usage goes to next line:
verifyFormat("void foo() {\n"
@@ -11269,6 +11305,30 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
" [looooooooooooooong]<\n"
" typename Loooooooooooooooooooooooooooooooooong\n"
" >(T t) {};\n"
+ " auto lambda =\n"
+ " []<typename T,\n"
+ " typename Loooooooooooooooooooooooooooooooooong\n"
+ " >(T t) {};\n"
+ // nested:
+ " auto lambda =\n"
+ " []<template <typename, typename>\n"
+ " typename Looooooooooooooooooong\n"
+ " >(T t) {};\n"
+ // nested with long capture:
+ " auto lambda =\n"
+ " [loooooooooooooooooooong]<\n"
+ " template <typename, typename>\n"
+ " typename Looooooooooooooooooong\n"
+ " >(T t) {};\n"
+ // nested, with long name and long captures:
+ " auto lambda =\n"
+ " [loooooooooooooooooooong]<\n"
+ " template <\n"
+ " typename Foooooooooooooooo,\n"
+ " typename\n"
+ " >\n"
+ " typename T\n"
+ " >(T t) {};\n"
"}\n",
Style);
// test that if the type is NOT long, it pulls it back into one line:
>From 19bc40e7d824804ebcd9839cb2155a704d368e36 Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Sat, 11 Jan 2025 01:37:04 -0800
Subject: [PATCH 5/8] address comments
---
clang/unittests/Format/FormatTest.cpp | 98 +++++++++++++--------------
1 file changed, 46 insertions(+), 52 deletions(-)
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 840ca703254705..cd968fc719f407 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11118,16 +11118,9 @@ TEST_F(FormatTest, WrapsTemplateDeclarationsWithComments) {
TEST_F(FormatTest, BreakBeforeTemplateClose) {
FormatStyle Style = getGoogleStyle(FormatStyle::LK_Cpp);
+ // Begin with tests covering the case where there is no constraint on the column limit.
Style.ColumnLimit = 0;
- verifyNoChange("template <typename Foo>\n"
- "void foo() {}",
- Style);
- verifyNoChange("template <\n"
- " typename Foo,\n"
- " typename Bar>\n"
- "void foo() {}",
- Style);
- // when BreakBeforeTemplateClose is off, this line break is removed:
+ // When BreakBeforeTemplateClose is turned off, the line break that it adds shall be removed:
verifyFormat("template <\n"
" typename Foo,\n"
" typename Bar>\n"
@@ -11139,14 +11132,15 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
"void foo() {}",
Style);
Style.BreakBeforeTemplateClose = true;
- // BreakBeforeTemplateClose should NOT force multiline templates
+ // BreakBeforeTemplateClose should NOT force template declarations onto multiple lines.
+ // Use verifyNoChange since ColumnLimit = 0.
verifyNoChange("template <typename Foo>\n"
"void foo() {}",
Style);
verifyNoChange("template <typename Foo, typename Bar>\n"
"void foo() {}",
Style);
- // it should allow a line break:
+ // It should allow a line break, even when the typename is short:
verifyNoChange("template <\n"
" typename Foo\n"
">\n"
@@ -11158,7 +11152,7 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
">\n"
"void foo() {}",
Style);
- // it should add a line break if not already present:
+ // It should add a line break before > if not already present:
verifyFormat("template <\n"
" typename Foo\n"
">\n"
@@ -11177,7 +11171,7 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
" typename Bar>\n"
"void foo() {}",
Style);
- // when within an indent scope, the > should be placed appropriately:
+ // When within an indent scope, the > should be placed accordingly:
verifyFormat("struct Baz {\n"
" template <\n"
" typename Foo,\n"
@@ -11193,7 +11187,7 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
"};",
Style);
- // test from issue #80049
+ // Test from issue #80049:
verifyFormat(
"void foo() {\n"
" using type = std::remove_cv_t<\n"
@@ -11203,91 +11197,91 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
" T1\n"
" >\n"
" >;\n"
- "}\n",
+ "}",
"void foo() {\n"
" using type = std::remove_cv_t<\n"
" add_common_cv_reference<\n"
" std::common_type_t<std::decay_t<T0>, std::decay_t<T1>>,\n"
" T0,\n"
" T1>>;\n"
- "}\n",
+ "}",
Style);
- // test lambda goes to next line:
+ // Test lambda goes to next line:
verifyFormat("void foo() {\n"
" auto lambda = []<\n"
" typename T\n"
" >(T t) {\n"
" };\n"
- "}\n",
+ "}",
"void foo() {\n"
" auto lambda = []<\n"
" typename T>(T t){\n"
" };\n"
- "}\n",
+ "}",
Style);
- // with no column limit, two parameters can go on the same line:
+ // With no column limit, two parameters can go on the same line:
verifyFormat("void foo() {\n"
" auto lambda = []<\n"
" typename T, typename Foo\n"
" >(T t) {\n"
" };\n"
- "}\n",
+ "}",
"void foo() {\n"
" auto lambda = []<\n"
" typename T, typename Foo>(T t){\n"
" };\n"
- "}\n",
+ "}",
Style);
- // or on different lines:
+ // Or on different lines:
verifyFormat("void foo() {\n"
" auto lambda = []<\n"
" typename T,\n"
" typename Foo\n"
" >(T t) {\n"
" };\n"
- "}\n",
+ "}",
"void foo() {\n"
" auto lambda = []<\n"
" typename T,\n"
" typename Foo>(T t){\n"
" };\n"
- "}\n",
+ "}",
Style);
- // same line with no column limit
+ // Note that this is the same line (no \n):
verifyFormat("void foo() {\n"
" auto lambda = []<typename "
"Looooooooooooooooooooooooooooong>("
"Looooooooooooooooooooooooooooong t) {};\n"
- "}\n",
+ "}",
Style);
- // test template usage goes to next line:
+ // Test template usage goes to next line too:
verifyFormat("void foo() {\n"
" myFunc<\n"
" T\n"
" >();\n"
- "}\n",
+ "}",
"void foo() {\n"
" myFunc<\n"
" T>();\n"
- "}\n",
+ "}",
Style);
- // now test that it handles the cases when the column limit forces wrapping
+ // Now test that it handles the cases when the column limit forces wrapping.
Style.ColumnLimit = 40;
- // when the column limit allows it, the template should be combined back into
+ // When the column limit allows it, the template should be combined back into
// one line:
verifyFormat("template <typename Foo, typename Bar>\n"
"void foo() {}",
"template <\n"
" typename Foo,\n"
" typename Bar\n"
- ">\n"
+ ">"
"void foo() {}",
Style);
- // but not when the name is looong
+ // But not when the name is looong:
verifyFormat("template <\n"
" typename Foo,\n"
" typename Barrrrrrrrrrrrrrrrrrrrrrrrrr\n"
@@ -11300,7 +11294,7 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
">\n"
"void foo() {}",
Style);
- // additionally, long names should be split in one step:
+ // Additionally, long names should be split in one step:
verifyFormat(
"template <\n"
" typename Foo,\n"
@@ -11319,7 +11313,7 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
"template <typename Fooooooooooooooooooooooooooo, typename Bar>\n"
"void foo() {}",
Style);
- // even when there is only one long name:
+ // Even when there is only one long name:
verifyFormat("template <\n"
" typename Fooooooooooooooooooooooooooo\n"
">\n"
@@ -11327,18 +11321,18 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
"template <typename Fooooooooooooooooooooooooooo>\n"
"void foo() {}",
Style);
- // test lambda goes to next line if the type is looong:
+ // Test lambda goes to next line if the type is looong:
verifyFormat(
"void foo() {\n"
- // in this case, breaking "typename Looong" onto the next line would
- // actually exceed the column limit by even more. same goes for "auto
+ // In this case, breaking "typename Looong" onto the next line would
+ // actually exceed the column limit by even more. Same goes for "auto
// lambda = []<\n" because then the continuation indent would be all the
- // way to the "[". therefore, this is correct for the column limited case:
+ // way to the "[". Therefore, this is correct for the column limited case:
" auto lambda =\n"
" []<typename Loooooooooooooooooooooooooooooooooong\n"
" >(T t) {};\n"
- // for completeness, let's also make sure it's willing to break if and
- // when doing so is helpful. if we put something long into the square
+ // For completeness, let's also make sure it's willing to break if and
+ // when doing so is helpful. If we put something long into the square
// brackets, now it's worth it:
" auto lambda =\n"
" [looooooooooooooong]<\n"
@@ -11348,18 +11342,18 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
" []<typename T,\n"
" typename Loooooooooooooooooooooooooooooooooong\n"
" >(T t) {};\n"
- // nested:
+ // Nested:
" auto lambda =\n"
" []<template <typename, typename>\n"
" typename Looooooooooooooooooong\n"
" >(T t) {};\n"
- // nested with long capture:
+ // Nested with long capture:
" auto lambda =\n"
" [loooooooooooooooooooong]<\n"
" template <typename, typename>\n"
" typename Looooooooooooooooooong\n"
" >(T t) {};\n"
- // nested, with long name and long captures:
+ // Nested, with long name and long captures:
" auto lambda =\n"
" [loooooooooooooooooooong]<\n"
" template <\n"
@@ -11368,26 +11362,26 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
" >\n"
" typename T\n"
" >(T t) {};\n"
- "}\n",
+ "}",
Style);
- // test that if the type is NOT long, it pulls it back into one line:
+ // Test that if the type is NOT long, it pulls it back into one line:
verifyFormat("void foo() {\n"
" auto lambda = []<typename T>(T t) {};\n"
- "}\n",
+ "}",
"void foo() {\n"
" auto lambda = []<\n"
" typename T\n"
" >(T t) {};\n"
- "}\n",
+ "}",
Style);
- // test template usage goes to next line only if the type is looong:
- verifyFormat("void foo() { myFunc<T>(); }\n", Style);
+ // Test template usage goes to next line only if the type is looong:
+ verifyFormat("void foo() { myFunc<T>(); }", Style);
verifyFormat("void foo() {\n"
" myFunc<\n"
" Loooooooooooooooooooooooooooooooooooooooong\n"
" >();\n"
- "}\n",
+ "}",
Style);
}
>From f75268ab23d20be2d96999a9f62d283fa300a825 Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Sat, 11 Jan 2025 22:35:07 -0800
Subject: [PATCH 6/8] address comments
---
clang/docs/ClangFormatStyleOptions.rst | 4 ++--
clang/docs/ReleaseNotes.rst | 2 +-
clang/include/clang/Format/Format.h | 4 ++--
clang/lib/Format/ContinuationIndenter.cpp | 4 ++--
clang/lib/Format/Format.cpp | 5 +++--
clang/lib/Format/TokenAnnotator.cpp | 2 +-
clang/unittests/Format/ConfigParseTest.cpp | 2 +-
clang/unittests/Format/FormatTest.cpp | 17 ++++++++++-------
8 files changed, 22 insertions(+), 18 deletions(-)
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 96c27e85e0d342..ca92a073b41e45 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -3421,9 +3421,9 @@ the configuration (without a prefix: ``Auto``).
-.. _BreakBeforeTemplateClose:
+.. _BreakBeforeTemplateCloser:
-**BreakBeforeTemplateClose** (``Boolean``) :versionbadge:`clang-format 20` :ref:`¶ <BreakBeforeTemplateClose>`
+**BreakBeforeTemplateCloser** (``Boolean``) :versionbadge:`clang-format 20` :ref:`¶ <BreakBeforeTemplateCloser>`
If ``true``, a line break will be placed before the ``>`` in a multiline
template declaration.
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 92503c929acf39..ffc74108025f6f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1136,7 +1136,7 @@ clang-format
- Adds ``VariableTemplates`` option.
- Adds support for bash globstar in ``.clang-format-ignore``.
- Adds ``WrapNamespaceBodyWithEmptyLines`` option.
-- Adds ``BreakBeforeTemplateClose`` option.
+- Adds ``BreakBeforeTemplateCloser`` option.
libclang
--------
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index da287e5b65cc5f..5132e38ea02ec6 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -2269,7 +2269,7 @@ struct FormatStyle {
/// typename Baz>
/// \endcode
/// \version 20
- bool BreakBeforeTemplateClose;
+ bool BreakBeforeTemplateCloser;
/// If ``true``, ternary operators will be placed after line breaks.
/// \code
@@ -5252,7 +5252,7 @@ struct FormatStyle {
BreakBeforeBraces == R.BreakBeforeBraces &&
BreakBeforeConceptDeclarations == R.BreakBeforeConceptDeclarations &&
BreakBeforeInlineASMColon == R.BreakBeforeInlineASMColon &&
- BreakBeforeTemplateClose == R.BreakBeforeTemplateClose &&
+ BreakBeforeTemplateCloser == R.BreakBeforeTemplateCloser &&
BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators &&
BreakBinaryOperations == R.BreakBinaryOperations &&
BreakConstructorInitializers == R.BreakConstructorInitializers &&
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 0c6348bc416f5b..8e7f0d88f81742 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -407,7 +407,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
if (CurrentState.BreakBeforeClosingParen && Current.is(tok::r_paren))
return true;
if (CurrentState.BreakBeforeClosingAngle && Current.is(TT_TemplateCloser) &&
- Style.BreakBeforeTemplateClose) {
+ Style.BreakBeforeTemplateCloser) {
return true;
}
if (Style.Language == FormatStyle::LK_ObjC &&
@@ -1378,7 +1378,7 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
State.Stack.size() > 1) {
return State.Stack[State.Stack.size() - 2].LastSpace;
}
- if (Current.is(TT_TemplateCloser) && Style.BreakBeforeTemplateClose &&
+ if (Current.is(TT_TemplateCloser) && Style.BreakBeforeTemplateCloser &&
State.Stack.size() > 1) {
return State.Stack[State.Stack.size() - 2].LastSpace;
}
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 2229455d45a4ad..e421880d4cf34c 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1014,7 +1014,8 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
IO.mapOptional("BreakBeforeInlineASMColon",
Style.BreakBeforeInlineASMColon);
- IO.mapOptional("BreakBeforeTemplateClose", Style.BreakBeforeTemplateClose);
+ IO.mapOptional("BreakBeforeTemplateCloser",
+ Style.BreakBeforeTemplateCloser);
IO.mapOptional("BreakBeforeTernaryOperators",
Style.BreakBeforeTernaryOperators);
IO.mapOptional("BreakBinaryOperations", Style.BreakBinaryOperations);
@@ -1533,7 +1534,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
LLVMStyle.BreakBeforeConceptDeclarations = FormatStyle::BBCDS_Always;
LLVMStyle.BreakBeforeInlineASMColon = FormatStyle::BBIAS_OnlyMultiline;
- LLVMStyle.BreakBeforeTemplateClose = false;
+ 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 f33ad347436314..98c0c09811b9b5 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -6325,7 +6325,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
return false;
if (Right.is(TT_TemplateCloser))
- return Style.BreakBeforeTemplateClose;
+ return Style.BreakBeforeTemplateCloser;
if (Right.is(tok::r_square) && Right.MatchingParen &&
Right.MatchingParen->is(TT_LambdaLSquare)) {
return false;
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index 8a0afc50c7b17d..ead9662ba54801 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -166,7 +166,7 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
CHECK_PARSE_BOOL(BinPackArguments);
CHECK_PARSE_BOOL(BreakAdjacentStringLiterals);
CHECK_PARSE_BOOL(BreakAfterJavaFieldAnnotations);
- CHECK_PARSE_BOOL(BreakBeforeTemplateClose);
+ CHECK_PARSE_BOOL(BreakBeforeTemplateCloser);
CHECK_PARSE_BOOL(BreakBeforeTernaryOperators);
CHECK_PARSE_BOOL(BreakStringLiterals);
CHECK_PARSE_BOOL(CompactNamespaces);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index cd968fc719f407..da0df0134568f6 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11116,11 +11116,13 @@ TEST_F(FormatTest, WrapsTemplateDeclarationsWithComments) {
Style);
}
-TEST_F(FormatTest, BreakBeforeTemplateClose) {
+TEST_F(FormatTest, BreakBeforeTemplateCloser) {
FormatStyle Style = getGoogleStyle(FormatStyle::LK_Cpp);
- // Begin with tests covering the case where there is no constraint on the column limit.
+ // Begin with tests covering the case where there is no constraint on the
+ // column limit.
Style.ColumnLimit = 0;
- // When BreakBeforeTemplateClose is turned off, the line break that it adds shall be removed:
+ // When BreakBeforeTemplateCloser is turned off, the line break that it adds
+ // shall be removed:
verifyFormat("template <\n"
" typename Foo,\n"
" typename Bar>\n"
@@ -11131,9 +11133,10 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
">\n"
"void foo() {}",
Style);
- Style.BreakBeforeTemplateClose = true;
- // BreakBeforeTemplateClose should NOT force template declarations onto multiple lines.
- // Use verifyNoChange since ColumnLimit = 0.
+
+ Style.BreakBeforeTemplateCloser = true;
+ // BreakBeforeTemplateCloser should NOT force template declarations onto
+ // multiple lines. Use verifyNoChange since ColumnLimit = 0.
verifyNoChange("template <typename Foo>\n"
"void foo() {}",
Style);
@@ -11278,7 +11281,7 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
"template <\n"
" typename Foo,\n"
" typename Bar\n"
- ">"
+ ">\n"
"void foo() {}",
Style);
// But not when the name is looong:
>From 130428887e534cc3bfdfeec5846df2fd1e939667 Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Sat, 11 Jan 2025 22:47:45 -0800
Subject: [PATCH 7/8] address comments
---
clang/unittests/Format/FormatTest.cpp | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index da0df0134568f6..b01139ebb8864c 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11136,14 +11136,15 @@ TEST_F(FormatTest, BreakBeforeTemplateCloser) {
Style.BreakBeforeTemplateCloser = true;
// BreakBeforeTemplateCloser should NOT force template declarations onto
- // multiple lines. Use verifyNoChange since ColumnLimit = 0.
- verifyNoChange("template <typename Foo>\n"
- "void foo() {}",
- Style);
- verifyNoChange("template <typename Foo, typename Bar>\n"
- "void foo() {}",
- Style);
- // It should allow a line break, even when the typename is short:
+ // multiple lines.
+ verifyFormat("template <typename Foo>\n"
+ "void foo() {}",
+ Style);
+ verifyFormat("template <typename Foo, typename Bar>\n"
+ "void foo() {}",
+ Style);
+ // It should allow a line break, even when the typename is short.
+ // verifyNoChange is needed because the default behavior is one line.
verifyNoChange("template <\n"
" typename Foo\n"
">\n"
>From 9277a685c7a0199fff20677759d663254de9189f Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Sun, 12 Jan 2025 12:08:16 -0800
Subject: [PATCH 8/8] switch from bool to enum
---
clang/docs/ClangFormatStyleOptions.rst | 42 +++++++++++++--------
clang/include/clang/Format/Format.h | 43 +++++++++++++---------
clang/lib/Format/ContinuationIndenter.cpp | 5 ++-
clang/lib/Format/Format.cpp | 11 +++++-
clang/lib/Format/TokenAnnotator.cpp | 2 +-
clang/unittests/Format/ConfigParseTest.cpp | 7 +++-
clang/unittests/Format/FormatTest.cpp | 2 +-
7 files changed, 74 insertions(+), 38 deletions(-)
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index ca92a073b41e45..6df9c8028e7dd6 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -3423,24 +3423,36 @@ the configuration (without a prefix: ``Auto``).
.. _BreakBeforeTemplateCloser:
-**BreakBeforeTemplateCloser** (``Boolean``) :versionbadge:`clang-format 20` :ref:`¶ <BreakBeforeTemplateCloser>`
- If ``true``, a line break will be placed before the ``>`` in a multiline
- template declaration.
+**BreakBeforeTemplateCloser** (``BreakBeforeTemplateCloserStyle``) :versionbadge:`clang-format 20` :ref:`¶ <BreakBeforeTemplateCloser>`
+ The style of when a line break will be placed before the ``>`` that closes
+ a template.
- .. code-block:: c++
+ Possible values:
+
+ * ``BBTCS_Never`` (in configuration: ``Never``)
+ Never break before a template closer.
+
+ .. code-block:: c++
+
+ template <typename Foo, typename Bar>
+
+ template <
+ typename Foo,
+ typename Bar>
+
+ * ``BBTCS_Multiline`` (in configuration: ``Multiline``)
+ Break before a template closer if the template spans more than one line.
+
+ .. code-block:: c++
+
+ template <typename Foo, typename Bar>
+
+ template <
+ typename Foo,
+ typename Bar
+ >
- true:
- template <
- typename Foo,
- typename Bar,
- typename Baz
- >
- false:
- template <
- typename Foo,
- typename Bar,
- typename Baz>
.. _BreakBeforeTernaryOperators:
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 5132e38ea02ec6..d5706a807b0dae 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -2252,24 +2252,33 @@ struct FormatStyle {
/// \version 16
BreakBeforeInlineASMColonStyle BreakBeforeInlineASMColon;
- /// If ``true``, a line break will be placed before the ``>`` in a multiline
- /// template declaration.
- /// \code
- /// true:
- /// template <
- /// typename Foo,
- /// typename Bar,
- /// typename Baz
- /// >
- ///
- /// false:
- /// template <
- /// typename Foo,
- /// typename Bar,
- /// typename Baz>
- /// \endcode
+ /// Different styles for whether to break before a template closer.
+ enum BreakBeforeTemplateCloserStyle : int8_t {
+ /// Never break before a template closer.
+ /// \code
+ /// template <typename Foo, typename Bar>
+ ///
+ /// template <
+ /// typename Foo,
+ /// typename Bar>
+ /// \endcode
+ BBTCS_Never,
+ /// Break before a template closer if the template spans more than one line.
+ /// \code
+ /// template <typename Foo, typename Bar>
+ ///
+ /// template <
+ /// typename Foo,
+ /// typename Bar
+ /// >
+ /// \endcode
+ BBTCS_Multiline,
+ };
+
+ /// The style of when a line break will be placed before the ``>`` that closes
+ /// a template.
/// \version 20
- bool BreakBeforeTemplateCloser;
+ BreakBeforeTemplateCloserStyle BreakBeforeTemplateCloser;
/// If ``true``, ternary operators will be placed after line breaks.
/// \code
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 8e7f0d88f81742..b3beb43793c259 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -407,7 +407,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
if (CurrentState.BreakBeforeClosingParen && Current.is(tok::r_paren))
return true;
if (CurrentState.BreakBeforeClosingAngle && Current.is(TT_TemplateCloser) &&
- Style.BreakBeforeTemplateCloser) {
+ Style.BreakBeforeTemplateCloser == FormatStyle::BBTCS_Multiline) {
return true;
}
if (Style.Language == FormatStyle::LK_ObjC &&
@@ -1378,7 +1378,8 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
State.Stack.size() > 1) {
return State.Stack[State.Stack.size() - 2].LastSpace;
}
- if (Current.is(TT_TemplateCloser) && Style.BreakBeforeTemplateCloser &&
+ if (Current.is(TT_TemplateCloser) &&
+ Style.BreakBeforeTemplateCloser != FormatStyle::BBTCS_Never &&
State.Stack.size() > 1) {
return State.Stack[State.Stack.size() - 2].LastSpace;
}
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index e421880d4cf34c..30a0d7b1a5d2c4 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -256,6 +256,15 @@ struct ScalarEnumerationTraits<FormatStyle::BreakBeforeInlineASMColonStyle> {
}
};
+template <>
+struct ScalarEnumerationTraits<FormatStyle::BreakBeforeTemplateCloserStyle> {
+ static void enumeration(IO &IO,
+ FormatStyle::BreakBeforeTemplateCloserStyle &Value) {
+ IO.enumCase(Value, "Never", FormatStyle::BBTCS_Never);
+ IO.enumCase(Value, "Multiline", FormatStyle::BBTCS_Multiline);
+ }
+};
+
template <>
struct ScalarEnumerationTraits<FormatStyle::BreakBinaryOperationsStyle> {
static void enumeration(IO &IO,
@@ -1534,7 +1543,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.BreakBeforeTemplateCloser = FormatStyle::BBTCS_Never;
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 98c0c09811b9b5..dcc9469aac6774 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -6325,7 +6325,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
return false;
if (Right.is(TT_TemplateCloser))
- return Style.BreakBeforeTemplateCloser;
+ return Style.BreakBeforeTemplateCloser != FormatStyle::BBTCS_Never;
if (Right.is(tok::r_square) && Right.MatchingParen &&
Right.MatchingParen->is(TT_LambdaLSquare)) {
return false;
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index ead9662ba54801..785c0901c720fc 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -166,7 +166,6 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
CHECK_PARSE_BOOL(BinPackArguments);
CHECK_PARSE_BOOL(BreakAdjacentStringLiterals);
CHECK_PARSE_BOOL(BreakAfterJavaFieldAnnotations);
- CHECK_PARSE_BOOL(BreakBeforeTemplateCloser);
CHECK_PARSE_BOOL(BreakBeforeTernaryOperators);
CHECK_PARSE_BOOL(BreakStringLiterals);
CHECK_PARSE_BOOL(CompactNamespaces);
@@ -424,6 +423,12 @@ TEST(ConfigParseTest, ParsesConfiguration) {
CHECK_PARSE("BreakBeforeBinaryOperators: true", BreakBeforeBinaryOperators,
FormatStyle::BOS_All);
+ Style.BreakBeforeTemplateCloser = FormatStyle::BBTCS_Never;
+ CHECK_PARSE("BreakBeforeTemplateCloser: Multiline", BreakBeforeTemplateCloser,
+ FormatStyle::BBTCS_Multiline);
+ CHECK_PARSE("BreakBeforeTemplateCloser: Never", BreakBeforeTemplateCloser,
+ FormatStyle::BBTCS_Never);
+
Style.BreakBinaryOperations = FormatStyle::BBO_Never;
CHECK_PARSE("BreakBinaryOperations: OnePerLine", BreakBinaryOperations,
FormatStyle::BBO_OnePerLine);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index b01139ebb8864c..6b51c26c8ee03d 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11134,7 +11134,7 @@ TEST_F(FormatTest, BreakBeforeTemplateCloser) {
"void foo() {}",
Style);
- Style.BreakBeforeTemplateCloser = true;
+ Style.BreakBeforeTemplateCloser = FormatStyle::BBTCS_Multiline;
// BreakBeforeTemplateCloser should NOT force template declarations onto
// multiple lines.
verifyFormat("template <typename Foo>\n"
More information about the cfe-commits
mailing list