フューチャー技術ブログ

Go 1.20 vetのアップデート

はじめに

TIG/DXユニット所属の今泉です。 Go 1.20連載の6本目です。

そもそもvetとは

Goの標準ライブラリに組み込まれている、コンパイラによってキャッチされないエラーや懸念を検出し報告してくれるコードの静的解析ツールです。
機能の詳細は本記事では割愛しますが、以下コマンドで利用可能なチェックの一覧を確認できます。

go tool vet help

公式のドキュメントはこちらです。

類似のツールとしては以下のようなものがあります。
私のいるチームではstaticcheckを利用しています。

ループ変数が関数内に多重にネストされていた場合の検知

次のようなコードはよくあるケースでバグを含んでいます。

func TestParallel(t *testing.T) {
tests := []struct{ name string }{{name: "とまと"}, {name: "にんじん"}, {name: "じゃがいも"}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
fmt.Println(tt.name)
})
}
}

このコードをテストすると、とまとやにんじんが出力してほしい箇所もじゃがいもになってしまいます。
これはループ内に渡している変数ttがループごとに作成される変数ではなくループ全体で利用されるものであることに起因します。

>go test -race -v
=== RUN TestParallel
=== RUN TestParallel/とまと
=== PAUSE TestParallel/とまと
=== RUN TestParallel/にんじん
=== PAUSE TestParallel/にんじん
=== RUN TestParallel/じゃがいも
=== PAUSE TestParallel/じゃがいも
=== CONT TestParallel/とまと
じゃがいも
=== CONT TestParallel/じゃがいも
じゃがいも
=== CONT TestParallel/にんじん
じゃがいも
--- PASS: TestParallel (0.00s)
--- PASS: TestParallel/とまと (0.00s)
--- PASS: TestParallel/じゃがいも (0.00s)
--- PASS: TestParallel/にんじん (0.00s)
PASS
ok /src 1.253s

go1.20ではこのような問題を検知してくれるようになります。

>go1.20rc3 vet
# /src
.\main_test.go:60:16: loop variable tt captured by func literal

不正な時刻形式の検知

time layoutが2006-01-02(yyyy-mm-dd) ではなく、2006-02-01(yyyy-dd-mm) となっていた場合に検知してくれるようになりました。
わたしにとってはいまいちピンときませんが、アメリカ式時刻が馴染み深い方は間違えてしまったりするのでしょうか…?
proposalを確認すると予想以上にこの間違いは発生しており、vetへの追加が決まったようです。

There is a lots of projects on Github with this issue:
多くのGithub上のプロジェクトでこの問題があるようだ
https://github.com/search?l=GO&q=%222006-02-01%22+language%3AGo&type=Code
Even bigger projects have or had bad code:
巨大なプロジェクトですら同様の問題を抱えていたりする
https://github.com/couchbase/go-couchbase/blob/118e3f09dbf08c7310d6bc1a5cfe5e6f8a0e3c32/populate/populate.go#L18
https://github.com/gobuffalo/buffalo/blob/20f545e952c31f65eadf7a4833388ed2eaa37589/binding/decoders/time_test.go#L55-L56
juju/juju@f992f35

That’s pretty surprising but it does seem to meet the vet bars:
Correctness - a real or potential bug for sure
Frequency - seems to happen more than we expected!
Precision - can’t imagine why anyone would use YYYY-DD-MM date format
驚いたことに、vetの対象とすべき基準をみたしているようです。
・正確さ - 確かに実際または潜在的なバグであること
・頻度 - 予想以上に発生しているようだ!
・精度 - YYYY-DD-MM 日付を使用するケースはありえないと思う

※日本語は意訳です

ただ、 Go 1.20連載の4本目で宮永さんに紹介いただいている通りlayoutにDateTime,DateOnly,TimeOnlyが追加されました。
新しいlayoutを使用することでこのミスは防ぐことができると思慮します。

おわりに

今回はgo vetのアップデートについて紹介させていただきました。

些細なアップデートですが、静的解析も少しずつ改良されていく様子が伺えて面白かったです。

次は連載の最終回で藤井さんのgo build に追加される cover オプション(利用例付き)です。