[インデックス 13479] ファイルの概要
このコミットは、Go言語の静的解析ツールである cmd/vet
(通称 go tool vet
) に、実行する検査を制御するための新しいフラグを追加するものです。これにより、ユーザーはデフォルトですべての検査を実行する代わりに、特定の検査のみを選択して実行できるようになります。
コミット
commit f49b7b0acfad77e051df0e91a6784a3c0808d118
Author: Rob Pike <r@golang.org>
Date: Mon Jul 16 14:03:11 2012 -0700
cmd/vet: provide flags to control which tests to run
By default, all are still run, but a particular test can be
selected with the new flags.
R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/6395053
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/f49b7b0acfad77e051df0e91a6784a3c0808d118
元コミット内容
cmd/vet
: 実行するテストを制御するためのフラグを提供する。
デフォルトでは引き続きすべてのテストが実行されるが、新しいフラグを使用することで特定のテストを選択できるようになる。
変更の背景
go tool vet
は、Goプログラムの潜在的なバグや疑わしい構造を検出するための静的解析ツールです。元々、vet
は実行時にすべての利用可能な検査を自動的に実行していました。しかし、開発のワークフローやCI/CDパイプラインにおいて、特定の種類の検査のみを実行したい、あるいは特定の検査を一時的に無効にしたいというニーズが生じることがあります。例えば、特定の検査が誤検知(false positive)を多く出す場合や、開発中のコードベースで特定の警告を一時的に無視したい場合などです。
このコミットは、このような柔軟性を提供するために、各検査に対応するコマンドラインフラグを導入しました。これにより、ユーザーは go tool vet
の実行時に、どの検査を実行するかを明示的に指定できるようになり、より細かく解析プロセスを制御できるようになります。
前提知識の解説
go tool vet
とは
go tool vet
は、Go言語の標準ツールチェーンに含まれる静的解析ツールです。コンパイラでは検出できないが、実行時に問題を引き起こす可能性のあるコードの慣用句や構造上の問題を特定することを目的としています。例えば、Printf
フォーマット文字列と引数の不一致、構造体タグの誤り、メソッドシグネチャの非標準的な定義などを検出します。
vet
はヒューリスティックに基づいており、すべての報告が必ずしも実際のバグであるとは限りませんが、コンパイラでは捕捉できないエラーを見つけるのに非常に役立ちます。
go tool vet
が行う主な検査の種類
このコミットで言及されている、または影響を受ける主な検査は以下の通りです。
-
Printf family (Printf系関数):
fmt.Printf
やその関連関数(Sprintf
,Fprintf
など)の呼び出しにおいて、フォーマット文字列と引数の型や数が一致しない場合に警告します。- 例:
fmt.Printf("%d", "hello")
のようなコード。 - 関連フラグ:
-printf
-
Methods (メソッド):
Format
,GobEncode
,GobDecode
,MarshalJSON
,MarshalXML
,UnmarshalJSON
,UnreadByte
,UnreadRune
,WriteByte
,WriteTo
など、Goの標準ライブラリで慣用的に使われるメソッド名に対して、そのシグネチャ(引数と戻り値の型)が標準的なものと異なる場合に警告します。これは、インターフェースの実装ミスや意図しない動作を防ぐためです。- 例:
ReadByte() byte
の代わりにReadByte() (byte, error)
が期待される場合など。 - 関連フラグ:
-methods
-
Struct tags (構造体タグ):
reflect.StructTag.Get
で解釈されるべき構造体フィールドタグが、正しいフォーマットに従っていない場合に警告します。構造体タグは、JSONエンコーディングやデータベースマッピングなどでメタデータを提供するために使用されます。- 例:
json:"name,omitempty"
のようなタグの書式が誤っている場合。 - 関連フラグ:
-structtags
-
Untagged composite literals (タグなし複合リテラル):
- 構造体の複合リテラル(
struct{}
で初期化されるもの)において、フィールド名を明示的に指定せずに値のみで初期化されている場合に警告します。これは、構造体のフィールド順序が変更された際に、意図しないフィールドに値が割り当てられるリスクを減らすための慣用的なスタイルチェックです。 - 例:
MyStruct{1, "hello"}
の代わりにMyStruct{Field1: 1, Field2: "hello"}
が推奨される。 - 関連フラグ:
-composites
- 構造体の複合リテラル(
Go言語の flag
パッケージ
Go言語の標準ライブラリには、コマンドライン引数を解析するための flag
パッケージが提供されています。このパッケージを使用すると、--name value
や -name value
の形式でコマンドライン引数を定義し、プログラム内でその値を取得できます。このコミットでは、この flag
パッケージを使用して新しい検査制御フラグを実装しています。
技術的詳細
このコミットの主要な技術的変更点は、go tool vet
の各検査に専用のコマンドラインフラグを導入し、それらのフラグの状態に基づいて検査の実行を条件分岐させることです。
-
フラグの定義:
src/cmd/vet/main.go
に、各検査に対応するブーリアン型のフラグが定義されました。vetMethods
(-methods
)vetPrintf
(-printf
)vetStructTags
(-structtags
)vetUntaggedLiteral
(-composites
)
- また、
vetAll
(-all
) というフラグも導入され、これはデフォルトでtrue
に設定されています。これは、明示的な検査フラグが指定されていない場合に、すべての検査を実行するという従来の動作を維持するためのものです。
-
フラグの相互作用ロジック:
main.go
のmain
関数内で、コマンドライン引数の解析後、新しいロジックが追加されました。- もし
vetMethods
,vetPrintf
,vetStructTags
,vetUntaggedLiteral
のいずれかのフラグがtrue
(つまり、ユーザーが特定の検査を明示的に要求した)であれば、vetAll
フラグはfalse
に設定されます。これにより、「特定の検査が指定された場合は、すべてを実行するデフォルトの動作を無効にする」という挙動が実現されます。
-
検査の条件付き実行:
- 各検査ロジックが実装されているファイル(
method.go
,print.go
,structtag.go
,taglit.go
)に、検査を実行する前にフラグの状態を確認する条件分岐が追加されました。 - 例えば、
method.go
のcheckCanonicalMethod
関数では、if !*vetMethods && !*vetAll { return }
というチェックが追加されています。これは、「-methods
フラグが指定されていない、かつ、すべての検査を実行するモードでもない場合は、このメソッド検査をスキップする」という意味になります。 - このパターンは、他のすべての検査関数にも適用されています。
- 各検査ロジックが実装されているファイル(
-
ドキュメントの更新:
src/cmd/vet/doc.go
が更新され、新しいフラグとその機能が説明されています。これにより、ユーザーはgo tool vet -help
を実行した際に、これらの新しいオプションについて知ることができます。
この変更により、go tool vet
はより柔軟なツールとなり、開発者は自身のニーズに合わせて静的解析の範囲を調整できるようになりました。
コアとなるコードの変更箇所
このコミットでは、以下のファイルが変更されています。
src/cmd/vet/doc.go
:vet
ツールのドキュメントが更新され、新しいフラグとその機能が追加されました。src/cmd/vet/main.go
: コマンドラインフラグの定義と、フラグの相互作用ロジック(特定の検査フラグが指定された場合にvetAll
を無効にする)が追加されました。src/cmd/vet/method.go
: メソッド検査のロジックに、-methods
または-all
フラグが有効な場合にのみ実行される条件分岐が追加されました。src/cmd/vet/print.go
: Printf系関数検査のロジックに、-printf
または-all
フラグが有効な場合にのみ実行される条件分岐が追加されました。また、テスト用の不要なコードが削除されています。src/cmd/vet/structtag.go
: 構造体タグ検査のロジックに、-structtags
または-all
フラグが有効な場合にのみ実行される条件分岐が追加されました。src/cmd/vet/taglit.go
: タグなし複合リテラル検査のロジックに、-composites
または-all
フラグが有効な場合にのみ実行される条件分岐が追加されました。
コアとなるコードの解説
src/cmd/vet/main.go
var (
vetAll = flag.Bool("all", true, "check everything; disabled if any explicit check is requested")
vetMethods = flag.Bool("methods", false, "check that canonically named methods are canonically defined")
vetPrintf = flag.Bool("printf", false, "check printf-like invocations")
vetStructTags = flag.Bool("structtags", false, "check that struct field tags have canonical format")
vetUntaggedLiteral = flag.Bool("composites", false, "check that composite literals used type-tagged elements")
)
// ...
func main() {
// ...
flag.Parse()
// If a check is named explicitly, turn off the 'all' flag.
if *vetMethods || *vetPrintf || *vetStructTags || *vetUntaggedLiteral {
*vetAll = false
}
// ...
}
この部分では、flag.Bool
を使用して新しいコマンドラインフラグを定義しています。各フラグは、対応する検査を有効にするかどうかを制御します。vetAll
はデフォルトで true
であり、すべての検査を実行する従来の動作を維持します。
main
関数内では、flag.Parse()
の後に、ユーザーが特定の検査フラグ(-methods
, -printf
など)を一つでも指定した場合に、vetAll
フラグを false
に設定するロジックが追加されています。これにより、特定の検査が要求された場合は、デフォルトの「すべて実行」モードが無効になります。
src/cmd/vet/method.go
(および print.go
, structtag.go
, taglit.go
も同様)
func (f *File) checkCanonicalMethod(id *ast.Ident, t *ast.FuncType) {
if !*vetMethods && !*vetAll {
return
}
// ... 既存のメソッド検査ロジック ...
}
各検査関数(例: checkCanonicalMethod
)の冒頭に、上記の条件分岐が追加されました。
!*vetMethods
:-methods
フラグが指定されていない場合。!*vetAll
:-all
フラグがfalse
の場合(つまり、特定の検査が指定されたか、または-all=false
が明示的に指定された場合)。
この条件は、「-methods
フラグが true
でない、かつ、vetAll
フラグも true
でない」場合に return
することで、その検査をスキップします。これにより、vetMethods
が true
の場合、または vetAll
が true
の場合にのみ、検査ロジックが実行されるようになります。他の検査ファイル(print.go
, structtag.go
, taglit.go
)でも同様のパターンが適用されています。
src/cmd/vet/doc.go
--- a/src/cmd/vet/doc.go
+++ b/src/cmd/vet/doc.go
@@ -9,9 +9,12 @@ calls whose arguments do not align with the format string. Vet uses heuristics
that do not guarantee all reports are genuine problems, but it can find errors
not caught by the compilers.
+By default all checks are performed, but if explicit flags are provided, only
+those identified by the flags are performed.
+
Available checks:
-1. Printf family
+1. Printf family, flag -printf
Suspicious calls to functions in the Printf family, including any functions
with these names:
@@ -28,7 +31,7 @@ complains about arguments that look like format descriptor strings.
It also checks for errors such as using a Writer as the first argument of
Printf.
-2. Methods
+2. Methods, flag -methods
Non-standard signatures for methods with familiar names, including:
Format GobEncode GobDecode MarshalJSON MarshalXML
@@ -36,16 +39,21 @@ Non-standard signatures for methods with familiar names, including:
UnmarshalJSON UnreadByte UnreadRune WriteByte
WriteTo
-3. Struct tags
+3. Struct tags, flag -structtags
Struct tags that do not follow the format understood by reflect.StructTag.Get.
+4. Untagged composite literals, flag -composites
+\
+
Usage:
go tool vet [flag] [file.go ...]
go tool vet [flag] [directory ...] # Scan all .go files under directory, recursively
-The flags are:\
+The other flags are:\
-v
Verbose mode
-printfuncs
この差分は、go tool vet
のドキュメントが更新され、新しいフラグ(-printf
, -methods
, -structtags
, -composites
)が各検査の説明とともに追記されたことを示しています。これにより、ユーザーは go tool vet
のヘルプメッセージを通じて、これらの新しいオプションを認識できるようになります。
関連リンク
- Go言語の公式ドキュメント: https://go.dev/
go tool vet
のドキュメント (Go言語のバージョンによって内容が異なる場合があります): https://pkg.go.dev/cmd/vet- Go言語の
flag
パッケージ: https://pkg.go.dev/flag
参考にした情報源リンク
- GitHub: https://github.com/golang/go/commit/f49b7b0acfad77e051df0e91a6784a3c0808d118
- Go Code Review Comments: https://go.dev/doc/effective_go#vet
- Go言語の
go tool vet
に関する一般的な情報 (Web検索結果に基づく)