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 "fmt"
14 "go/ast"
15 "go/format"
16 "go/parser"
17 "go/token"
18 "internal/diff"
19 "os"
20 "path/filepath"
21 "runtime"
22 "strings"
23 "testing"
24 )
25
26 var filesToWrite = flag.String("write", "", `go/types files to generate, or "all" for all files`)
27
28 const (
29 srcDir = "/src/cmd/compile/internal/types2/"
30 dstDir = "/src/go/types/"
31 )
32
33
34
35
36 func TestGenerate(t *testing.T) {
37
38
39 write := *filesToWrite != ""
40 var files []string
41 if *filesToWrite != "" && *filesToWrite != "all" {
42 files = strings.Split(*filesToWrite, ",")
43 } else {
44 for file := range filemap {
45 files = append(files, file)
46 }
47 }
48
49 for _, filename := range files {
50 generate(t, filename, write)
51 }
52 }
53
54 func generate(t *testing.T, filename string, write bool) {
55
56 srcFilename := filepath.FromSlash(runtime.GOROOT() + srcDir + filename)
57 file, err := parser.ParseFile(fset, srcFilename, nil, parser.ParseComments)
58 if err != nil {
59 t.Fatal(err)
60 }
61
62
63 file.Name.Name = strings.ReplaceAll(file.Name.Name, "types2", "types")
64
65
66 if action := filemap[filename]; action != nil {
67 action(file)
68 }
69
70
71 var buf bytes.Buffer
72 rel, _ := filepath.Rel(dstDir, srcDir)
73 fmt.Fprintf(&buf, "// Code generated by \"go test -run=Generate -write=all\"; DO NOT EDIT.\n")
74 fmt.Fprintf(&buf, "// Source: %s/%s\n\n", filepath.ToSlash(rel), filename)
75 if err := format.Node(&buf, fset, file); err != nil {
76 t.Fatal(err)
77 }
78 generatedContent := buf.Bytes()
79
80
81 dstFilename := filepath.FromSlash(runtime.GOROOT() + dstDir + filename)
82 onDiskContent, err := os.ReadFile(dstFilename)
83 if err != nil {
84 t.Fatalf("reading %q: %v", filename, err)
85 }
86
87
88 if d := diff.Diff(filename+" (on disk in "+dstDir+")", onDiskContent, filename+" (generated from "+srcDir+")", generatedContent); d != nil {
89 if write {
90 t.Logf("applying change:\n%s", d)
91 if err := os.WriteFile(dstFilename, generatedContent, 0o644); err != nil {
92 t.Fatalf("writing %q: %v", filename, err)
93 }
94 } else {
95 t.Errorf("file on disk in %s is stale:\n%s", dstDir, d)
96 }
97 }
98 }
99
100 type action func(in *ast.File)
101
102 var filemap = map[string]action{
103 "alias.go": fixTokenPos,
104 "assignments.go": func(f *ast.File) {
105 renameImportPath(f, `"cmd/compile/internal/syntax"->"go/ast"`)
106 renameSelectorExprs(f, "syntax.Name->ast.Ident", "ident.Value->ident.Name", "ast.Pos->token.Pos")
107 renameIdents(f, "syntax->ast", "poser->positioner", "nopos->noposn")
108 },
109 "array.go": nil,
110 "api_predicates.go": nil,
111 "basic.go": nil,
112 "builtins.go": func(f *ast.File) {
113 renameImportPath(f, `"cmd/compile/internal/syntax"->"go/ast"`)
114 renameIdents(f, "syntax->ast")
115 renameSelectors(f, "ArgList->Args")
116 fixSelValue(f)
117 fixAtPosCall(f)
118 },
119 "builtins_test.go": func(f *ast.File) {
120 renameImportPath(f, `"cmd/compile/internal/syntax"->"go/ast"`, `"cmd/compile/internal/types2"->"go/types"`)
121 renameSelectorExprs(f, "syntax.Name->ast.Ident", "p.Value->p.Name")
122 renameIdents(f, "syntax->ast")
123 },
124 "chan.go": nil,
125 "const.go": fixTokenPos,
126 "context.go": nil,
127 "context_test.go": nil,
128 "conversions.go": nil,
129 "cycles.go": func(f *ast.File) {
130 renameImportPath(f, `"cmd/compile/internal/syntax"->"go/ast"`)
131 renameSelectorExprs(f, "syntax.Name->ast.Ident", "rhs.Value->rhs.Name")
132 renameSelectors(f, "Trace->_Trace")
133 },
134 "errors_test.go": func(f *ast.File) { renameIdents(f, "nopos->noposn") },
135 "errsupport.go": nil,
136 "gccgosizes.go": nil,
137 "gcsizes.go": func(f *ast.File) { renameIdents(f, "IsSyncAtomicAlign64->_IsSyncAtomicAlign64") },
138 "hilbert_test.go": func(f *ast.File) { renameImportPath(f, `"cmd/compile/internal/types2"->"go/types"`) },
139 "infer.go": func(f *ast.File) { fixTokenPos(f); fixInferSig(f) },
140 "initorder.go": nil,
141
142 "instantiate.go": func(f *ast.File) { fixTokenPos(f); fixCheckErrorfCall(f) },
143 "instantiate_test.go": func(f *ast.File) { renameImportPath(f, `"cmd/compile/internal/types2"->"go/types"`) },
144 "literals.go": func(f *ast.File) {
145 insertImportPath(f, `"go/token"`)
146 renameImportPath(f, `"cmd/compile/internal/syntax"->"go/ast"`)
147 renameSelectorExprs(f,
148 "syntax.IntLit->token.INT", "syntax.FloatLit->token.FLOAT", "syntax.ImagLit->token.IMAG",
149 "syntax.Name->ast.Ident", "key.Value->key.Name", "atyp.Elem->atyp.Elt")
150 renameIdents(f, "syntax->ast")
151 renameSelectors(f, "ElemList->Elts")
152 },
153 "lookup.go": fixTokenPos,
154 "main_test.go": nil,
155 "map.go": nil,
156 "mono.go": func(f *ast.File) {
157 fixTokenPos(f)
158 insertImportPath(f, `"go/ast"`)
159 renameSelectorExprs(f, "syntax.Expr->ast.Expr")
160 },
161 "named.go": func(f *ast.File) { fixTokenPos(f); renameSelectors(f, "Trace->_Trace") },
162 "object.go": func(f *ast.File) { fixTokenPos(f); renameIdents(f, "NewTypeNameLazy->_NewTypeNameLazy") },
163
164
165 "objset.go": nil,
166 "operand.go": func(f *ast.File) {
167 insertImportPath(f, `"go/token"`)
168 renameImportPath(f, `"cmd/compile/internal/syntax"->"go/ast"`)
169 renameSelectorExprs(f,
170 "syntax.Pos->token.Pos", "syntax.LitKind->token.Token",
171 "syntax.IntLit->token.INT", "syntax.FloatLit->token.FLOAT",
172 "syntax.ImagLit->token.IMAG", "syntax.RuneLit->token.CHAR",
173 "syntax.StringLit->token.STRING")
174 renameIdents(f, "syntax->ast")
175 },
176 "package.go": nil,
177 "pointer.go": nil,
178 "predicates.go": nil,
179 "range.go": func(f *ast.File) {
180 renameImportPath(f, `"cmd/compile/internal/syntax"->"go/ast"`)
181 renameSelectorExprs(f, "syntax.Name->ast.Ident", "syntax.ForStmt->ast.RangeStmt", "ident.Value->ident.Name")
182 renameIdents(f, "syntax->ast", "poser->positioner")
183 },
184 "recording.go": func(f *ast.File) {
185 renameImportPath(f, `"cmd/compile/internal/syntax"->"go/ast"`)
186 renameSelectorExprs(f, "syntax.Name->ast.Ident")
187 renameIdents(f, "syntax->ast")
188 fixAtPosCall(f)
189 },
190 "scope.go": func(f *ast.File) { fixTokenPos(f); renameIdents(f, "InsertLazy->_InsertLazy") },
191 "selection.go": nil,
192 "sizes.go": func(f *ast.File) { renameIdents(f, "IsSyncAtomicAlign64->_IsSyncAtomicAlign64") },
193 "slice.go": nil,
194 "subst.go": func(f *ast.File) { fixTokenPos(f); renameSelectors(f, "Trace->_Trace") },
195 "termlist.go": nil,
196 "termlist_test.go": nil,
197 "tuple.go": nil,
198 "typelists.go": nil,
199 "typeset.go": func(f *ast.File) { fixTokenPos(f); renameSelectors(f, "Trace->_Trace") },
200 "typeparam.go": nil,
201 "typeterm_test.go": nil,
202 "typeterm.go": nil,
203 "typestring.go": nil,
204 "under.go": nil,
205 "unify.go": fixSprintf,
206 "universe.go": fixGlobalTypVarDecl,
207 "util_test.go": fixTokenPos,
208 "validtype.go": func(f *ast.File) { fixTokenPos(f); renameSelectors(f, "Trace->_Trace") },
209 }
210
211
212
213
214
215 type renameMap map[string]string
216
217
218 func makeRenameMap(renames ...string) renameMap {
219 m := make(renameMap)
220 for _, r := range renames {
221 s := strings.Split(r, "->")
222 if len(s) != 2 {
223 panic("invalid rename entry: " + r)
224 }
225 m[s[0]] = s[1]
226 }
227 return m
228 }
229
230
231 func (m renameMap) rename(s *string) {
232 if r, ok := m[*s]; ok {
233 *s = r
234 }
235 }
236
237
238
239 func (m renameMap) renameSel(n *ast.SelectorExpr) {
240 if a, _ := n.X.(*ast.Ident); a != nil {
241 a_x := a.Name + "." + n.Sel.Name
242 if r, ok := m[a_x]; ok {
243 b_y := strings.Split(r, ".")
244 if len(b_y) != 2 {
245 panic("invalid selector expression: " + r)
246 }
247 a.Name = b_y[0]
248 n.Sel.Name = b_y[1]
249 }
250 }
251 }
252
253
254
255 func renameIdents(f *ast.File, renames ...string) {
256 m := makeRenameMap(renames...)
257 ast.Inspect(f, func(n ast.Node) bool {
258 switch n := n.(type) {
259 case *ast.Ident:
260 m.rename(&n.Name)
261 return false
262 }
263 return true
264 })
265 }
266
267
268 func renameSelectors(f *ast.File, renames ...string) {
269 m := makeRenameMap(renames...)
270 ast.Inspect(f, func(n ast.Node) bool {
271 switch n := n.(type) {
272 case *ast.SelectorExpr:
273 m.rename(&n.Sel.Name)
274 return false
275 }
276 return true
277 })
278
279 }
280
281
282
283 func renameSelectorExprs(f *ast.File, renames ...string) {
284 m := makeRenameMap(renames...)
285 ast.Inspect(f, func(n ast.Node) bool {
286 switch n := n.(type) {
287 case *ast.SelectorExpr:
288 m.renameSel(n)
289 return false
290 }
291 return true
292 })
293 }
294
295
296 func renameImportPath(f *ast.File, renames ...string) {
297 m := makeRenameMap(renames...)
298 ast.Inspect(f, func(n ast.Node) bool {
299 switch n := n.(type) {
300 case *ast.ImportSpec:
301 if n.Path.Kind != token.STRING {
302 panic("invalid import path")
303 }
304 m.rename(&n.Path.Value)
305 return false
306 }
307 return true
308 })
309 }
310
311
312
313 func insertImportPath(f *ast.File, path string) {
314 for _, d := range f.Decls {
315 if g, _ := d.(*ast.GenDecl); g != nil && g.Tok == token.IMPORT {
316 g.Specs = append(g.Specs, &ast.ImportSpec{Path: &ast.BasicLit{ValuePos: g.End(), Kind: token.STRING, Value: path}})
317 return
318 }
319 }
320 panic("no import declaration present")
321 }
322
323
324
325 func fixTokenPos(f *ast.File) {
326 m := makeRenameMap(`"cmd/compile/internal/syntax"->"go/token"`, "syntax.Pos->token.Pos", "IsKnown->IsValid")
327 ast.Inspect(f, func(n ast.Node) bool {
328 switch n := n.(type) {
329 case *ast.ImportSpec:
330
331 if n.Path.Kind != token.STRING {
332 panic("invalid import path")
333 }
334 m.rename(&n.Path.Value)
335 return false
336 case *ast.SelectorExpr:
337
338 m.renameSel(n)
339 case *ast.CallExpr:
340
341 if fun, _ := n.Fun.(*ast.SelectorExpr); fun != nil && len(n.Args) == 0 {
342 m.rename(&fun.Sel.Name)
343 return false
344 }
345 }
346 return true
347 })
348 }
349
350
351 func fixSelValue(f *ast.File) {
352 ast.Inspect(f, func(n ast.Node) bool {
353 switch n := n.(type) {
354 case *ast.SelectorExpr:
355 if n.Sel.Name == "Value" {
356 if selx, _ := n.X.(*ast.SelectorExpr); selx != nil && selx.Sel.Name == "Sel" {
357 n.Sel.Name = "Name"
358 return false
359 }
360 }
361 }
362 return true
363 })
364 }
365
366
367
368
369 func fixInferSig(f *ast.File) {
370 ast.Inspect(f, func(n ast.Node) bool {
371 switch n := n.(type) {
372 case *ast.FuncDecl:
373 if n.Name.Name == "infer" {
374
375 par := n.Type.Params.List[0]
376 if len(par.Names) == 1 && par.Names[0].Name == "pos" {
377 par.Names[0] = newIdent(par.Names[0].Pos(), "posn")
378 par.Type = newIdent(par.Type.Pos(), "positioner")
379 return true
380 }
381 }
382 case *ast.CallExpr:
383 if selx, _ := n.Fun.(*ast.SelectorExpr); selx != nil {
384 switch selx.Sel.Name {
385 case "renameTParams":
386
387 if isIdent(n.Args[0], "pos") {
388 pos := n.Args[0].Pos()
389 fun := &ast.SelectorExpr{X: newIdent(pos, "posn"), Sel: newIdent(pos, "Pos")}
390 arg := &ast.CallExpr{Fun: fun, Lparen: pos, Args: nil, Ellipsis: token.NoPos, Rparen: pos}
391 n.Args[0] = arg
392 return false
393 }
394 case "addf":
395
396 if isIdent(n.Args[0], "pos") {
397 pos := n.Args[0].Pos()
398 arg := newIdent(pos, "posn")
399 n.Args[0] = arg
400 return false
401 }
402 case "allowVersion":
403
404 if isIdent(n.Args[0], "pos") {
405 pos := n.Args[0].Pos()
406 arg := newIdent(pos, "posn")
407 n.Args[0] = arg
408 return false
409 }
410 }
411 }
412 }
413 return true
414 })
415 }
416
417
418
419 func fixAtPosCall(f *ast.File) {
420 ast.Inspect(f, func(n ast.Node) bool {
421 switch n := n.(type) {
422 case *ast.CallExpr:
423 if selx, _ := n.Fun.(*ast.SelectorExpr); selx != nil && selx.Sel.Name == "dump" {
424 for i, arg := range n.Args {
425 if call, _ := arg.(*ast.CallExpr); call != nil {
426
427 if isIdent(call.Fun, "atPos") {
428 pos := call.Args[0].Pos()
429 fun := &ast.SelectorExpr{X: call.Args[0], Sel: newIdent(pos, "Pos")}
430 n.Args[i] = &ast.CallExpr{Fun: fun, Lparen: pos, Rparen: pos}
431 return false
432 }
433 }
434 }
435 }
436 }
437 return true
438 })
439 }
440
441
442 func fixErrErrorfCall(f *ast.File) {
443 ast.Inspect(f, func(n ast.Node) bool {
444 switch n := n.(type) {
445 case *ast.CallExpr:
446 if selx, _ := n.Fun.(*ast.SelectorExpr); selx != nil {
447 if isIdent(selx.X, "err") {
448 switch selx.Sel.Name {
449 case "errorf":
450
451 if ident, _ := n.Args[0].(*ast.Ident); ident != nil && ident.Name == "obj" {
452 pos := n.Args[0].Pos()
453 fun := &ast.SelectorExpr{X: ident, Sel: newIdent(pos, "Pos")}
454 n.Args[0] = &ast.CallExpr{Fun: fun, Lparen: pos, Rparen: pos}
455 return false
456 }
457 }
458 }
459 }
460 }
461 return true
462 })
463 }
464
465
466 func fixCheckErrorfCall(f *ast.File) {
467 ast.Inspect(f, func(n ast.Node) bool {
468 switch n := n.(type) {
469 case *ast.CallExpr:
470 if selx, _ := n.Fun.(*ast.SelectorExpr); selx != nil {
471 if isIdent(selx.X, "check") {
472 switch selx.Sel.Name {
473 case "errorf":
474
475 if ident := asIdent(n.Args[0], "pos"); ident != nil {
476 pos := n.Args[0].Pos()
477 fun := newIdent(pos, "atPos")
478 n.Args[0] = &ast.CallExpr{Fun: fun, Lparen: pos, Args: []ast.Expr{ident}, Rparen: pos}
479 return false
480 }
481 }
482 }
483 }
484 }
485 return true
486 })
487 }
488
489
490
491
492 func fixGlobalTypVarDecl(f *ast.File) {
493 ast.Inspect(f, func(n ast.Node) bool {
494 switch n := n.(type) {
495 case *ast.ValueSpec:
496
497 if len(n.Names) == 1 && n.Names[0].Name == "Typ" && len(n.Values) == 1 {
498 n.Values[0].(*ast.CompositeLit).Type.(*ast.ArrayType).Len = nil
499 return false
500 }
501 }
502 return true
503 })
504 }
505
506
507 func fixSprintf(f *ast.File) {
508 ast.Inspect(f, func(n ast.Node) bool {
509 switch n := n.(type) {
510 case *ast.CallExpr:
511 if isIdent(n.Fun, "sprintf") && len(n.Args) >= 4 {
512 n.Args = insert(n.Args, 1, newIdent(n.Args[1].Pos(), "nil"))
513 return false
514 }
515 }
516 return true
517 })
518 }
519
520
521 func asIdent(x ast.Node, name string) *ast.Ident {
522 if ident, _ := x.(*ast.Ident); ident != nil && ident.Name == name {
523 return ident
524 }
525 return nil
526 }
527
528
529 func isIdent(x ast.Node, name string) bool {
530 return asIdent(x, name) != nil
531 }
532
533
534 func newIdent(pos token.Pos, name string) *ast.Ident {
535 id := ast.NewIdent(name)
536 id.NamePos = pos
537 return id
538 }
539
540
541 func insert(list []ast.Expr, at int, x ast.Expr) []ast.Expr {
542 list = append(list, nil)
543 copy(list[at+1:], list[at:])
544 list[at] = x
545 return list
546 }
547
View as plain text