Reputation: 28339
clang-format version 9.0.1, applied to C++ code.
The combination of AlwaysBreakAfterReturnType
and AfterFunction
is giving me strange results. The interaction with different options seems quite subtle, so I wonder what I need to do to get my desired result (which is coming).
First, the code being formatted.
int foo(int, double);
int bar(int, double) { return 42; }
template <typename T, typename U> XY<T, U> xy1(X, Y y) { return XY<T, U>{}; }
template <typename T, typename U> XY<T, U> xy2(X, Y) { return XY<T, U>{}; }
Note that the only difference between the functions xy1
and xy2
is that xy1
provides a name for tis last parameter, while xy2
does not name any of its paramteres.
Next, the contents of a minimal .clang-format file.
---
BasedOnStyle: LLVM
AlwaysBreakAfterReturnType: TopLevelDefinitions
Running clang-format will format the original code as follows.
int foo(int, double);
int
bar(int, double) {
return 42;
}
template <typename T, typename U>
XY<T, U>
xy1(X, Y y) {
return XY<T, U>{};
}
template <typename T, typename U>
XY<T, U>
xy2(X, Y) {
return XY<T, U>{};
}
However, I want the opening curly brace for the function on its own line, not packed just to the right of the function.
From the docs, I should set BraceWrapping/AfterFunction
to true, resulting in the following .clang-format file.
---
BasedOnStyle: LLVM
AlwaysBreakAfterReturnType: TopLevelDefinitions
BraceWrapping:
AfterFunction: true
BreakBeforeBraces: Custom
This results in the following formatting result.
int foo(int, double);
int
bar(int, double)
{
return 42;
}
template <typename T, typename U>
XY<T, U>
xy1(X, Y y)
{
return XY<T, U>{};
}
template <typename T, typename U> XY<T, U> xy2(X, Y) { return XY<T, U>{}; }
This is what I expect, except for the formatting of the function xy2
, which is just nothing like I'd expect, and not even close to the formatting for xy1
, which is exactly what I'd expect.
If I go a bit further, and force a break for the template, then I end up with this .clang-format file...
---
BasedOnStyle: LLVM
AlwaysBreakAfterReturnType: TopLevelDefinitions
AlwaysBreakTemplateDeclarations: Yes
BraceWrapping:
AfterFunction: true
BreakBeforeBraces: Custom
which produces this formatted output.
int foo(int, double);
int
bar(int, double)
{
return 42;
}
template <typename T, typename U>
XY<T, U>
xy1(X, Y y)
{
return XY<T, U>{};
}
template <typename T, typename U>
XY<T, U> xy2(X, Y)
{
return XY<T, U>{};
}
This is closer, but the formatting for xy2
completely ignores the request to break after the return type.
The subtle interactions between the different options is q bit confusing, and I have not been able to come up with a way to get what I want, which is basically for functions that have no explicit arguments to get formatted the same as those that have explicit arguments.
Again, note the subtle difference between xy1
and xy2
. xy1
has at least one named parameter, while xy2
does not have any named parameters - but neither does bar
.
Note also that the regular function bar
does not have any named parameters and yet it is formatted correctly, while the function template xy2
is still not formatted properly.
What magic combination of options will cause xy2
to be formatted the same as xy1
and bar
?
Thanks.
Upvotes: 4
Views: 763
Reputation: 2670
This is resolved in clang-format v14 and above (maybe even 13)
Your issue was migrated to github during the recent move of the LLVM bug tracker
https://github.com/llvm/llvm-project/issues/44720
Upvotes: 0
Reputation: 3571
After experimenting a bit myself, I am pretty sure that there is no "magic combination". clang-format seems to have a problem with the missing parameter names.
I opened a bug report: https://bugs.llvm.org/show_bug.cgi?id=45375
In the meantime:
If you can use C++17, there is a workaround by using the [[maybe_unused]]
attribute in the second template function:
template <typename T, typename U>
XY<T, U>
xy2([[maybe_unused]] X x, Y)
{
return XY<T, U>{};
}
(using your last config)
Upvotes: 2