https://github.com/leijurv updated https://github.com/llvm/llvm-project/pull/118046
>From 1caf823165b16f6701993d586df51d5cdbf0885e Mon Sep 17 00:00:00 2001 From: Leijurv <leij...@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 <leij...@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 <leij...@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 <leij...@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 <leij...@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 <leij...@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 <leij...@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 <leij...@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" _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits