Как создать категорию для внешних заголовков в кланг-формате?

Я хочу настроить clang-format для сортировки включенных заголовков на C ++ следующим образом:

  • основной заголовок (связанный с текущим файлом cpp),
  • локальные заголовки включены через "",
  • другие заголовки включаются с помощью ‹>,
  • заголовки из определенных внешних библиотек (например, boost, catch2),
  • системные / стандартные заголовки.

Я использую clang-format 8.0.0 на macOS. Моя текущая конфигурация (фрагмент, относящийся только к включенным) выглядит следующим образом:

SortIncludes: true
IncludeBlocks: Regroup
IncludeCategories:
  # Headers in <> without extension.
  - Regex:           '<([A-Za-z0-9\/-_])+>'
    Priority:        4
  # Headers in <> from specific external libraries.
  - Regex:           '<((\bboost\b)|(\bcatch2\b))\/([A-Za-z0-9.\/-_])+>'
    Priority:        3
  # Headers in <> with extension.
  - Regex:           '<([A-Za-z0-9.\/-_])+>'
    Priority:        2
  # Headers in "" with extension.
  - Regex:           '"([A-Za-z0-9.\/-_])+"'
    Priority:        1

В этой конфигурации я предполагаю, что системные / стандартные заголовки не имеют расширения. Это не будет работать с заголовками UNIX / POSIX. Главный заголовок определяется автоматически, и ему присваивается приоритет 0. Пока все работает, как ожидалось, за исключением категории для внешних библиотек. Похоже, clang-format присваивает ему приоритет 2.

Ожидаемый результат:

#include "test.h"

#include <allocator/region.hpp>
#include <page.hpp>
#include <page_allocator.hpp>
#include <test_utils.hpp>
#include <utils.hpp>
#include <zone_allocator.hpp>

#include <catch2/catch.hpp>     // <--------

#include <array>
#include <cmath>
#include <cstring>
#include <map>

Фактический результат:

#include "test.h"

#include <allocator/region.hpp>
#include <catch2/catch.hpp>     // <--------
#include <page.hpp>
#include <page_allocator.hpp>
#include <test_utils.hpp>
#include <utils.hpp>
#include <zone_allocator.hpp>

#include <array>
#include <cmath>
#include <cstring>
#include <map>

Как настроить приоритет 3 для получения ожидаемого результата?


person eclipse    schedule 22.04.2019    source источник


Ответы (2)


Проблема в том, что в формате Clan используются регулярные выражения POSIX ERE. И они не поддерживают границы слов.

Таким образом, <catch2/catch.hpp> никогда не будет соответствовать второму правилу. Затем та же строка оценивается для третьего правила, которое соответствует.

Если бы он соответствовал второму правилу, он бы остановился на этом, но поскольку это не так, он переходит к следующему правилу.

Просто удалите все \b из регулярного выражения. Их можно безопасно удалить, потому что у вас уже есть границы слов: слева у вас есть <, а справа у вас /, так что даже если бы вы могли использовать границы слов, это было бы бесполезно.

  - Regex:           '<(boost|catch2)\/([A-Za-z0-9.\/-_])+>'
    Priority:        3

ПРИМЕЧАНИЕ. Имейте в виду, что - внутри [] должен иметь обратную косую черту, если только она не находится на последней позиции. Это потому, что он используется для диапазонов. Поэтому, когда вы пишете [A-Za-z0-9.\/-_], вы имеете в виду A-Za-z0-9. или диапазон от / до _, что, вероятно, вы не имеете в виду. как это.

person Julio    schedule 22.04.2019
comment
К сожалению, ни один из этих способов не работает. В первом случае (переупорядочивание) ничего не меняется, а во втором заголовок catch2 все еще находится в той же категории + системные заголовки перемещаются посередине. Думаю, clang-format ожидает там чего-то другого. - person eclipse; 22.04.2019
comment
Жаль, похоже, что формат clang использует регулярные выражения POSIX ERE, которые не поддерживают утверждения с опережением. В любом случае, я думаю, что это все еще выполнимо, я подумаю ... - person Julio; 22.04.2019
comment
У вас много библиотек, таких как boost и catch2 или только эти 2? @затмение - person Julio; 22.04.2019
comment
Ну, в этом конкретном проекте только эти 2, но в идеале я хотел бы иметь общее решение для других проектов. Почему это имеет значение? - person eclipse; 22.04.2019
comment
Потому что даже это выполнимо, с каждой библиотекой становится все сложнее. Взгляните на этот пример: regex101.com/r/3x2Oxr/3 Для каждой библиотеки регулярное выражение увеличивается. Возможно, вы могли бы создать свой собственный скрипт для генерации таких регулярных выражений с учетом некоторых входных библиотек. @затмение - person Julio; 22.04.2019
comment
Это выглядит очень сложно ... Мне удалось найти решение (см. Мой собственный ответ), но он все еще не говорит мне, почему исходный подход не работает. В любом случае спасибо за ваши усилия. - person eclipse; 22.04.2019

Я заставил его работать, используя и изменяя пример из документации формата clang для этой опции:

SortIncludes: true
IncludeBlocks: Regroup
IncludeCategories:
  # Headers in <> without extension.
  - Regex:           '<([A-Za-z0-9\Q/-_\E])+>'
    Priority:        4
  # Headers in <> from specific external libraries.
  - Regex:           '<(catch2|boost)\/'
    Priority:        3
  # Headers in <> with extension.
  - Regex:           '<([A-Za-z0-9.\Q/-_\E])+>'
    Priority:        2
  # Headers in "" with extension.
  - Regex:           '"([A-Za-z0-9.\Q/-_\E])+"'
    Priority:        1

В частности, я изменил регулярное выражение с приоритетом 3, чтобы оно было больше похоже на исходный пример:

'^(<|"(gtest|gmock|isl|json)/)'

Кроме того, я добавил модификаторы \ Q и \ E, чтобы избежать проблемы, упомянутой Julio. Теперь все работает как положено. Однако я до сих пор не знаю, почему решение из вопроса не работает.

person eclipse    schedule 22.04.2019
comment
Вероятно, границы слов не поддерживаются в регулярных выражениях posix ere. Попробуйте использовать исходные правила и удалите все \b из второго правила. - person Julio; 22.04.2019
comment
Ага, ты прав. Без \ b оригинальный подход работает. Спасибо! - person eclipse; 22.04.2019
comment
Если вы используете исходный подход, не забудьте очистить - или поместить его в конец класса [A-Za-z0-9\/_-]. Я добавлю свой комментарий в качестве ответа, так как он, кажется, решает исходную проблему. - person Julio; 22.04.2019