介绍
clang-tidy是一个开源的lint工具。
它的主要作用:
a) 自动化检查代码格式是否满足要求
b) 增强编译器的检查功能,提示可能出错或有性能问题的代码
背靠clang/llvm的强大能力,clang-tidy提供了极强的定制和扩展能力。
这使得很多新的大型C/C++项目从项目初始就启用clang-tidy。
vscode上使用clang-tidy
在vscode上使用clang-tidy很简单,只需要安装Clang-Tidy插件就可以了。
该插件的基本原理是调用clang-tidy –export-fixes=- 输出文本,然后解析文本后组装为vs能识别的告警信息。
准备环境
安装clang-tidy并配置好插件
首先需要安装clang-tidy,使用apt安装或者自行编译都可以。
然后安装Clang-Tidy插件,并确保插件配置能找到clang-tidy的程序(确保路径或者PATH正确)。
为工程中的代码生成compile_commands.json
clang-tidy和许多clang体系工具一样,知道源代码编译命令后可以工作得更好。
由于源代码文件众多,实际上可操作的方法只有使用编译系统自动生成的编译命令记录compile_commands.json。使用cmake的体系,添加-DCMAKE_EXPORT_COMPILE_COMMANDS=ON就能自动生成该文件。其他构建体系也有类似的解决方案,可参考https://sarcasm.github.io/notes/dev/compilation-database.html 。
生成该文件后,还需要注意把这个.json放置到源代码的父目录下,否则clang-tidy会找不到。如果在${top_dir}/build中构建工程并生成了compile_commands.json,但是代码在${top_dir}/src中,则clang-tidy无法自动找到compile_commands.json,需要把其拷贝到${top_dir}下。
修复Clang-Tidy不支持中文的bug
Clang-Tidy使用了clang-tidy文本输出YAML格式的部分(来自 –export-fixes部分)。
示例如下:
1 | MainSourceFile: '/media/majiang/c6b38ac3-8b8a-4613-8259-dddbffe2f4cb/majiang/cpp_exercise/llvm_study_Kaleidoscope/./main.cpp' |
最核心的信息是FilePath和FileOffset,这两个信息给出了Vscode界面应该在哪里显示告警。
但不幸的是,FileOffset这个值是clang-tidy给其自动修复工具用的,所以其值是一个以byte计数的偏移。
而在vscode中,文件位置的offset不是以byte记的,而是以字符来计算的。如果混入了中文等多byte字符,则vscode中的offset数值将小于clang-tidy给出的FileOffset。
更加糟糕的是,vscode当前没有给出把一个FileOffset转换为行号和列号的接口。其只提供了TextDocument.positionAt(offset: number)。这里的offset是以字符记的。看起来vscode是把单个字符当做了最小单元(哪怕这个字符实际上对应多个byte,可能这样对上层抽象的处理更加容易)。
由于上面描述的问题,一旦代码中出现中文等多byte字符,Clang-Tidy插件给出的告警就会向下漂移(由于其调用了TextDocument.positionAt,并且传入的是以byte记的offset,所以计算出的lineno要更大)。
参考 https://github.com/notskm/vscode-clang-tidy/issues/13,已经有人提到了这个问题,并且作者也给出了与我同样的分析,但是没有提出解决方案。
但是,实际上clang-tidy在非YAML部分其实已经给出了正确的行号和列号,如下所示。
1 | main.cpp:46:3: warning: do not call c-style vararg functions [cppcoreguidelines-pro-type-vararg] |
很奇怪的是Clang-Tidy插件专门从这一行中提取了warning这个关键字用来计算提示信息的严重程度,但是没用这里的行号和列号。
一种快速的规避方案,可以就从这里提取行号和列号。参考如下补丁。
1 | --- /home/majiang/.vscode/extensions/notskm.clang-tidy-0.4.1/out/tidy.js |