使用 clang 格式选项 AlwaysBreakAfterReturnType 和 AfterFunction 的奇怪结果

Strange results with clang-format options AlwaysBreakAfterReturnType and AfterFunction

clang-format 版本 9.0.1,适用于 C++ 代码。

AlwaysBreakAfterReturnTypeAfterFunction 的组合给我带来了奇怪的结果。与不同选项的交互似乎非常微妙,所以我想知道我需要做什么才能获得我想要的结果(即将到来)。

首先,正在格式化的代码。

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>{}; }

请注意,函数 xy1xy2 之间的唯一区别是 xy1 为最后一个参数提供了一个名称,而 xy2 没有为任何参数命名它的参数。

接下来,一个最小的 .clang 格式文件的内容。

---
BasedOnStyle:  LLVM
AlwaysBreakAfterReturnType: TopLevelDefinitions

运行 clang-format 将原代码格式化如下

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>{};
}

但是,我希望函数的左大括号单独占一行,而不是仅放在函数的右侧。

根据文档,我应该将 BraceWrapping/AfterFunction 设置为 true,从而生成以下 .clang 格式文件。

---
BasedOnStyle:  LLVM
AlwaysBreakAfterReturnType: TopLevelDefinitions
BraceWrapping:
    AfterFunction:   true
BreakBeforeBraces: Custom

这会产生以下格式化结果。

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>{}; }

这是我所期望的,除了函数 xy2 的格式外,这与我所期望的完全不同,甚至不接近 xy1 的格式,即正是我所期望的。

如果我更进一步,强制中断模板,那么我最终会得到这个 .clang 格式的文件...

---
BasedOnStyle:  LLVM
AlwaysBreakAfterReturnType: TopLevelDefinitions
AlwaysBreakTemplateDeclarations: Yes
BraceWrapping:
    AfterFunction:   true
BreakBeforeBraces: Custom

产生这种格式化的输出。

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>{};
}

这更接近,但是 xy2 的格式完全忽略了在 return 类型之后中断的请求。

不同选项之间微妙的相互作用有点令人困惑,我还没有想出一种方法来获得我想要的东西,这基本上是针对没有明确参数的函数来获得相同格式的作为那些有明确论点的人。

再次注意 xy1xy2 之间的细微差别。 xy1 至少有一个命名参数,而 xy2 没有任何命名参数 - 但 bar.

也没有

另请注意,常规函数 bar 没有任何命名参数,但格式正确,而函数模板 xy2 的格式仍然不正确。

什么神奇的选项组合会导致 xy2 的格式与 xy1bar 相同?

谢谢。

经过自己的试验,我很确定没有"magic combination"。 clang-format 似乎缺少参数名称有问题。

我打开了一个错误报告:https://bugs.llvm.org/show_bug.cgi?id=45375

同时:

如果您可以使用 C++17,则可以使用第二个模板函数中的 [[maybe_unused]] 属性来解决此问题:

template <typename T, typename U> 
XY<T, U> 
xy2([[maybe_unused]] X x, Y)
{
  return XY<T, U>{};
}

(使用您上次的配置)

这已在 clang-format v14 及更高版本(甚至可能是 13)中得到解决

在 LLVM 错误跟踪器的最近移动过程中,您的问题已迁移到 github

https://github.com/llvm/llvm-project/issues/44720