Clang-Include-Fixer

与其他语言相比,C++ 的一个主要缺点是需要手动管理任何文件中的 #include 指令。 clang-include-fixer 通过提供一种自动方式来添加 #include 指令来解决此问题的一个方面,该指令用于一个翻译单元中缺少的符号。

在插入缺少的 #include 时,clang-include-fixer 会将所有缺少前缀命名空间限定符的未识别符号的实例添加缺少的命名空间限定符。

设置

要使用 clang-include-fixer,需要两个数据库。这两个数据库都可以使用现有工具生成。

  • 编译数据库。包含项目中任何给定文件的编译器命令,可以通过 CMake 生成,请参阅 如何为 LLVM 设置工具

  • 符号索引。包含项目中的所有符号信息,以将给定的标识符与头文件匹配。

理想情况下,这两个数据库(compile_commands.jsonfind_all_symbols_db.yaml)都链接到它们对应的源代码树的根目录。然后,如果 clang-include-fixer 使用来自该树的源文件调用,则可以自动获取它们。请注意,默认情况下,由 CMake 生成的 compile_commands.json 不包括头文件,因此工具只能处理实现文件。

从编译数据库创建符号索引

包含修复器包含 find-all-symbols,这是一个工具,用于通过解析编译数据库中列出的所有源文件,从编译数据库创建 YAML 格式的符号数据库。以下命令列表展示了如何为 LLVM 设置数据库,任何由 CMake 构建的项目都应该遵循类似的步骤。

$ cd path/to/llvm-build
$ ninja find-all-symbols // build find-all-symbols tool.
$ ninja clang-include-fixer // build clang-include-fixer tool.
$ ls compile_commands.json # Make sure compile_commands.json exists.
  compile_commands.json
$ path/to/llvm/source/clang-tools-extra/clang-include-fixer/find-all-symbols/tool/run-find-all-symbols.py
  ... wait as clang indexes the code base ...
$ ln -s $PWD/find_all_symbols_db.yaml path/to/llvm/source/ # Link database into the source tree.
$ ln -s $PWD/compile_commands.json path/to/llvm/source/ # Also link compilation database if it's not there already.
$ cd path/to/llvm/source
$ /path/to/clang-include-fixer -db=yaml path/to/file/with/missing/include.cpp
  Added #include "foo.h"

集成到 Vim

要在 Vim 中对可能未保存的缓冲区运行 clang-include-fixer。将以下按键绑定添加到您的 .vimrc

noremap <leader>cf :pyf path/to/llvm/source/clang-tools-extra/clang-include-fixer/tool/clang-include-fixer.py<cr>

这将为 NORMAL 和 VISUAL 模式启用 clang-include-fixer。如果您需要在其他键上使用 clang-include-fixer,请将 <leader>cf 更改为其他绑定。 <leader> 键 是对由 mapleader 变量定义的特定键的引用,默认情况下绑定到反斜杠。

确保 vim 可以找到 clang-include-fixer

  • clang-include-fixer 的路径添加到 PATH 环境变量。

  • 或在 vimrc 中设置 g:clang_include_fixer_pathlet g:clang_include_fixer_path=path/to/clang-include-fixer

您可以通过设置 let g:clang_include_fixer_maximum_suggested_headers=5 来自定义显示的标题数量。

.vimrc 中的自定义设置

  • let g:clang_include_fixer_path = "clang-include-fixer"

    设置 clang-include-fixer 二进制文件路径。

  • let g:clang_include_fixer_maximum_suggested_headers = 3

    设置要显示的 #includes 的最大数量。默认值为 3。

  • let g:clang_include_fixer_increment_num = 5

    设置每次按下 m 时要显示的 #includes 的递增数量。默认值为 5。

  • let g:clang_include_fixer_jump_to_include = 0

    如果要跳转到新插入的 #include 行,请设置为 1。默认值为 0。

  • let g:clang_include_fixer_query_mode = 0

    如果要为光标下的符号插入 #include,请设置为 1。默认值为 0。与普通模式相比,此模式不会解析源文件,只从数据库中搜索符号,这比普通模式快。

有关更多详细信息,请参阅 clang-include-fixer.py

集成到 Emacs

要在 Emacs 中对可能未保存的缓冲区运行 clang-include-fixer。通过将包含该文件的目录添加到 load-path 并要求在您的 .emacs 中使用 clang-include-fixer,确保 Emacs 可以找到 clang-include-fixer.el

(add-to-list 'load-path "path/to/llvm/source/clang-tools-extra/clang-include-fixer/tool/"
(require 'clang-include-fixer)

在 Emacs 中,可以使用命令 M-x clang-include-fixer 调用该工具。这将插入定义第一个未定义符号的头文件;如果有多个头文件可以定义该符号,则会提示用户选择一个。

要包含定义光标所在符号的头文件,请运行 M-x clang-include-fixer-at-point

确保 Emacs 可以找到 clang-include-fixer

  • 要么将 clang-include-fixer 的父目录添加到 PATH 环境变量,要么自定义 Emacs 用户选项 clang-include-fixer-executable 以指向程序的文件名。

工作原理

为了从 Clang 获取最多的信息,clang-include-fixer 与解析一起运行,并从 Clang 的语义分析中接收回调。特别是,它重用了对拼写错误更正的现有支持。每当 Clang 尝试更正潜在的拼写错误时,它都会向包含修复器发出回调,然后包含修复器会查找相应的文件。此时,仍然可以使用丰富的查找信息,这在稍后的阶段的 AST 中不可用。

然后将应该更正拼写错误的标识符发送到数据库,如果返回头文件,则会将其作为包含指令添加到文件的顶部。

目前,clang-include-fixer 一次只插入一个包含项,以避免陷入后续错误。如果需要多个 #include 添加,则可以重新运行该程序,直到达到固定点。