go testが実行するデフォルトのgo vetチェック対象にstdversionが加わり、go.modのgoディレクティブより新しい標準ライブラリAPIの使用をgo test実行時に自動検出するようになった。
go test
概要
go testはビルドの一部として、対象パッケージとそのテストソースに対してgo vetの高信頼サブセットを実行する。このサブセットにstdversionチェックが追加された。stdversionは、参照元ファイルで有効なGoバージョン(go.modのgoディレクティブおよびファイル先頭の//go:build go1.Xビルドタグから決定される)に対して新しすぎる標準ライブラリのシンボル参照を報告するチェックである。
これにより、テスト対象のパッケージやテストファイルが、go.modのgoディレクティブが宣言するGoバージョンよりも後から標準ライブラリに追加されたAPIを使用している場合、go testはテストバイナリを実行せずにvetエラーとして報告するようになる。
go testがデフォルトで実行するvetチェックの対象はatomic, bools, buildtag, directive, errorsas, ifaceassert, nilfunc, printf, slog, stdversion, stringintconv, testsであり、個々のチェックの詳細はgo doc cmd/vetで確認できる。この挙動が不要な場合は-vet=offで無効化、逆に全チェックを有効にしたい場合は-vet=allを指定する。
移行時の注意
- 既存のテスト対象パッケージが、
go.modのgoディレクティブより新しいバージョンで追加された標準ライブラリAPIを使っている場合、これまで通っていたgo testが新たに失敗するようになることがある。- 実際に必要とするGoバージョンに合わせて
go.modのgoディレクティブを引き上げる。 - 特定のファイルだけが新しいAPIを使う場合は、そのファイルに
//go:build go1.Xビルドタグを付ける。 - 一時的にこの挙動を無効にしたい場合は
go test -vet=offを使う。
- 実際に必要とするGoバージョンに合わせて
stdversion自体はgolang.org/x/tools/go/analysis/passes/stdversionとしてすでにgo vetの標準スイートに含まれており、今回の変更はgo testが実行する縮小サブセットにこれを追加するものである。
実装解説
go testが実行するvetチェックの縮小サブセットはcmd/go/internal/testパッケージのdefaultVetFlags(test.go)に列挙されており、ここに"-stdversion"が加えられた。
実際の診断ロジックはベンダリングされたstdversionアナライザ(stdversion.go)が担う。このアナライザは、ツールチェインがgo1.22未満のReleaseTagsしか持たない場合や、パッケージのgoバージョンがgo1.21未満の場合は診断をスキップする(実装当時、goディレクティブがツールチェイン要件として明確に規定されていなかったため)。それ以外の場合、go/typesのUses情報からASTを走査し、参照している識別子の由来パッケージについて「そのファイルで有効なGoバージョンでは未導入のシンボルか」をtypesinternal.TooNewStdSymbolsで判定し、該当すればpkg.Symbol requires goX.Y or laterという診断を出す。