VSCode で clangd を使って、賢いC++インテリセンス環境を整える



VSCode の標準のC++インテリセンスでは、簡単なコード補完などや、構文が間違ってるなどのエラー表示はリアルタイムに出来ますが、警告などはリアルタイム表示出来なかったり、その他コーディング時に行ってほしい賢い機能が不足しがちです。

例えば以下のコードは、セミコロン忘れなどのエラーは表示してくれますが、未初期化変数の `f` などはコンパイル時に警告がちょろっと出るだけで、見落としてしまいます。


```cpp
#include <iostream>
using namespace std;

int main(){
    int f;
    cout << f << endl;

    cout << "semicolon" << endl
    return 0
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188347/6b45bf0b-d3e1-8d65-7b6f-d1c348e869f9.png)

MS 標準の　C++ インテリセンスはそこまで賢くないからというのが理由なのですが、ここで変わりに `clangd` を使うことで、賢いリアルタイムインテリセンスを使えるようにします！

しかも、拡張を入れて、各プロジェクトで使い回せる設定ファイルを置くだけのシンプル環境構築法です。

また、CLion や Rust などでもおなじみの、コード内に追加情報をインラインで表示する inlay hints も使えるようになります。

自分の環境では以下のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188347/426b8f1b-1c86-8445-c9fa-0247bc657a9d.png)

未初期化の `answer` に警告が表示されている他、関数呼び出しの引数にパラメーター名が表示されています。関数を呼ぶときに引数をどの順番で書くのか分かりやすくなります（オプションで消すことも出来ます）。

:::note info
`clangd` という名前ですが、clang コンパイラの他に gcc なども使用可能です！
:::


## clangd 拡張のインストール

拡張機能タブから「clangd」を検索してインストールします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188347/2a0b9f32-0a80-d533-556b-728a91703be5.png)

インストールが完了すると、標準のインテリセンスと競合が発生するので標準インテリセンスを無効にするように指示されます。無効にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188347/99e3b4a0-b0a3-7688-d9ab-607d20cd49e7.png)

パスに clangd が見つからなかったり古いと、VSCodeの内部ディレクトリにインストールするダイアログが出ます。このダイアログでインストールしてもシステムの方の clangd は干渉しないのでインストールしましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188347/3e66eb9b-9f39-7116-673c-ea7ffc81e2a5.png)
インストールしたら、VSCodeを再起動します。


VSCode でプログラムを書くフォルダを開いたら、`compile_flags.txt` を作成します。ここには指定するコンパイルオプションを1行ずつ書きます。VSCode の Settings などで設定した include パスなどは clangd は読まないので、ここに全て書きます。

例えば以下のような感じです。
```:compile_flags.txt
-Wall
-Wextra
-Wno-unknown-pragmas
-Wno-unused
-Wno-unused-parameter
-Wno-sign-compare
-std=gnu++17
-I
atcoder-library/
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188347/3b52e461-f978-39ee-c5b9-54ad15c69126.png)


`compile_flags.txt` を変更してもリアルタイムには反映されないので、設定を変えたら VSCode を再起動します。

すると、以下のようにオプションに合わせて警告を表示してくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188347/aa9b25d4-6974-3004-9354-a5a1af33ddef.png)

以下のような、if の中で `==` を間違えて `=` と打ってしまっても、ちゃんとリアルタイムに波線を引いてくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188347/d14e8131-bb74-7e56-7bc5-c02487fc0bb5.png)
(余談ですが、本当に if 文の中で代入を行いたいときは、`if ((a = 0))` と、`()` で式全体をくくると警告が出なくなります。)


## Inlay Hints

他にも clangd は、コード内に追加情報をインラインで表示する機能があります。例えば以下のように動作します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188347/6f838c53-2e44-6b59-7fe7-9c3ef83bf4a1.png)

関数のパラメーター名を呼び出し側で表示してくれたり、`auto` と書いた型を教えてくれたりします。パラメーターヒントの方は、変数名とパラメーター名が一緒のときは省略してくれます。

また、配列の初期化のときに、各要素の配列インデックスを教えてくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188347/f1ff90f2-d9b9-393c-f1a1-a88b02302c53.png)

これらが不要なときは、`compile_flags.txt` と同様に `.clangd` ファイルを作って、そこで以下のように設定します。
```:.clangd
InlayHints:
  Enabled: Yes
  ParameterNames: Yes
  DeducedTypes: No
  Designators: No
```
- ParameterNames: 関数呼び出しのパラメーター名の表示
- DeducedTypes: auto の型の表示
- Designators: 配列インデックスの表示
になります。

また、VSCodeの設定を追加することで、主張の強すぎる InlayHint を弱めることが出来ます。
自分は、`settings.json` (ユーザー設定(JSON)) に以下の設定を追加して、Inlay Hintの表示を半透明にしています。
```json:settings.json
    "workbench.colorCustomizations": {
        "editorInlayHint.background": "#11111111",
        "editorInlayHint.foreground": "#eeeeee19",
    }
```

そうすると、このくらいの主張度になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/188347/e2c878dd-5ffa-81d5-6cb7-bff361cf7233.png)
このくらいの薄さであれば普段は気にならず、引数について気になるときにはヒントに注目すれば情報を得られて、良いと思っています。

余談ですが、`workbench.colorCustomizations` は他にも様々な場所のスタイルを変更でき、 `editorWhitespace.foreground` で空白文字の表示方法、`editorStickyScroll.background` で　StickyScroll　の背景の色を変更できます。詳しくは[こちら](https://code.visualstudio.com/api/references/theme-color)。

## FAQ
### ・`compile_flags.txt` を毎プロジェクト用意するのだるい。どこかにまとめたり、`settings.json` に書けないの？
自分もやり方わかりません。多分無い気がします。
`compile_flags.txt` の他に、各ソースコード用にオプションを書く方式の `compile_commands.json` は `settings.json` でパスを指定できますが、これは各ファイル名に一致している必要があり、ワイルドカードなどが使えないので厳しそうです。

## 最後に
いかがだったでしょうか？
もし良いと思ったら記事の「いいね」と「ストック」お願いします。