aboutsummaryrefslogtreecommitdiff
path: root/clang/unittests
diff options
context:
space:
mode:
authorleijurv <leijurv@gmail.com>2025-02-06 01:15:47 -0800
committerGitHub <noreply@github.com>2025-02-06 01:15:47 -0800
commitd2b45ce100d641a8f1690e30843bb9c5ea71ab86 (patch)
treece6d7d8789e85d82656f19a99116801a58dcc2ac /clang/unittests
parent7ef33e609c45515de9db1b5222fe6e05edd76c94 (diff)
downloadllvm-d2b45ce100d641a8f1690e30843bb9c5ea71ab86.zip
llvm-d2b45ce100d641a8f1690e30843bb9c5ea71ab86.tar.gz
llvm-d2b45ce100d641a8f1690e30843bb9c5ea71ab86.tar.bz2
[clang-format] Add BreakBeforeTemplateCloser option (#118046)
In clang-format, multiline templates have the `>` on the same line as the last parameter: ```c++ template < typename Foo, typename Bar> void foo() { ``` I would like to add an option to put the `>` on the next line, like this: ```c++ template < typename Foo, typename Bar > void foo() { ``` An example of a large project that uses this style is NVIDIA's CUTLASS, here is an example: https://github.com/NVIDIA/cutlass/blob/main/include/cutlass/epilogue/dispatch_policy.hpp#L149-L156 My reasoning is that it reminds me of this style of braces: ```c++ if (foo()) { bar(); baz();} ``` Most people agree this is better: ```c++ if (foo()) { bar(); baz(); } ``` --------- Co-authored-by: Owen Pan <owenpiano@gmail.com>
Diffstat (limited to 'clang/unittests')
-rw-r--r--clang/unittests/Format/ConfigParseTest.cpp1
-rw-r--r--clang/unittests/Format/FormatTest.cpp230
2 files changed, 231 insertions, 0 deletions
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index 5bb1c00..0cb2a12 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -170,6 +170,7 @@ 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);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 253e504..a9fddc3 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -11224,6 +11224,236 @@ TEST_F(FormatTest, WrapsTemplateDeclarationsWithComments) {
Style);
}
+TEST_F(FormatTest, BreakBeforeTemplateCloser) {
+ auto Style = getLLVMStyle();
+ // Begin with tests covering the case where there is no constraint on the
+ // column limit.
+ Style.ColumnLimit = 0;
+ Style.BreakBeforeTemplateCloser = true;
+ // BreakBeforeTemplateCloser should NOT force template declarations onto
+ // multiple lines.
+ verifyFormat("template <typename Foo>\n"
+ "void foo() {}",
+ Style);
+ verifyFormat("template <typename Foo, typename Bar>\n"
+ "void foo() {}",
+ Style);
+ // It should add a line break before > 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 accordingly:
+ 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 from https://github.com/llvm/llvm-project/issues/80049:
+ verifyFormat(
+ "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"
+ ">;",
+ "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>>;",
+ Style);
+
+ // Test lambda goes to next line:
+ verifyFormat("void foo() {\n"
+ " auto lambda = []<\n"
+ " typename T\n"
+ " >(T t) {\n"
+ " };\n"
+ "}",
+ "void foo() {\n"
+ " auto lambda = []<\n"
+ " typename T>(T t){\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"
+ "}",
+ "void foo() {\n"
+ " auto lambda = []<\n"
+ " typename T, typename Foo>(T t){\n"
+ " };\n"
+ "}",
+ Style);
+ // Or on different lines:
+ verifyFormat("void foo() {\n"
+ " auto lambda = []<\n"
+ " typename T,\n"
+ " typename Foo\n"
+ " >(T t) {\n"
+ " };\n"
+ "}",
+ "void foo() {\n"
+ " auto lambda = []<\n"
+ " typename T,\n"
+ " typename Foo>(T t){\n"
+ " };\n"
+ "}",
+ Style);
+
+ // Test template usage goes to next line too:
+ verifyFormat("void foo() {\n"
+ " myFunc<\n"
+ " T\n"
+ " >();\n"
+ "}",
+ "void foo() {\n"
+ " myFunc<\n"
+ " T>();\n"
+ "}",
+ Style);
+
+ // Now test that it handles the cases when the column limit forces wrapping.
+ Style.ColumnLimit = 40;
+ // The typename goes on the first line if it fits:
+ verifyFormat("template <typename Fooooooooooooooooooo,\n"
+ " typename Bar>\n"
+ "void foo() {}",
+ Style);
+ verifyFormat("template <typename Foo,\n"
+ " typename Barrrrrrrrrrrrrrrrrr>\n"
+ "void foo() {}",
+ Style);
+ // Long names should be split in one step:
+ verifyFormat("template <\n"
+ " typename Foo,\n"
+ " typename Barrrrrrrrrrrrrrrrrrr\n"
+ ">\n"
+ "void foo() {}",
+ "template <typename Foo, typename Barrrrrrrrrrrrrrrrrrr>\n"
+ "void foo() {}",
+ Style);
+ verifyFormat("template <\n"
+ " typename Foooooooooooooooooooo,\n"
+ " typename Bar\n"
+ ">\n"
+ "void foo() {}",
+ "template <typename Foooooooooooooooooooo, typename Bar>\n"
+ "void foo() {}",
+ Style);
+ // Even when there is only one long name:
+ verifyFormat("template <\n"
+ " typename Foooooooooooooooooooo\n"
+ ">\n"
+ "void foo() {}",
+ "template <typename Foooooooooooooooooooo>\n"
+ "void foo() {}",
+ Style);
+ // Test lambda goes to next line if the type is looong:
+ verifyFormat("void foo() {\n"
+ " auto lambda =\n"
+ " []<\n"
+ " typename Loooooooooooooooooooooooooooooooooong\n"
+ " >(T t) {};\n"
+ " auto lambda =\n"
+ " [looooooooooooooong]<\n"
+ " typename Loooooooooooooooooooooooooooooooooong\n"
+ " >(T t) {};\n"
+ " auto lambda =\n"
+ " []<\n"
+ " typename T,\n"
+ " typename Loooooooooooooooooooooooooooooooooong\n"
+ " >(T t) {};\n"
+ // Nested:
+ " auto lambda =\n"
+ " []<\n"
+ " template <typename, typename>\n"
+ " typename Looooooooooooooooooong\n"
+ " >(T t) {};\n"
+ // Same idea, the "T" is now short rather than Looong:
+ " auto lambda =\n"
+ " []<template <typename, typename>\n"
+ " typename T>(T t) {};\n"
+ // Nested with long capture forces the style to block indent:
+ " auto lambda =\n"
+ " [loooooooooooooooooooong]<\n"
+ " template <typename, typename>\n"
+ " typename Looooooooooooooooooong\n"
+ " >(T t) {};\n"
+ // But *now* it stays block indented even when T is short:
+ " auto lambda =\n"
+ " [loooooooooooooooooooong]<\n"
+ " template <typename, typename>\n"
+ " typename T\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"
+ // Allow the nested template to be on the same line:
+ " auto lambda =\n"
+ " [loooooooooooooooooooong]<\n"
+ " template <typename Fooooooooo,\n"
+ " typename>\n"
+ " typename T\n"
+ " >(T t) {};\n"
+ "}",
+ Style);
+
+ // Test template usage goes to next line if the type is looong:
+ verifyFormat("void foo() {\n"
+ " myFunc<\n"
+ " Looooooooooooooooooooooooong\n"
+ " >();\n"
+ "}",
+ Style);
+ // Even a single type in the middle is enough to force it to block indent
+ // style:
+ verifyFormat("void foo() {\n"
+ " myFunc<\n"
+ " Foo, Foo, Foo,\n"
+ " Foooooooooooooooooooooooooooooo,\n"
+ " Foo, Foo, Foo, Foo\n"
+ " >();\n"
+ "}",
+ Style);
+}
+
TEST_F(FormatTest, WrapsTemplateParameters) {
FormatStyle Style = getLLVMStyle();
Style.AlignAfterOpenBracket = FormatStyle::BAS_DontAlign;