SODA Engineering Blog
🏂

Go静的解析のSuggestedFixを完全に理解して静的解析ツールを書きたくなる

2023/12/24に公開

スニダンを開発しているSODA inc.の Advent Calendar 24日目の記事です!!!/

昨日は imajo さんによる「開発途中の機能を公開してしまって落ち込んだ話」でした!

今日はGoの静的解析について書きます!

https://qiita.com/advent-calendar/2023/soda-inc

ゴール:静的解析ツールを書きたくなる

「Goの静的解析なんか難しそう」がこの記事を読んだあとに「思ったより簡単だな。なんか書いてみよう」に変わると嬉しいです。

Goは標準パッケージで静的解析が出来て便利

Goでは、 go/astgo/types をはじめとして、標準パッケージで静的解析まわりのエコシステムが提供されています。

サードパーティなライブラリから静的解析まわりのエコシステムが提供される言語も多いですが、Goのように標準でサポートされていると色々と良いことがあります。
例えば、言語仕様に新しい機能が追加されたときに同時に対応されて嬉しかったり、静的解析の容易性も考慮された上で言語が実装されて安心だったり。

https://pkg.go.dev/go/ast

https://pkg.go.dev/go/types

Goの静的解析はこれを見れば完全に理解できる

tenntennさん が公開されている資料を見ると、静的解析をコード生成も含めて完全に理解できます。ありがたや。
このブログでは静的解析の詳しい解説は避け、 analysis.SuggestedFix まわりのみを中心に紹介します。

https://tenn.in/analysis

analysis.Diagnosticanalysis.(*Pass).Reportf で検出していく

Goの静的解析では、 analysis.Diagnostic を作り、 analysis.Pass.Report に渡すことで改善点などを検出することができます。
analysis.(*Pass).Reportf はそれを簡易的に実現できる関数で、次の例のようにお手軽に検出することができます。

https://github.com/rinchsan/groupvar/blob/517ca698de1f59d43119276e5b2e4da77e009030/groupvar.go#L38

analysis.SuggestedFix-fix オプションで修正提案していく

analysis.DiagnosticSuggestedFixes フィールドに analysis.SuggestedFix のスライスを入れて作って Report に渡すことで、検出したコードに対して修正提案を作ることができます。

次の例のように、修正を入れる位置を Pos で指定しつつ、修正内容を []byte で指定していく形で実装します。
この例のように文字列を直接指定するのも良いですが、 format.Node を使って go/ast で作ったASTを文字列に変換したものを使うのもオススメです。

https://github.com/rinchsan/ppprof/blob/620c5b034fbb98ba12b157207ec45659c2a109bc/ppprof.go#L46-L68

ちなみに、 unitchecker ではなく singlecheckermultichecker で作ることで単一のCLIツールとして実行できるようになりますが、そのときに -fix オプションを渡すと analysis.Diagnostic.SuggestedFixes の通りにソースコードを修正してくれる機構も標準で提供されています。

https://github.com/rinchsan/ppprof/blob/620c5b034fbb98ba12b157207ec45659c2a109bc/cmd/ppprof/main.go

analysistest.Runanalysistest.RunWithSuggestedFixes でテストも書ける

次の例のようにGoのファイルを作り、コメントで // want "検出されるときのメッセージ" のように書いておき、そのファイルを対象に analysistest.Run でテストする機構が標準で提供されています。
analysis.Diagnostic が正しい Message で正しい PosReport されているかテストできます。

https://github.com/rinchsan/ppprof/blob/620c5b034fbb98ba12b157207ec45659c2a109bc/testdata/src/a/a.go

また、次のように元ファイルと一緒にGoldenファイルを作っておき analysistest.Run の代わりに analysistest.RunWithSuggestedFixes を使うことで analysis.Diagnostic.SuggestedFixes の内容をテストする機構も提供されています。

https://github.com/rinchsan/ppprof/blob/620c5b034fbb98ba12b157207ec45659c2a109bc/testdata/src/a/a.go.golden

べんり!

Goは標準で静的解析が色々とサポートされてて便利!

GitHubで編集を提案
SODA Engineering Blog
SODA Engineering Blog

Discussion