[インデックス 15252] ファイルの概要
このコミットは、Go言語のcmd/go
ツールにおけるvet
コマンドのバグ修正に関するものです。具体的には、go vet
が一部のGoファイルを二重に処理してしまう問題と、パッケージディレクトリ外で実行された場合にファイルが見つからない問題を解決しています。
コミット
commit 11884db3d76a7e91521bb63cff3cc701c0c07826
Author: Russ Cox <rsc@golang.org>
Date: Thu Feb 14 15:00:51 2013 -0500
cmd/go: fix vet
The IgnoredGoFiles are already listed in allgofiles,
so they were being run twice. Worse, the ones in
IgnoredGoFiles are not fully qualified paths, so they
weren't being found when executed outside the
package directory.
Fixes #4764.
R=golang-dev, minux.ma, franciscossouza
CC=golang-dev
https://golang.org/cl/7308049
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/11884db3d76a7e91521bb63cff3cc701c0c07826
元コミット内容
cmd/go: fix vet
IgnoredGoFiles
はすでにallgofiles
にリストされているため、二重に実行されていました。さらに悪いことに、IgnoredGoFiles
内のファイルは完全修飾パスではなかったため、パッケージディレクトリ外で実行された場合に見つかりませんでした。
Fixes #4764.
変更の背景
この変更は、Goのvet
コマンドが特定の条件下で正しく動作しないバグ(Issue #4764)を修正するために行われました。Issue #4764は、「cmd/go: vet fails with 'no such file or directory'」というタイトルで報告されており、go vet
コマンドがcrypto/rand
パッケージ内のrand_windows.go
のようなファイルを検出できず、「no such file or directory」というエラーで終了するという問題が指摘されていました。
この問題の根本原因は、go vet
が処理するファイルリストの構築方法にありました。具体的には、pkg.allgofiles
とpkg.IgnoredGoFiles
という2つのリストが関係していました。pkg.allgofiles
はパッケージ内のすべてのGoファイルのリストを含んでいましたが、pkg.IgnoredGoFiles
もまた、ビルド時に無視されるべきファイル(例えば、特定のOSやアーキテクチャに特化したファイルで、現在のビルド環境では使用されないもの)を含んでいました。
問題は、IgnoredGoFiles
に含まれるファイルがallgofiles
にも含まれているにもかかわらず、vet
コマンドへの引数として両方が結合されて渡されていた点にありました。これにより、ファイルが二重に処理される可能性がありました。さらに深刻な問題は、IgnoredGoFiles
内のパスが完全修飾パス(絶対パス)ではなく、相対パスであったため、go vet
がパッケージのルートディレクトリ以外から実行された場合に、これらのファイルを正しく見つけられないというものでした。結果として、go vet
は存在しないファイルを処理しようとしてエラーを発生させていました。
このコミットは、これらの問題を解決し、go vet
が常に正しいファイルセットを、正しいパスで処理するようにすることを目的としています。
前提知識の解説
go vet
: Go言語の静的解析ツールの一つで、Goプログラムの潜在的なバグや疑わしい構成を検出します。例えば、フォーマット文字列の誤り、到達不能なコード、ロックの誤用などをチェックします。開発者がコードの品質を向上させ、一般的な間違いを避けるのに役立ちます。pkg.allgofiles
: Goのビルドシステムやツールが内部的に使用する構造体(go/build
パッケージのPackage
型など)の一部で、特定のGoパッケージに属するすべてのGoソースファイルのリスト(ファイル名またはパスの配列)を指します。これには、通常のGoファイル、テストファイル、およびビルドタグによって条件付きで含まれる可能性のあるファイルが含まれます。pkg.IgnoredGoFiles
: 同様に、go/build
パッケージのPackage
型の一部で、現在のビルドコンテキストでは無視されるべきGoソースファイルのリストを指します。これらは通常、ビルドタグ(例:// +build linux
)によって特定のOSやアーキテクチャに限定されるファイルで、現在の環境ではコンパイルされないものです。relPaths
: この関数は、与えられたファイルパスのリストを、現在の作業ディレクトリからの相対パスに変換するユーティリティ関数であると推測されます。go vet
のようなツールは、引数として相対パスを受け取ることが多いため、このような変換が必要になります。
技術的詳細
このコミットが修正している問題は、go vet
コマンドが内部的にGoパッケージのファイルリストを処理する方法に起因していました。
-
二重処理の問題:
src/cmd/go/vet.go
の元のコードでは、runVet
関数内でpkg.allgofiles
とpkg.IgnoredGoFiles
を結合してvet
ツールに渡していました。run(tool("vet"), relPaths(stringList(pkg.allgofiles, pkg.IgnoredGoFiles)))
ここで、
stringList
関数は2つの文字列スライスを結合する役割を果たします。しかし、pkg.IgnoredGoFiles
に含まれるファイルは、すでにpkg.allgofiles
にも含まれている場合があります(例えば、allgofiles
はパッケージディレクトリ内のすべてのGoファイルを列挙し、IgnoredGoFiles
はそのサブセットであるため)。この冗長な結合により、vet
ツールが同じファイルを二度処理しようとする可能性がありました。これは非効率であるだけでなく、場合によっては予期せぬ動作を引き起こす可能性がありました。 -
不完全なパスの問題: さらに深刻なのは、
pkg.IgnoredGoFiles
内のファイルパスが完全修飾パス(絶対パス)ではなかったという点です。go vet
がパッケージのルートディレクトリ以外の場所から実行された場合、相対パスであるIgnoredGoFiles
内のファイルは、現在の作業ディレクトリからの相対パスとして解釈され、結果としてファイルが見つからないというエラーが発生していました。これは、go vet
がgo
コマンドの一部として実行される際に、go
コマンドが内部的にパッケージのコンテキストを正しく設定しない場合に顕在化する問題でした。
このコミットの修正は、これらの問題を直接的に解決します。vet
コマンドに渡すファイルリストからpkg.IgnoredGoFiles
を削除することで、二重処理の問題を解消します。pkg.allgofiles
はすでにパッケージ内のすべての関連するGoファイルを完全なパスで含んでいるため、これだけで十分です。これにより、vet
は常に正しいファイルセットを、正しい(見つけられる)パスで処理するようになります。
コアとなるコードの変更箇所
--- a/src/cmd/go/vet.go
+++ b/src/cmd/go/vet.go
@@ -32,6 +32,6 @@ func runVet(cmd *Command, args []string) {
// Use pkg.gofiles instead of pkg.Dir so that
// the command only applies to this package,
// not to packages in subdirectories.
-\t\trun(tool("vet"), relPaths(stringList(pkg.allgofiles, pkg.IgnoredGoFiles)))
+\t\trun(tool("vet"), relPaths(pkg.allgofiles))
}
}
コアとなるコードの解説
変更はsrc/cmd/go/vet.go
ファイルのrunVet
関数内の一行に集約されています。
元のコード:
run(tool("vet"), relPaths(stringList(pkg.allgofiles, pkg.IgnoredGoFiles)))
修正後のコード:
run(tool("vet"), relPaths(pkg.allgofiles))
この変更の核心は、vet
ツールに渡すファイルリストからpkg.IgnoredGoFiles
を削除したことです。
tool("vet")
:vet
コマンドの実行可能パスを取得します。relPaths(...)
: 取得したファイルパスのリストを、現在の作業ディレクトリからの相対パスに変換します。stringList(pkg.allgofiles, pkg.IgnoredGoFiles)
(変更前):pkg.allgofiles
とpkg.IgnoredGoFiles
の2つの文字列スライスを結合して、単一のリストを作成していました。pkg.allgofiles
(変更後): 修正後は、pkg.allgofiles
のみをrelPaths
関数に渡しています。
この修正により、go vet
はパッケージ内のすべてのGoファイル(pkg.allgofiles
に含まれるもの)のみを処理するようになります。pkg.IgnoredGoFiles
に含まれるファイルは、ビルド時に無視されるべきものであり、vet
による静的解析の対象から外れるべきです。また、pkg.allgofiles
は通常、完全修飾パスまたはgo
コマンドが正しく解決できるパスでファイルを提供するため、パスの問題も同時に解決されます。
結果として、go vet
はより正確なファイルセットに対して実行され、二重処理や「ファイルが見つからない」といったエラーが解消されます。
関連リンク
- Go Issue #4764: https://github.com/golang/go/issues/4764
- Go CL 7308049: https://golang.org/cl/7308049