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を呼ぶしかないのだろうか