Source file
src/go/types/generate_test.go
1
2
3
4
5
6
7
8 package types_test
9
10 import (
11 "bytes"
12 "flag"
13 "go/ast"
14 "go/format"
15 "go/parser"
16 "go/token"
17 "internal/diff"
18 "os"
19 "path/filepath"
20 "runtime"
21 "strings"
22 "testing"
23 )
24
25 var filesToWrite = flag.String("write", "", `go/types files to generate, or "all" for all files`)
26
27 const (
28 srcDir = "/src/cmd/compile/internal/types2/"
29 dstDir = "/src/go/types/"
30 )
31
32
33
34
35 func TestGenerate(t *testing.T) {
36
37
38 write := *filesToWrite != ""
39 var files []string
40 if *filesToWrite != "" && *filesToWrite != "all" {
41 files = strings.Split(*filesToWrite, ",")
42 } else {
43 for file := range filemap {
44 files = append(files, file)
45 }
46 }
47
48 for _, filename := range files {
49 generate(t, filename, write)
50 }
51 }
52
53 func generate(t *testing.T, filename string, write bool) {
54
55 srcFilename := filepath.FromSlash(runtime.GOROOT() + srcDir + filename)
56 file, err := parser.ParseFile(fset, srcFilename, nil, parser.ParseComments)
57 if err != nil {
58 t.Fatal(err)
59 }
60
61
62 file.Name.Name = strings.ReplaceAll(file.Name.Name, "types2", "types")
63
64
65 if action := filemap[filename]; action != nil {
66 action(file)
67 }
68
69
70 var buf bytes.Buffer
71 buf.WriteString("// Code generated by \"go test -run=Generate -write=all\"; DO NOT EDIT.\n\n")
72 if err := format.Node(&buf, fset, file); err != nil {
73 t.Fatal(err)
74 }
75 generatedContent := buf.Bytes()
76
77 dstFilename := filepath.FromSlash(runtime.GOROOT() + dstDir + filename)
78 onDiskContent, err := os.ReadFile(dstFilename)
79 if err != nil {
80 t.Fatalf("reading %q: %v", filename, err)
81 }
82
83 if d := diff.Diff(filename+" (on disk)", onDiskContent, filename+" (generated)", generatedContent); d != nil {
84 if write {
85 t.Logf("applying change:\n%s", d)
86 if err := os.WriteFile(dstFilename, generatedContent, 0o644); err != nil {
87 t.Fatalf("writing %q: %v", filename, err)
88 }
89 } else {
90 t.Errorf("generated file content does not match:\n%s", string(d))
91 }
92 }
93 }
94
95 type action func(in *ast.File)
96
97 var filemap = map[string]action{
98 "alias.go": nil,
99 "array.go": nil,
100 "api_predicates.go": nil,
101 "basic.go": nil,
102 "chan.go": nil,
103 "const.go": func(f *ast.File) { fixTokenPos(f) },
104 "context.go": nil,
105 "context_test.go": nil,
106 "gccgosizes.go": nil,
107 "gcsizes.go": func(f *ast.File) { renameIdents(f, "IsSyncAtomicAlign64->_IsSyncAtomicAlign64") },
108 "hilbert_test.go": func(f *ast.File) { renameImportPath(f, `"cmd/compile/internal/types2"`, `"go/types"`) },
109 "infer.go": func(f *ast.File) {
110 fixTokenPos(f)
111 fixInferSig(f)
112 },
113
114 "instantiate.go": func(f *ast.File) { fixTokenPos(f); fixCheckErrorfCall(f) },
115 "instantiate_test.go": func(f *ast.File) { renameImportPath(f, `"cmd/compile/internal/types2"`, `"go/types"`) },
116 "lookup.go": func(f *ast.File) { fixTokenPos(f) },
117 "main_test.go": nil,
118 "map.go": nil,
119 "named.go": func(f *ast.File) { fixTokenPos(f); fixTraceSel(f) },
120 "object.go": func(f *ast.File) { fixTokenPos(f); renameIdents(f, "NewTypeNameLazy->_NewTypeNameLazy") },
121 "object_test.go": func(f *ast.File) { renameImportPath(f, `"cmd/compile/internal/types2"`, `"go/types"`) },
122 "objset.go": nil,
123 "package.go": nil,
124 "pointer.go": nil,
125 "predicates.go": nil,
126 "scope.go": func(f *ast.File) {
127 fixTokenPos(f)
128 renameIdents(f, "Squash->squash", "InsertLazy->_InsertLazy")
129 },
130 "selection.go": nil,
131 "sizes.go": func(f *ast.File) { renameIdents(f, "IsSyncAtomicAlign64->_IsSyncAtomicAlign64") },
132 "slice.go": nil,
133 "subst.go": func(f *ast.File) { fixTokenPos(f); fixTraceSel(f) },
134 "termlist.go": nil,
135 "termlist_test.go": nil,
136 "tuple.go": nil,
137 "typelists.go": nil,
138 "typeparam.go": nil,
139 "typeterm_test.go": nil,
140 "typeterm.go": nil,
141 "under.go": nil,
142 "unify.go": fixSprintf,
143 "universe.go": fixGlobalTypVarDecl,
144 "util_test.go": fixTokenPos,
145 "validtype.go": nil,
146 }
147
148
149
150
151
152
153 func renameIdents(f *ast.File, renames ...string) {
154 var list [][]string
155 for _, r := range renames {
156 s := strings.Split(r, "->")
157 if len(s) != 2 {
158 panic("invalid rename entry: " + r)
159 }
160 list = append(list, s)
161 }
162 ast.Inspect(f, func(n ast.Node) bool {
163 switch n := n.(type) {
164 case *ast.Ident:
165 for _, r := range list {
166 if n.Name == r[0] {
167 n.Name = r[1]
168 }
169 }
170 return false
171 }
172 return true
173 })
174 }
175
176
177 func renameImportPath(f *ast.File, from, to string) {
178 ast.Inspect(f, func(n ast.Node) bool {
179 switch n := n.(type) {
180 case *ast.ImportSpec:
181 if n.Path.Kind == token.STRING && n.Path.Value == from {
182 n.Path.Value = to
183 return false
184 }
185 }
186 return true
187 })
188 }
189
190
191
192 func fixTokenPos(f *ast.File) {
193 ast.Inspect(f, func(n ast.Node) bool {
194 switch n := n.(type) {
195 case *ast.ImportSpec:
196
197 if n.Path.Kind == token.STRING && n.Path.Value == `"cmd/compile/internal/syntax"` {
198 n.Path.Value = `"go/token"`
199 return false
200 }
201 case *ast.SelectorExpr:
202
203 if x, _ := n.X.(*ast.Ident); x != nil && x.Name == "syntax" && n.Sel.Name == "Pos" {
204 x.Name = "token"
205 return false
206 }
207 case *ast.CallExpr:
208
209 if fun, _ := n.Fun.(*ast.SelectorExpr); fun != nil && fun.Sel.Name == "IsKnown" && len(n.Args) == 0 {
210 fun.Sel.Name = "IsValid"
211 return false
212 }
213 }
214 return true
215 })
216 }
217
218
219
220
221 func fixInferSig(f *ast.File) {
222 ast.Inspect(f, func(n ast.Node) bool {
223 switch n := n.(type) {
224 case *ast.FuncDecl:
225 if n.Name.Name == "infer" {
226
227 par := n.Type.Params.List[0]
228 if len(par.Names) == 1 && par.Names[0].Name == "pos" {
229 par.Names[0] = newIdent(par.Names[0].Pos(), "posn")
230 par.Type = newIdent(par.Type.Pos(), "positioner")
231 return true
232 }
233 }
234 case *ast.CallExpr:
235 if selx, _ := n.Fun.(*ast.SelectorExpr); selx != nil {
236 switch selx.Sel.Name {
237 case "renameTParams":
238
239 if ident, _ := n.Args[0].(*ast.Ident); ident != nil && ident.Name == "pos" {
240 pos := n.Args[0].Pos()
241 fun := &ast.SelectorExpr{X: newIdent(pos, "posn"), Sel: newIdent(pos, "Pos")}
242 arg := &ast.CallExpr{Fun: fun, Lparen: pos, Args: nil, Ellipsis: token.NoPos, Rparen: pos}
243 n.Args[0] = arg
244 return false
245 }
246 case "errorf":
247
248 if ident, _ := n.Args[0].(*ast.Ident); ident != nil && ident.Name == "pos" {
249 pos := n.Args[0].Pos()
250 arg := newIdent(pos, "posn")
251 n.Args[0] = arg
252 return false
253 }
254 case "allowVersion":
255
256 if ident, _ := n.Args[1].(*ast.Ident); ident != nil && ident.Name == "pos" {
257 pos := n.Args[1].Pos()
258 arg := newIdent(pos, "posn")
259 n.Args[1] = arg
260 return false
261 }
262 }
263 }
264 }
265 return true
266 })
267 }
268
269
270 func fixErrErrorfCall(f *ast.File) {
271 ast.Inspect(f, func(n ast.Node) bool {
272 switch n := n.(type) {
273 case *ast.CallExpr:
274 if selx, _ := n.Fun.(*ast.SelectorExpr); selx != nil {
275 if ident, _ := selx.X.(*ast.Ident); ident != nil && ident.Name == "err" {
276 switch selx.Sel.Name {
277 case "errorf":
278
279 if ident, _ := n.Args[0].(*ast.Ident); ident != nil && ident.Name == "obj" {
280 pos := n.Args[0].Pos()
281 fun := &ast.SelectorExpr{X: ident, Sel: newIdent(pos, "Pos")}
282 arg := &ast.CallExpr{Fun: fun, Lparen: pos, Args: nil, Ellipsis: token.NoPos, Rparen: pos}
283 n.Args[0] = arg
284 return false
285 }
286 }
287 }
288 }
289 }
290 return true
291 })
292 }
293
294
295 func fixCheckErrorfCall(f *ast.File) {
296 ast.Inspect(f, func(n ast.Node) bool {
297 switch n := n.(type) {
298 case *ast.CallExpr:
299 if selx, _ := n.Fun.(*ast.SelectorExpr); selx != nil {
300 if ident, _ := selx.X.(*ast.Ident); ident != nil && ident.Name == "check" {
301 switch selx.Sel.Name {
302 case "errorf":
303
304 if ident, _ := n.Args[0].(*ast.Ident); ident != nil && ident.Name == "pos" {
305 pos := n.Args[0].Pos()
306 fun := newIdent(pos, "atPos")
307 arg := &ast.CallExpr{Fun: fun, Lparen: pos, Args: []ast.Expr{ident}, Ellipsis: token.NoPos, Rparen: pos}
308 n.Args[0] = arg
309 return false
310 }
311 }
312 }
313 }
314 }
315 return true
316 })
317 }
318
319
320 func fixTraceSel(f *ast.File) {
321 ast.Inspect(f, func(n ast.Node) bool {
322 switch n := n.(type) {
323 case *ast.SelectorExpr:
324
325 if n.Sel.Name == "Trace" {
326 n.Sel.Name = "_Trace"
327 return false
328 }
329 }
330 return true
331 })
332 }
333
334
335
336
337 func fixGlobalTypVarDecl(f *ast.File) {
338 ast.Inspect(f, func(n ast.Node) bool {
339 switch n := n.(type) {
340 case *ast.ValueSpec:
341
342 if len(n.Names) == 1 && n.Names[0].Name == "Typ" && len(n.Values) == 1 {
343 n.Values[0].(*ast.CompositeLit).Type.(*ast.ArrayType).Len = nil
344 return false
345 }
346 }
347 return true
348 })
349 }
350
351
352 func fixSprintf(f *ast.File) {
353 ast.Inspect(f, func(n ast.Node) bool {
354 switch n := n.(type) {
355 case *ast.CallExpr:
356 if fun, _ := n.Fun.(*ast.Ident); fun != nil && fun.Name == "sprintf" && len(n.Args) >= 4 {
357 n.Args = insert(n.Args, 1, newIdent(n.Args[1].Pos(), "nil"))
358 return false
359 }
360 }
361 return true
362 })
363 }
364
365
366 func newIdent(pos token.Pos, name string) *ast.Ident {
367 id := ast.NewIdent(name)
368 id.NamePos = pos
369 return id
370 }
371
372
373 func insert(list []ast.Expr, at int, x ast.Expr) []ast.Expr {
374 list = append(list, nil)
375 copy(list[at+1:], list[at:])
376 list[at] = x
377 return list
378 }
379
View as plain text