メインコンテンツへスキップ

Go Proposal Weekly Digest

Go言語のproposal更新を毎週お届け

#77986accepted

x/tools/go/analysis/passes/modernize: vars for atomic, embedlit, errorsastype, plusbuild, stringscut, stditerators

ステータス変更: likely_accept accepted

要約

AIによる要約であり、誤りを含む場合があります。

概要

x/tools/go/analysis/passes/modernize パッケージ内に既に実装済みだが非公開(unexported)だった6つのアナライザ変数(AtomicTypesAnalyzerEmbedLitAnalyzerErrorsastypeAnalyzerPlusBuildAnalyzerStringscutAnalyzerStditeratorsAnalyzer)を公開エクスポートされた変数として公開するというプロポーザルです。機能的な変更は一切なく、既存機能への外部アクセスを可能にするAPIの追加です。

ステータス変更

likely_acceptaccepted
2026年4月22日の週次レビューで likely accept に設定された後、2026年4月29日のレビュー会議(@aclements、@adonovan、@bradfitz、@cherrymui、@griesemer、@ianlancetaylor、@neild、@rolandshoemaker 出席)で反対意見や新たな議論が生じなかったため、合意に変化なしとして正式に承認されました。

技術的背景

現状の問題点

modernize パッケージには Suite 変数([]*analysis.Analyzer のスライス)が公開されており、全アナライザをまとめて利用できます。しかし、特定のアナライザだけを個別に利用したい場合(例:社内ツールに一部のアナライザだけを組み込む)、以下のいずれかの方法しかありませんでした。

  1. Suite スライスから目的のアナライザを名前で検索して取り出すハック的手法
  2. 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 fixSuite を通じて既に利用可能なものをそのまま直接アクセスできるようにするだけ
  • gopls の内部ハック解消: 現状 gopls は internal/goplsexport パッケージを通じてこれらの内部変数に goplsexport.EmbedLitModernizer = embedLitAnalyzer のような形でアクセスしており、この公開により正式な手段でアクセスできるようになる
  • ワークアラウンドの存在: @adonovan は「現状でも modernizer.Suite スライスからアナライザを取り出せる」と指摘したが、それは明確なAPIではなくハック的手法であるとして、エクスポートの正当性が認められた
  • release-blocker ラベル: このIssueには release-blocker ラベルが付いており、何らかのリリースに向けた優先度の高い変更として扱われている

関連リンク