clang-format: царь-костыль 🩼
Я раньше писал про clang-tidy в этом блоге. Он нужен для проверки кода на качество. У него модульный вид - каждый может написать свою проверку и использовать множество независимых друг от друга проверок. Он работает на уровне AST, то есть код проходит лексический и синтаксический анализ до тулзы.
А clang-format это еще одна тулза, нужная для форматирования исходного кода - чтобы было нужное количество пробелов, отсортированные
#include и прочее. Он работает на уровне токенов, то есть код проходит только лексический анализ до тулзы.То есть
clang-format очень приблизительно понимает, что перед ним за токен и что нужно сделать. Например, текстclass A: B {
ему это видится как последовательность токенов(kw_class) (identifier) (colon) (identifier) (l_brace)
И clang-format применяет серию захардкоженных правил поверх этих токенов, с поддержкой разной фигни как стека вложенности для скобок. Никакой модульности нет, то есть все правила написаны прямо в глубине тулзы.Например, в какой-то момент в середине работы вызывается метод WhitespaceManager::generateReplacements, который поправляет пробелы, и в нем внутри метод WhitespaceManager::alignArrayInitializers, чтобы поправить пробелы в массивах.
Совсем без семантики форматировать сложно, поэтому
clang-format перед форматированием "аннотирует" токены дополнительными данными: сопоставляет каждому Token структуру FormatToken.Там есть всякие поля, как bool IsArrayInitializer (то что этот токен - начало array initialization);
или FormatToken *MatchingParen (ссылка на закрывающую скобку).
Работает все при таком подходе очень хреново 😣. Из стандартных ошибок - ставит много где лишние пробелы или портит лямбды.
Есть куча issue про clang-format, а чинить их значительно сложнее чем issue для
clang-tidy.Если в
clang-tidy область потенциальных правок - код отдельной проверки (максимум несколько сотен строк), то в clang-format это весь clang-format.Например, очень сложно починить такой пустяк как неработающее форматированое во вложенном внутри скобок array initializer. Дело в том, что форматирование полагается на "аннотацию" токенов, а оно именно такое для вложенных скобок, какое есть. Надо править "аннотатор", но это сложно и есть риск сломать что-то еще.
И так для многих issue - начинаешь разбираться в мелкой проблеме - почему ставится лишний пробел, раскрываешь всю цепочку причин, и получаешь мега-проблему, которую нереально починить.
Поэтому старайтесь делать модульные программы, чтобы уменьшить область потенциальных правок при починке бага 😎