Closed5

ast.Objectが非推奨になった挙動の対処

sho-hatasho-hata

tparagenという、GoのASTを解析してテスト並行化ラベルを付与する自作のツールをgo1.23にアップデートしたところ、staticcheckにて下記のエラーが発生した。

ast.Object has been deprecated since Go 1.22 and an alternative has been available since Go 1.0: The relationship between Idents and Objects cannot be correctly computed without type information. For example, the expression T{K: 0} may denote a struct, map, slice, or array literal, depending on the type of T. If T is a struct, then K refers to a field of T, whereas for the other types it refers to a value in the environment

実際のログ
https://github.com/sho-hata/tparagen/actions/runs/10764557617/job/29847568974?pr=24

sho-hatasho-hata

go1.22のリリースノートを読みにいくと、非推奨になった旨の情報が記載されていた。
https://tip.golang.org/doc/go1.22#:~:text=The following declarations related to syntactic identifier resolution are now deprecated

In general, identifiers cannot be accurately resolved without type information. For example, the expression T{K: 0} may denote a struct, map, slice, or array literal, depending on the type of T. If T is a struct, then K refers to a field of T, whereas for the other types it refers to a value in the environment.

型情報なしではIdentifiers(識別子)が定まらない。
T{K: 0} のような構文が、T がどの型であるかによって全く異なる意味を持つため、型情報がないと正しく解釈できない。

ast.Object型にはTypeフィールドがあるものの、型情報が入っていない。

type Object struct {
	Kind ObjKind
	Name string // declared name
	Decl any    // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, AssignStmt, Scope; or nil
	Data any    // object-specific data; or nil
	Type any    // placeholder for type information; may be nil
}

型が明示されていない場合、コンパイラは K が何を指すのか(フィールドなのか、環境中の値なのか)を正確に判断できず、
以下のような式があった場合、mapなのか構造体なのか、はたまたスライス、配列なのかわからないだろうというもの。

T{K:0}

構造体パターン

 hoge := struct{ K int }{K: 0}

この場合 T は「K というフィールドを持つ構造体」であり、K: 0 はフィールド K に 0 を代入していることになる。

mapパターン

var T map[string]int = map[string]int{"K": 0}

この場合、T{"K": 0} という式は、構造体ではなくマップリテラルとして解釈される。T がマップ型のため、"K" はキーとして解釈され、0はキー"K"に対応した値として解釈される。

sho-hatasho-hata

解決

今回のケースにおける解決策:ast.Objectを使用しない。

&ast.Ident{
        NamePos: pos,
        Name:    varName,
-        Obj: &ast.Object{
-					Name: varName,
-					Type: testMethodPackageType,
-				},
+        Obj: nil,
			},

今回のケース(ast.Identを作ってパースしたソースコードを改造するケース)においては上記の対応ができた。
その他のケースについては、ast.Object型のコメントを参考にするとよい。https://pkg.go.dev/go/ast#Object

New programs should set the [parser.SkipObjectResolution] parser flag to disable syntactic object resolution (which also saves CPU and memory), and instead use the type checker go/types if object resolution is desired. See the Defs, Uses, and Implicits fields of the [types.Info] struct for details.

このスクラップは2ヶ月前にクローズされました