LoginSignup
14
12

More than 3 years have passed since last update.

VSCodeでclangのclangdでclang-tidy

Last updated at Posted at 2019-11-19

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: Pathclangd.exeを入れる。
{03924299-31F1-4BE0-85C2-F918EDAF032B}.png

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 EngineDisable
C_Cpp: FormattingDisable(clangdからclang-formatを呼び出せる)

おまけ

compile_flags.txtからcompile_commands.jsonを生成するPythonスクリプトを作ってみた。
flags_to_db.py

clang-tidyに必要なファイル

.clang-tidy
YAML形式で記述する。

これらのファイルはプロジェクトのルートディレクトリに置く。

.clang-tidyの要素

.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

有効化するチェックと無効化するチェックを記述する。
*アスタリスクはすべてのチェック項目を表す。
-ハイフンは続くチェック項目を無効化する。
基本的にはチェックグループを記述して、不要なチェック項目を除外する。
チェックグループ

上記の場合、最初にすべてを無効化 ⇒ 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.FunctionCaselower_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を呼ぶしかないのだろうか

14
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
12