https://github.com/leijurv created https://github.com/llvm/llvm-project/pull/118046
In clang-format, multiline templates have the `>` on the same line as the last parameter: ```c++ template< typename Foo, typename Bar, typename Baz> void foo() { ``` I would like to add an option to put the `>` on the next line, like this: ```c++ template< typename Foo, typename Bar, typename Baz > void foo() { ``` My reasoning is that it rubs me the wrong way and reminds me of this style of braces: ```c++ if (foo()) { bar();} ``` Most people agree this is better: ```c++ if (foo()) { bar(); } ``` >From b9886635c250fe765bf35c6b0e785f55b0749d52 Mon Sep 17 00:00:00 2001 From: Leijurv <leij...@gmail.com> Date: Thu, 28 Nov 2024 21:44:50 -0600 Subject: [PATCH] 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; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits