[clang] BreakBeforeTemplateClose (PR #118046)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Nov 28 20:06:48 PST 2024
https://github.com/leijurv updated https://github.com/llvm/llvm-project/pull/118046
>From b9886635c250fe765bf35c6b0e785f55b0749d52 Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Thu, 28 Nov 2024 21:44:50 -0600
Subject: [PATCH 1/3] BreakBeforeTemplateClose
---
clang/docs/ClangFormatStyleOptions.rst | 23 ++++++++++++++++++++++
clang/include/clang/Format/Format.h | 4 ++++
clang/lib/Format/ContinuationIndenter.cpp | 22 +++++++++++++++++++++
clang/lib/Format/Format.cpp | 2 ++
clang/unittests/Format/ConfigParseTest.cpp | 1 +
clang/unittests/Format/FormatTest.cpp | 21 ++++++++++++++++++++
6 files changed, 73 insertions(+)
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index dc34094b5053a9..b40507b289049d 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -3416,6 +3416,29 @@ the configuration (without a prefix: ``Auto``).
+
+.. _BreakBeforeTemplateClose:
+
+**BreakBeforeTemplateClose** (``Boolean``) :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/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 056fad2cc0ff8c..a8478060828072 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -2248,6 +2248,9 @@ struct FormatStyle {
/// \version 16
BreakBeforeInlineASMColonStyle BreakBeforeInlineASMColon;
+ /// If ``true``, a line break will be placed before the ``>`` in a multiline template declaration.
+ bool BreakBeforeTemplateClose;
+
/// If ``true``, ternary operators will be placed after line breaks.
/// \code
/// true:
@@ -5184,6 +5187,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..5887e9cef9011d 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -382,10 +382,28 @@ bool ContinuationIndenter::canBreak(const LineState &State) {
return !State.NoLineBreak && !CurrentState.NoLineBreak;
}
+bool isMatchingBraceOnSameLine(const FormatToken* Token) {
+ if (!Token->MatchingParen) {
+ return false;
+ }
+ const FormatToken* Matching = Token->MatchingParen;
+ const FormatToken* Current = Token;
+ while (Current && Current != Matching) {
+ if (Current->NewlinesBefore > 0) {
+ return false;
+ }
+ Current = Current->Previous;
+ }
+ return true;
+}
+
bool ContinuationIndenter::mustBreak(const LineState &State) {
const FormatToken &Current = *State.NextToken;
const FormatToken &Previous = *Current.Previous;
const auto &CurrentState = State.Stack.back();
+ if (Current.ClosesTemplateDeclaration && Style.BreakBeforeTemplateClose) {
+ return !isMatchingBraceOnSameLine(State.NextToken);
+ }
if (Style.BraceWrapping.BeforeLambdaBody && Current.CanBreakBefore &&
Current.is(TT_LambdaLBrace) && Previous.isNot(TT_LineComment)) {
auto LambdaBodyLength = getLengthToMatchingParen(Current, State.Stack);
@@ -1279,6 +1297,10 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
FormatToken &Current = *State.NextToken;
const auto &CurrentState = State.Stack.back();
+ if (Current.ClosesTemplateDeclaration && Style.BreakBeforeTemplateClose) {
+ return 0;
+ }
+
if (CurrentState.IsCSharpGenericTypeConstraint &&
Current.isNot(TT_CSharpGenericTypeConstraint)) {
return CurrentState.ColonPos + 2;
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index ee52972ce66f4a..a957129bbcf440 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1000,6 +1000,8 @@ 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);
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..3cd2e5d292e0f5 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11077,6 +11077,27 @@ TEST_F(FormatTest, WrapsTemplateDeclarationsWithComments) {
Style);
}
+TEST_F(FormatTest, BreakBeforeTemplateClose) {
+ FromatStyle Style = getLLVMStyle();
+ verifyFormat("template <typename Foo>\nvoid foo() {}", Style);
+ verifyFormat("template <\n typename Foo>\nvoid foo() {}", Style);
+ // when BreakBeforeTemplateClose is off, this line break is removed:
+ verifyFormat("template <\n typename Foo\n>\nvoid foo() {}",
+ "template <\n typename Foo>\nvoid foo() {}", Style);
+ Style.BreakBeforeTemplateClose = true;
+ // BreakBeforeTemplateClose should NOT force multiline templates
+ verifyFormat("template <typename Foo>\nvoid foo() {}", Style);
+ verifyFormat("template <typename Foo, typename Bar>\nvoid foo() {}", Style);
+ // it should allow a line break:
+ verifyFormat("template <\n typename Foo\n>\nvoid foo() {}", Style);
+ verifyFormat("template <\n typename Foo,\n typename Bar\n>\nvoid foo() {}", Style);
+ // it should add a line break if not already present:
+ verifyFormat("template <\n typename Foo>\nvoid foo() {}",
+ "template <\n typename Foo\n>\nvoid foo() {}", Style);
+ verifyFormat("template <\n typename Foo,\n typename Bar>\nvoid foo() {}",
+ "template <\n typename Foo,\n typename Bar\n>\nvoid foo() {}", Style);
+}
+
TEST_F(FormatTest, WrapsTemplateParameters) {
FormatStyle Style = getLLVMStyle();
Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;
>From 08f32c688238ae7c5a007c20f84f1eb3b1b49c1b Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Thu, 28 Nov 2024 21:59:53 -0600
Subject: [PATCH 2/3] typo
---
clang/unittests/Format/FormatTest.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 3cd2e5d292e0f5..afadf1eb5e9137 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11078,7 +11078,7 @@ TEST_F(FormatTest, WrapsTemplateDeclarationsWithComments) {
}
TEST_F(FormatTest, BreakBeforeTemplateClose) {
- FromatStyle Style = getLLVMStyle();
+ FormatStyle Style = getLLVMStyle();
verifyFormat("template <typename Foo>\nvoid foo() {}", Style);
verifyFormat("template <\n typename Foo>\nvoid foo() {}", Style);
// when BreakBeforeTemplateClose is off, this line break is removed:
>From 16e08d6904e89f6c14d3c74ad0cd9ff39420bbc8 Mon Sep 17 00:00:00 2001
From: Leijurv <leijurv at gmail.com>
Date: Thu, 28 Nov 2024 22:06:37 -0600
Subject: [PATCH 3/3] format
---
clang/include/clang/Format/Format.h | 3 ++-
clang/lib/Format/ContinuationIndenter.cpp | 18 +++++++-----------
clang/lib/Format/Format.cpp | 3 +--
clang/unittests/Format/FormatTest.cpp | 14 +++++++++-----
4 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index a8478060828072..d9cc6959d064f6 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -2248,7 +2248,8 @@ struct FormatStyle {
/// \version 16
BreakBeforeInlineASMColonStyle BreakBeforeInlineASMColon;
- /// If ``true``, a line break will be placed before the ``>`` in a multiline template declaration.
+ /// If ``true``, a line break will be placed before the ``>`` in a multiline
+ /// template declaration.
bool BreakBeforeTemplateClose;
/// If ``true``, ternary operators will be placed after line breaks.
diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp
index 5887e9cef9011d..3d78647ada0f62 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -382,16 +382,14 @@ bool ContinuationIndenter::canBreak(const LineState &State) {
return !State.NoLineBreak && !CurrentState.NoLineBreak;
}
-bool isMatchingBraceOnSameLine(const FormatToken* Token) {
- if (!Token->MatchingParen) {
+bool isMatchingBraceOnSameLine(const FormatToken *Token) {
+ if (!Token->MatchingParen)
return false;
- }
- const FormatToken* Matching = Token->MatchingParen;
- const FormatToken* Current = Token;
+ const FormatToken *Matching = Token->MatchingParen;
+ const FormatToken *Current = Token;
while (Current && Current != Matching) {
- if (Current->NewlinesBefore > 0) {
+ if (Current->NewlinesBefore > 0)
return false;
- }
Current = Current->Previous;
}
return true;
@@ -401,9 +399,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
const FormatToken &Current = *State.NextToken;
const FormatToken &Previous = *Current.Previous;
const auto &CurrentState = State.Stack.back();
- if (Current.ClosesTemplateDeclaration && Style.BreakBeforeTemplateClose) {
+ if (Current.ClosesTemplateDeclaration && Style.BreakBeforeTemplateClose)
return !isMatchingBraceOnSameLine(State.NextToken);
- }
if (Style.BraceWrapping.BeforeLambdaBody && Current.CanBreakBefore &&
Current.is(TT_LambdaLBrace) && Previous.isNot(TT_LineComment)) {
auto LambdaBodyLength = getLengthToMatchingParen(Current, State.Stack);
@@ -1297,9 +1294,8 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) {
FormatToken &Current = *State.NextToken;
const auto &CurrentState = State.Stack.back();
- if (Current.ClosesTemplateDeclaration && Style.BreakBeforeTemplateClose) {
+ if (Current.ClosesTemplateDeclaration && Style.BreakBeforeTemplateClose)
return 0;
- }
if (CurrentState.IsCSharpGenericTypeConstraint &&
Current.isNot(TT_CSharpGenericTypeConstraint)) {
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index a957129bbcf440..3523f843d86b50 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1000,8 +1000,7 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
IO.mapOptional("BreakBeforeInlineASMColon",
Style.BreakBeforeInlineASMColon);
- IO.mapOptional("BreakBeforeTemplateClose",
- Style.BreakBeforeTemplateClose);
+ IO.mapOptional("BreakBeforeTemplateClose", Style.BreakBeforeTemplateClose);
IO.mapOptional("BreakBeforeTernaryOperators",
Style.BreakBeforeTernaryOperators);
IO.mapOptional("BreakBinaryOperations", Style.BreakBinaryOperations);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index afadf1eb5e9137..12a934d5c0fe90 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11083,19 +11083,23 @@ TEST_F(FormatTest, BreakBeforeTemplateClose) {
verifyFormat("template <\n typename Foo>\nvoid foo() {}", Style);
// when BreakBeforeTemplateClose is off, this line break is removed:
verifyFormat("template <\n typename Foo\n>\nvoid foo() {}",
- "template <\n typename Foo>\nvoid foo() {}", Style);
+ "template <\n typename Foo>\nvoid foo() {}", Style);
Style.BreakBeforeTemplateClose = true;
// BreakBeforeTemplateClose should NOT force multiline templates
verifyFormat("template <typename Foo>\nvoid foo() {}", Style);
verifyFormat("template <typename Foo, typename Bar>\nvoid foo() {}", Style);
// it should allow a line break:
verifyFormat("template <\n typename Foo\n>\nvoid foo() {}", Style);
- verifyFormat("template <\n typename Foo,\n typename Bar\n>\nvoid foo() {}", Style);
+ verifyFormat(
+ "template <\n typename Foo,\n typename Bar\n>\nvoid foo() {}",
+ Style);
// it should add a line break if not already present:
verifyFormat("template <\n typename Foo>\nvoid foo() {}",
- "template <\n typename Foo\n>\nvoid foo() {}", Style);
- verifyFormat("template <\n typename Foo,\n typename Bar>\nvoid foo() {}",
- "template <\n typename Foo,\n typename Bar\n>\nvoid foo() {}", Style);
+ "template <\n typename Foo\n>\nvoid foo() {}", Style);
+ verifyFormat(
+ "template <\n typename Foo,\n typename Bar>\nvoid foo() {}",
+ "template <\n typename Foo,\n typename Bar\n>\nvoid foo() {}",
+ Style);
}
TEST_F(FormatTest, WrapsTemplateParameters) {
More information about the cfe-commits
mailing list