Странные результаты с опционами лязг формата AlwaysBreakAfterReturnType и AfterFunction - PullRequest
4 голосов
/ 28 марта 2020

формат clang версии 9.0.1, примененный к коду C ++.

Сочетание AlwaysBreakAfterReturnType и AfterFunction дает мне странные результаты. Взаимодействие с различными параметрами кажется довольно тонким, поэтому мне интересно, что мне нужно сделать, чтобы получить желаемый результат (который будет).

Во-первых, форматируемый код.

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

Обратите внимание, что единственное различие между функциями xy1 и xy2 заключается в том, что xy1 предоставляет имя для этого последнего параметра, а xy2 не называет ни одного из его параметров.

Далее содержимое минимального файла .clang-формата.

---
BasedOnStyle:  LLVM
AlwaysBreakAfterReturnType: TopLevelDefinitions

Запуск clang-формата отформатирует исходный код следующим образом.

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, и это именно то, что я ожидал.

Если я go чуть дальше и форсирую разрыв для шаблона, то я получаю этот файл в формате .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 полностью игнорирует запрос на разрыв после возвращаемого типа.

Тонкое взаимодействие между различными параметрами сбивает с толку, и я не смог придумать способ получить то, что я хочу, в основном для функций, у которых нет явных аргументов для форматирования так же, как те, которые есть явные аргументы.

Опять же, обратите внимание на тонкую разницу между xy1 и xy2. xy1 имеет по крайней мере один именованный параметр, в то время как xy2 не имеет именованных параметров - но не имеет bar.

Обратите внимание также, что обычная функция bar не имеет именованных параметров и все же он отформатирован правильно, в то время как шаблон функции xy2 все еще не отформатирован должным образом.

Какая комбинация опций magi c приведет к тому, что xy2 будет отформатирован так же, как xy1 и bar?

Спасибо.

1 Ответ

2 голосов
/ 31 марта 2020

Немного поэкспериментировав, я почти уверен, что «комбинации магов c» не существует. Кажется, в clang-формате есть проблема с отсутствующими именами параметров.

Я открыл отчет об ошибке: 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>{};
}

(с использованием вашей последней конфигурации)

...