x/tools/go/analysis/passes/modernize: vars for atomic, errorsastype, plusbuild, stringscut, stditerators
要約
概要
x/tools/go/analysis/passes/modernize パッケージにおいて、現在内部実装として存在するが公開されていない5つのアナライザ(atomic、errorsastype、plusbuild、stringscut、stditerators)を公開変数(exported var)として公開することを提案しています。既存機能の公開APIへの昇格であり、新機能の追加ではありません。
ステータス変更
(新規) → active
2026年4月16日に @aclements によってプロポーザルレビューグループの active カラムに追加され、週次プロポーザルレビューミーティングでの審議対象となりました。このプロポーザルの実質的な機能はすでに modernize.Suite として実装済みであり、技術的リスクが低く議論の余地も少ないことから、比較的スムーズに active へ移行したと考えられます。
技術的背景
現状の問題点
modernize パッケージには go fix で使用されている modernize.Suite というアナライザのスライス変数があり、上記5つのアナライザはその中に含まれています。しかし、これらは外部から参照できない非公開シンボルとして実装されているため、独自の go/analysis ベースのツール(例:社内の lint ツールや gopls)からこれらのアナライザを個別に利用するには、Suite スライスから取り出すという回避策や、x/tools をフォークするといった内部ハックが必要でした。
// 現状のワークアラウンド(Suite から取り出す)
for _, a := range modernize.Suite {
if a.Name == "stringscut" {
// ここで利用...
}
}
提案された解決策
各アナライザを以下のように公開変数として export することで、外部ツールが直接参照できるようにします。
// After: 公開変数として直接参照可能になる
import "golang.org/x/tools/go/analysis/passes/modernize"
analyzer := &multichecker.Main(
modernize.AtomicAnalyzer,
modernize.StringsCutAnalyzer,
// ...
)
これによって何ができるようになるか
独自の go/analysis ベースのツールを実装している開発者が、x/tools をフォークすることなく、これら5つのアナライザを任意に組み合わせて利用できるようになります。
5つのアナライザの概要
| アナライザ | 対象Goバージョン | 変換内容 |
|---|---|---|
atomic |
Go 1.19+ | sync/atomic の関数を型安全な atomic.Int32 等の型メソッドへ置換 |
errorsastype |
Go 1.26+ | errors.As(err, &myerr) を errors.AsType[T](err) へ置換 |
plusbuild |
Go 1.17+ | //+build 旧形式のビルドタグを削除(//go:build が共存する場合) |
stringscut |
Go 1.18+ | strings.Index + スライスのパターンを strings.Cut へ置換 |
stditerators |
Go 1.23+ | Len()/At() スタイルのループを range x.All() イテレータへ置換 |
コード例
// atomic: Before
var x int32
atomic.AddInt32(&x, 1)
// atomic: After
var x atomic.Int32
x.Add(1)
// errorsastype: Before
var myerr *MyErr
if errors.As(err, &myerr) { ... }
// errorsastype: After
if myerr, ok := errors.AsType[*MyErr](err); ok { ... }
// plusbuild: Before(旧形式と新形式が共存)
//+build linux,amd64
//go:build linux && amd64
// plusbuild: After(旧形式を削除)
//go:build linux && amd64
// stringscut: Before
if i := strings.Index(s, ":"); i >= 0 {
key, value = s[:i], s[i+1:]
}
// stringscut: After
if key, value, ok := strings.Cut(s, ":"); ok { ... }
// stditerators: Before(go/types パッケージ等)
for i := 0; i < s.NumFields(); i++ {
use(s.Field(i))
}
// stditerators: After
for field := range s.Fields() {
use(field)
}
議論のハイライト
@adonovanは当初atomicアナライザのみを対象としていたが、プロポーザルの乱立を避けるために同様の未公開アナライザをまとめてこの1つの提案に統合した。@cespareは社内のgo/analysisツールでこれらのアナライザを利用したいというユースケースを提示し、外部ツール開発者からの需要を示した。現時点ではmodernize.Suiteスライスから取り出すことで技術的には回避可能だが、不安定かつ不格好な方法であると指摘。@aclementsは active 移行前に新たに公開される変数名の一覧をドキュメント化するよう求めており、API設計の明確化を重視している。- この変更は純粋にAPIの公開範囲の拡張であり、既存の動作・ロジックへの変更は一切なく、後方互換性に影響しない。
gopls内部では既にこれらのアナライザをgopls/internal/analysis/modernizeとして独自実装しており、公開APIへの統合によって内部の重複実装を解消できる可能性がある。