diff options
author | leijurv <leijurv@gmail.com> | 2025-02-06 01:15:47 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-02-06 01:15:47 -0800 |
commit | d2b45ce100d641a8f1690e30843bb9c5ea71ab86 (patch) | |
tree | ce6d7d8789e85d82656f19a99116801a58dcc2ac /clang/unittests | |
parent | 7ef33e609c45515de9db1b5222fe6e05edd76c94 (diff) | |
download | llvm-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.cpp | 1 | ||||
-rw-r--r-- | clang/unittests/Format/FormatTest.cpp | 230 |
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; |