【问题标题】:How to create category for external headers in clang-format?如何以 clang 格式为外部标题创建类别?
【发布时间】:2019-04-22 09:42:13
【问题描述】:

我想配置 clang-format 以在 C++ 中对包含的标头进行如下排序:

  • 主标头(与当前 cpp 文件关联),
  • 通过“”包含的本地标头,
  • 通过 ,
  • 包含的其他标头
  • 来自特定外部库(例如 boost、catch2)的标头,
  • 系统/标准头文件。

我在 macOS 上使用 clang-format 8.0.0。 我目前的配置(sn-p只和include相关)如下:

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 以获得预期结果?

【问题讨论】:

    标签: c++ regex clang llvm-clang clang-format


    【解决方案1】:

    问题是氏族格式使用POSIX ERE regexes。而且那些不支持单词边界。

    所以&lt;catch2/catch.hpp&gt; 永远不会匹配第二条规则。然后,为匹配的第三条规则评估相同的字符串。

    如果它符合第二条规则,它会停在那里,但由于它没有,它会继续下一条规则。

    只需删除正则表达式中的所有\b。删除它们是安全的,因为你已经有了单词边界:左边是&lt;,右边是/,所以即使你可以使用单词边界,它也没有用。

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

    注意:请记住,[] 内的 - 应该用反斜杠转义,除非它位于最后一个位置。那是因为它用于范围。因此,当您写 [A-Za-z0-9.\/-_] 时,您的意思是 A-Za-z0-9.range/_,这可能不是您的意思。

    【讨论】:

    • 不幸的是,这些方法都不起作用。在第一种情况下(重新排序)没有任何变化,而在第二种情况下,catch2 标头仍属于同一类别 + 系统标头在中间移动。我认为 clang-format 在那里期待一些不同的东西。
    • 很遗憾,clang 格式似乎使用不支持前瞻断言的 POSIX ERE 正则表达式。反正我觉得还是可行的,我再考虑一下……
    • 你有很多库,比如 boost 和 catch2 还是只有这 2 个? @eclipse
    • 好吧,在这个特定的项目中只有这 2 个,但理想情况下,我希望为其他项目提供通用解决方案。为什么重要?
    • 因为即使它是可行的,每个库都会变得更狡猾。看看这个例子:regex101.com/r/3x2Oxr/3 对于每个库,正则表达式都会增长。给定一些输入库,也许您可​​以创建自己的脚本来生成此类正则表达式。 @eclipse
    【解决方案2】:

    我通过使用和修改来自 clang-format 文档的示例来实现此选项:

    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 正则表达式更改为更像原始 example

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

    另外,我添加了 \Q 和 \E 修饰符以避免 Julio 提到的问题。 现在一切都按预期工作。但是我仍然不知道为什么问题帖子中的解决方案不起作用。

    【讨论】:

    • posix ere 正则表达式可能不支持单词边界。尝试使用您的原始规则并从第二条规则中删除所有\b
    • 是的,你是对的。没有 \b 原始方法有效。谢谢!
    • 如果您使用原始方法,请记住将- 转义或将其放在类[A-Za-z0-9\/_-] 的末尾。我将添加我的评论作为答案,因为它似乎解决了最初的问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-09
    • 1970-01-01
    • 2015-08-21
    • 2019-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多