落胆がらくた街

多分三日坊主で終わると思うんですけど

Vscode+PlatformIOでIntelliSenseが変なもん参照する時の覚書

前置き

f:id:suzumodoki:20171125212155j:plain
画像はVS codeにPlatform IOという拡張をぶち込んで
Mbed lpc1114fn28向けのプロジェクトを立ち上げた時の一コマ。
一見1114向けのヘッダが見事に読み込めているように見えるし、ビルドもちゃんと通るのでとっても快適。

f:id:suzumodoki:20171125221448j:plain
ところが、実はこんな明らかにヘッダファイルを読めているにも関わらず、IntelliSenseが1114のピンネームマクロ「dp14」を候補に出してくれない。
コンパイル・ビルドが通る以上ビルドツール向けのパスの設定はちゃんと出来ているので、問題はプロジェクトフォルダのc_cpp_properties.jsonという事になる*1
で、c_cpp_properties.jsonがどうなってるかというと…

イヤーッ!
f:id:suzumodoki:20171125212815j:plain
グワーッ!

これは「configurations」属性の直下の「includepath」属性なので、コンパイラに渡すインクルードパスと同じだ。
ここの設定は正しいのだが、何故かIntelliSenseはこのインクルードパスを参照してくれず、果には「mbed.hなんて無いよ」とか言い出す。
で、下の方を見てくと、「browse」というタグがあり、やはりその下にはpath属性があって似たような記述がずらっと並ぶ。
browse属性は何をしているかというと「fazzyモード(厳格ではない、多少のエラーは気にせずコード解析するモード)」で候補を出すときのインクルードパスだ。
最初にVs codeでプロジェクトを起こした時、インクルードパスを何も設定してないせいで#includeプリプロセッサに緑の線が引かれるが、あれは「参照が解決できないのでファジーモードで候補出すよ」という記号だ。だから緑の線が無くなるまできっちりインクルードパスを書いてやったのだが何故か逆に何も読んでくれなくなった(原因不明。誰か教えてください)。

コンパイラに渡すインクルードパスと違い、「browseのpath属性」にIntelliSenseが検索をかける時はサブフォルダまで舐め回すように探すので、
このずらーっと並んだ書き方は恐らく無駄でしか無い。
例えば1114が参照するのは「targets/TARGET_NXP/TARGET_LPC11XX_11CXX」以下なんかにあるファイルだが、
ドタマに「C:/Users/admin/.platformio/packages/framework-mbed/.」が書かれている以上、その下にある全く関係無い他のデバイス用の同名のヘッダも全部読む。
そして名前の衝突が起こった場合、本来ならばIntelliSenseは複数の候補があると言ってくるのだが、「複数の候補が存在するa.hからやはり複数の候補が存在するb.hをインクルード」というシチュエーションの時、どうやらb.hで名前がぶつかっている候補をIntelliSenseは見つけてくれない。

f:id:suzumodoki:20171125214129j:plain
PlatformIOはMbedプラットフォームを選択した時点で対応しているライブラリを全てダウンロードして手元に置く。
その為、たとえ存在を知らないような、BEETLEとかいうわけのわからんボードのAPIも手元にある。これは2017/11/25時点でMbedプロジェクトフォルダのアタマに置かれている(framework-mbed\targets\TARGET_ARM_SSG以下。)
で、ビルドツールは設定されたマクロに従い、図の右下の1114用ライブラリをきっちり読み込んでくれるのだが、ファジーモードのIntelliSenseはそんなマクロ知ったこっちゃないので、まずDevice.hで競合する(図中とりあえず①)。この時はまだ「競合してるよ」的なウィンドウを出してくれるのだが、ここから更に読み込んでいるヘッダに関しては「競合が解決されない以上は仮に一番上のヘッダを読んでおく」事になっているらしい。つまり、「TARGET_ARM_SSG\TARGET_BEETLE\PinName.h」をPinName.hの代表として読むわけだ(図中とりあえず②。図ではobjects.hが一例)。
かくして1114の為のPinName.hは読み飛ばされ、候補にdp14というマクロは出なくなる。纏めると、
「厳密な解析モードだと何故か何も表示してくれない。ファジーモードだと何もかも読み込み衝突を起こす」。


解決策

ようはbrowseタグのpath属性でサブフォルダを読まないようにすればいい。
vscode-cpptools/c_cpp_properties.json.md at master · Microsoft/vscode-cpptools · GitHub
リファレンス曰く、「パスの末尾が/*か\*ならそれ以降読まない」との事。なので、このずらっと並んだ部分を選択して、置換コマンドで
「",」を「/*",」に置換してやる。これだけ長ったらしく前置きをした挙句やることがこれだけって…。
f:id:suzumodoki:20171125223000j:plain

なお、今回はMbedの話だが、多分どのプラットフォームを選んでも似たり寄ったりじゃないかと思うので、状況は違えど現象が同じなら同じやり方でなんとかなると思います。
いやわかんないけど。めっちゃ対症療法だし。

*1:インクルードパスなどを設定する、プロジェクトフォルダ毎の設定ファイル