https://github.com/leijurv updated https://github.com/llvm/llvm-project/pull/118046
>From 79b3767b39d6d5d5c21bb461fb619651fb2443c5 Mon Sep 17 00:00:00 2001 From: Leijurv <leij...@gmail.com> Date: Fri, 29 Nov 2024 21:54:36 -0600 Subject: [PATCH] [clang-format] Add BreakBeforeTemplateClose option --- clang/docs/ClangFormatStyleOptions.rst | 23 +++++++ clang/docs/ReleaseNotes.rst | 1 + clang/include/clang/Format/Format.h | 20 ++++++ clang/lib/Format/ContinuationIndenter.cpp | 18 +++++ clang/lib/Format/Format.cpp | 2 + clang/unittests/Format/ConfigParseTest.cpp | 1 + clang/unittests/Format/FormatTest.cpp | 79 ++++++++++++++++++++++ 7 files changed, 144 insertions(+) diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 4be448171699ca..31ed9a10d7153d 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -3416,6 +3416,29 @@ 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..0c77c18b3e7f48 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -382,10 +382,25 @@ 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 +1294,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { FormatToken &Current = *State.NextToken; const auto &CurrentState = State.Stack.back(); + if (Current.ClosesTemplateDeclaration && Style.BreakBeforeTemplateClose) + return CurrentState.Indent - Style.ContinuationIndentWidth; + 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..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/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..1dffce7925a055 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -11077,6 +11077,85 @@ TEST_F(FormatTest, WrapsTemplateDeclarationsWithComments) { Style); } +TEST_F(FormatTest, BreakBeforeTemplateClose) { + FormatStyle Style = getGoogleStyle(FormatStyle::LK_Cpp); + Style.BreakTemplateDeclarations = FormatStyle::BTDS_Yes; + 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); +} + 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