clang-tidyとは
https://qiita.com/syoyo/items/0e75410c44ed73d4bdd7
要するに、問題のあるコードを報告したり直してくれるツール
VSCodeでclang-tidyを使うには
clangdを使う
https://clang.llvm.org/extra/clangd/
clang-tidyとclangdは別々のツールだったが、
LLVM 9.0からclangdからclang-tidyの機能を使えるようになった。
以下、Windows10で話を進めます。
clang-tidyを手に入れる
LLVMをインストールするとclang等と一緒についてくる。
LLVM公式サイト
http://llvm.org/
公式サイトにあるDownload!の下にあるLLVM 9.0.0(執筆時点)をクリック。
今回はWindows (64-bit)をダウンロード。
インストールして環境変数PathにLLVMのインストールディレクトリを追加する。
VSCodeに拡張を入れる
vscode-clangdという公式が出している拡張を入れる。
VSCode左下の歯車マークから設定を開く。
拡張機能のclangd configuration以下にある
Clangd: Argumentsに-clang-tidy
Clangd: Pathにclangd.exeを入れる。

clangdとclang-tidyに必要なファイル
clangdに必要なファイル
compile_commands.jsonまたはcompile_flags.txt
これらのファイルにはコンパイルに使用するフラグが保存されている。
どちらかのファイルをプロジェクトルートに置く。
両方のファイルが存在する場合、compile_flags.txtが使用されるようだ
compile_commands.json
compile_commands.jsonはCMakeでCMAKE_EXPORT_COMPILE_COMMANDSフラグを使うと生成できる。
だたしこの方法ではソースファイルに関する情報しか出力されず、ヘッダファイルの編集にclangdを使えない。
compile_commands.jsonにヘッダー情報を含めたいならPythonのcompdbを使う。
この方法ではプロジェクトルート/.clangd/indexにインデックス情報が作成される。
compile_flags.txt
compile_flags.txtの場合は一行ごとにフラグを指定する。
すべてのファイルで同じフラグを使用するので作成は楽。
ただしcompile_commands.jsonと違ってファイルごとのフラグを指定できない。
この方法ではインデックス情報は作成されない。
clangdをインストールしたら
設定からC/C++拡張(Microsoftが提供してるやつ)の項目を開きインテリセンスをオフにします。
C_Cpp: Intelli Sense EngineをDisable
C_Cpp: FormattingをDisable(clangdからclang-formatを呼び出せる)
おまけ
compile_flags.txtからcompile_commands.jsonを生成するPythonスクリプトを作ってみた。
flags_to_db.py
clang-tidyに必要なファイル
.clang-tidy
YAML形式で記述する。
これらのファイルはプロジェクトのルートディレクトリに置く。
.clang-tidyの要素
Checks: "-*,\
readability-*,\
-readability-convert-member-functions-to-static,\
-readability-uppercase-literal-suffix,\
-readability-static-accessed-through-instance,\
"
WarningsAsErrors: ''
HeaderFilterRegex: 'source.*\.(hpp|h)'
AnalyzeTemporaryDtors: false
FormatStyle: file
CheckOptions:
- key: readability-identifier-naming.ClassCase
value: CamelCase
- key: readability-identifier-naming.StructCase
value: CamelCase
Checks
有効化するチェックと無効化するチェックを記述する。
*アスタリスクはすべてのチェック項目を表す。
-ハイフンは続くチェック項目を無効化する。
基本的にはチェックグループを記述して、不要なチェック項目を除外する。
[チェックグループ] (https://clang.llvm.org/extra/clang-tidy/index.html#id2)
上記の場合、最初にすべてを無効化 ⇒ readability-から始まるチェックを有効化 ⇒ readabilityから一部のチェックを無効化、という流れとなっている。
WarningsAsErrors
警告をエラーとするか否か。
HeaderFilterRegex
このフィルターに一致するヘッダーから警告を出力する。
AnalyzeTemporaryDtors
デストラクタに関するものらしい
FormatStyle
fileを指定しても、いまいち効果が分からない。(要検証)
CheckOptions
チェック項目のオプションを設定する
key チェック項目名
value 設定値
例えばreadability-identifier-namingは命名規則を検証する。
readability-identifier-naming.ClassCaseでは以下の文字列を設定できる。
- lower_case
- UPPER_CASE
- camelBack
- CamelCase
- camel_Snake_Back
- Camel_Snake_Case
- aNy_CasE
効果は名前通り。
clang-tidyの局所的無効化
ここまでclang-tidyを使う方法を書いてきたが、時として使いたくないケースに出てくるだろう。
例えば
template <class BASIC_JSON_TYPE>
void to_json(BASIC_JSON_TYPE& j, const FOO& foo){
j["bar"] = foo.bar;
}
このテンプレート関数はnlohmann/jsonというjsonライブラリにおいて、自作クラスをjsonオブジェクトに代入できるようにする関数なのだが、関数名をlower_caseにしなくてはならない。
readability-identifier-naming.FunctionCaseをlower_case以外にするとclang-tidyはto_jsonという名前をfixするよう提案してくるだろう。
かといって命名規則を変更すると全ての関数名に影響が及ぶ。
そこで使うのが// NOLINT // NOLINTNEXTLINEコメントだ。
template <class BASIC_JSON_TYPE>
void to_json(BASIC_JSON_TYPE& j, const FOO& foo){ //NOLINT
j["bar"] = foo.bar;
}
template <class BASIC_JSON_TYPE>
// NOLINTNEXTLINE
void from_json(const BASIC_JSON_TYPE& j, FOO& foo){
foo.bar = j.at("bar").get<int>();
}
NOLINTは当該行
NOLINTNEXTLINEは次の行でclang-tidyのチェックを無効化する。
使ってみて
ファイル内全ての問題をFixするには、ターミナルからclang-tidyを呼ぶしかないのだろうか