x/tools/go/analysis/passes/modernize: vars for atomic, embedlit, errorsastype, plusbuild, stringscut, stditerators
要約
概要
x/tools/go/analysis/passes/modernize パッケージ内に既に実装済みだが非公開(unexported)だった6つのアナライザ変数(AtomicTypesAnalyzer、EmbedLitAnalyzer、ErrorsastypeAnalyzer、PlusBuildAnalyzer、StringscutAnalyzer、StditeratorsAnalyzer)を公開エクスポートされた変数として公開するというプロポーザルです。機能的な変更は一切なく、既存機能への外部アクセスを可能にするAPIの追加です。
ステータス変更
likely_accept → accepted
2026年4月22日の週次レビューで likely accept に設定された後、2026年4月29日のレビュー会議(@aclements、@adonovan、@bradfitz、@cherrymui、@griesemer、@ianlancetaylor、@neild、@rolandshoemaker 出席)で反対意見や新たな議論が生じなかったため、合意に変化なしとして正式に承認されました。
技術的背景
現状の問題点
modernize パッケージには Suite 変数([]*analysis.Analyzer のスライス)が公開されており、全アナライザをまとめて利用できます。しかし、特定のアナライザだけを個別に利用したい場合(例:社内ツールに一部のアナライザだけを組み込む)、以下のいずれかの方法しかありませんでした。
Suiteスライスから目的のアナライザを名前で検索して取り出すハック的手法x/toolsのソースコードをフォークして内部変数に直接アクセスする方法
コントリビュータの @cespare はコメントで、自社の静的解析ツールにgo/analysisパスと独自パスを組み合わせて使いたいが、未公開のパスへのアクセスのためにx/toolsをフォークせざるを得ない状況であったと指摘しています。
また、gopls が内部でこれらのアナライザにアクセスするためにinternal/goplsexportパッケージを介した回避策を使っており、それ自体がハックであることも背景にあります。
提案された解決策
以下の6つのアナライザ変数を公開エクスポートする:
package modernize
+ var (
+ AtomicTypesAnalyzer *analysis.Analyzer
+ EmbedLitAnalyzer *analysis.Analyzer
+ ErrorsastypeAnalyzer *analysis.Analyzer
+ PlusBuildAnalyzer *analysis.Analyzer
+ StringscutAnalyzer *analysis.Analyzer
+ StditeratorsAnalyzer *analysis.Analyzer
+ )
各アナライザが対象とする変換内容は以下の通りです:
- AtomicTypesAnalyzer:
sync/atomicのプリミティブ関数を Go 1.19 で導入された型安全なアトミック型(atomic.Int32等)に置き換える - EmbedLitAnalyzer: Go 1.27 で導入された機能を活用し、コンポジットリテラル内の埋め込みフィールド型の冗長な指定を削除する
- ErrorsastypeAnalyzer:
errors.Asの典型的な使用パターンを Go 1.26 で追加されたerrors.AsType[T]に置き換える - PlusBuildAnalyzer: 古い
//+build形式のビルドタグを//go:build形式のタグが既に存在するファイルから削除する - StringscutAnalyzer:
strings.Indexを使ったスライシングパターンをstrings.Cut(Go 1.18 追加)に置き換える - StditeratorsAnalyzer:
Len()/At()スタイルのループを標準ライブラリが提供するイテレータ(All()等)を使ったrangeループに置き換える
これによって何ができるようになるか
独自の静的解析ツールやリンタを開発している場合に、x/tools のフォークや Suite スライスからの検索ハックなしに、特定のモダナイザアナライザを直接インポートして利用できるようになります。
コード例
// Before: Suite スライスから特定のアナライザを検索するハック的手法
import "golang.org/x/tools/go/analysis/passes/modernize"
func getAtomicAnalyzer() *analysis.Analyzer {
for _, a := range modernize.Suite {
if a.Name == "atomictypes" {
return a
}
}
return nil // 見つからない場合はnil
}
// After: 公開変数を直接利用
import "golang.org/x/tools/go/analysis/passes/modernize"
multichecker.Main(
modernize.AtomicTypesAnalyzer,
modernize.StringscutAnalyzer,
myown.CustomAnalyzer,
)
各アナライザが提供するコード変換の例:
// AtomicTypesAnalyzer: Before
var x int32
atomic.AddInt32(&x, 1)
// AtomicTypesAnalyzer: After
var x atomic.Int32
x.Add(1)
// ErrorsastypeAnalyzer: Before
var myerr *MyErr
if errors.As(err, &myerr) {
handle(myerr)
}
// ErrorsastypeAnalyzer: After
if myerr, ok := errors.AsType[*MyErr](err); ok {
handle(myerr)
}
// StringscutAnalyzer: Before
idx := strings.Index(s, substr)
if idx >= 0 {
return s[:idx]
}
// StringscutAnalyzer: After
before, _, ok := strings.Cut(s, substr)
if ok {
return before
}
議論のハイライト
- プロポーザルの発端: 当初は
atomicアナライザ(Issue #77352)だけを公開する提案だったが、@adonovan がプロポーザルの乱立を避けるため、未公開の全モダナイザ変数をまとめて公開する形に拡張した - 機能的変更なし: このプロポーザルは純粋なAPI公開であり、アナライザのロジックや動作は変更されない。
go fixでSuiteを通じて既に利用可能なものをそのまま直接アクセスできるようにするだけ - gopls の内部ハック解消: 現状 gopls は
internal/goplsexportパッケージを通じてこれらの内部変数にgoplsexport.EmbedLitModernizer = embedLitAnalyzerのような形でアクセスしており、この公開により正式な手段でアクセスできるようになる - ワークアラウンドの存在: @adonovan は「現状でも
modernizer.Suiteスライスからアナライザを取り出せる」と指摘したが、それは明確なAPIではなくハック的手法であるとして、エクスポートの正当性が認められた - release-blocker ラベル: このIssueには
release-blockerラベルが付いており、何らかのリリースに向けた優先度の高い変更として扱われている