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(testFSet, srcFilename, nil, parser.ParseComments|parser.SkipObjectResolution)
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, testFSet, 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 "alias_test.go": func(f *ast.File) {
105 renameImportPath(f, `"cmd/compile/internal/types2"->"go/types"`)
106 renameIdents(f, "types2->types")
107 },
108 "assignments.go": func(f *ast.File) {
109 renameImportPath(f, `"cmd/compile/internal/syntax"->"go/ast"`)
110 renameSelectorExprs(f, "syntax.Name->ast.Ident", "ident.Value->ident.Name", "ast.Pos->token.Pos")
111 renameIdents(f, "syntax->ast", "poser->positioner", "nopos->noposn")
112 },
113 "array.go": nil,
114 "api_predicates.go": nil,
115 "basic.go": nil,
116 "builtins.go": func(f *ast.File) {
117 renameImportPath(f, `"cmd/compile/internal/syntax"->"go/ast"`)
118 renameIdents(f, "syntax->ast")
119 renameSelectors(f, "ArgList->Args")
120 fixSelValue(f)
121 fixAtPosCall(f)
122 },
123 "builtins_test.go": func(f *ast.File) {
124 renameImportPath(f, `"cmd/compile/internal/syntax"->"go/ast"`, `"cmd/compile/internal/types2"->"go/types"`)
125 renameSelectorExprs(f, "syntax.Name->ast.Ident", "p.Value->p.Name")
126 renameIdents(f, "syntax->ast")
127 },
128 "chan.go": nil,
129 "const.go": fixTokenPos,
130 "context.go": nil,
131 "context_test.go": nil,
132 "conversions.go": nil,
133 "cycles.go": func(f *ast.File) {
134 renameImportPath(f, `"cmd/compile/internal/syntax"->"go/ast"`)
135 renameSelectorExprs(f, "syntax.Name->ast.Ident", "rhs.Value->rhs.Name")
136 renameSelectors(f, "Trace->_Trace")
137 },
138 "errorcalls_test.go": func(f *ast.File) {
139 insertImportPath(f, `"go/token"`)
140 renameImportPath(f, `"cmd/compile/internal/syntax"->"go/ast"`)
141 renameSelectorExprs(f, "syntax.StringLit->token.STRING", "syntax.Name->ast.Ident", "n.Value->n.Name")
142 renameIdents(f, "syntax->ast")
143 renameSelectors(f, "ArgList->Args")
144 fixFSet(f)
145 },
146 "errors_test.go": func(f *ast.File) { renameIdents(f, "nopos->noposn") },
147 "errsupport.go": nil,
148 "gccgosizes.go": nil,
149 "gcsizes.go": func(f *ast.File) {
150 renameIdents(f, "IsSyncAtomicAlign64->_IsSyncAtomicAlign64", "IsSyncAtomicAlign128->_IsSyncAtomicAlign128")
151 },
152 "hilbert_test.go": func(f *ast.File) { renameImportPath(f, `"cmd/compile/internal/types2"->"go/types"`) },
153 "infer.go": func(f *ast.File) { fixTokenPos(f); fixInferSig(f) },
154 "initorder.go": nil,
155
156 "instantiate.go": func(f *ast.File) { fixTokenPos(f); fixCheckErrorfCall(f); fixSprintf(f) },
157 "instantiate_test.go": func(f *ast.File) { renameImportPath(f, `"cmd/compile/internal/types2"->"go/types"`) },
158 "literals.go": func(f *ast.File) {
159 insertImportPath(f, `"go/token"`)
160 renameImportPath(f, `"cmd/compile/internal/syntax"->"go/ast"`)
161 renameSelectorExprs(f,
162 "syntax.IntLit->token.INT", "syntax.FloatLit->token.FLOAT", "syntax.ImagLit->token.IMAG",
163 "syntax.Name->ast.Ident", "key.Value->key.Name", "atyp.Elem->atyp.Elt")
164 renameIdents(f, "syntax->ast")
165 renameSelectors(f, "ElemList->Elts")
166 },
167 "lookup.go": fixTokenPos,
168 "lookup_test.go": func(f *ast.File) {
169 renameImportPath(f, `"cmd/compile/internal/types2"->"go/types"`)
170 fixFSet(f)
171 },
172 "main_test.go": nil,
173 "map.go": nil,
174 "mono.go": func(f *ast.File) {
175 fixTokenPos(f)
176 insertImportPath(f, `"go/ast"`)
177 renameSelectorExprs(f, "syntax.Expr->ast.Expr")
178 },
179 "mono_test.go": func(f *ast.File) {
180 renameImportPath(f, `"cmd/compile/internal/types2"->"go/types"`)
181 renameIdents(f, "types2->types")
182 fixFSet(f)
183 },
184 "named.go": func(f *ast.File) { fixTokenPos(f); renameSelectors(f, "Trace->_Trace") },
185 "object.go": func(f *ast.File) { fixTokenPos(f); renameIdents(f, "NewTypeNameLazy->_NewTypeNameLazy") },
186 "object_test.go": func(f *ast.File) { renameImportPath(f, `"cmd/compile/internal/types2"->"go/types"`) },
187 "objset.go": nil,
188 "operand.go": func(f *ast.File) {
189 insertImportPath(f, `"go/token"`)
190 renameImportPath(f, `"cmd/compile/internal/syntax"->"go/ast"`)
191 renameSelectorExprs(f,
192 "syntax.Pos->token.Pos", "syntax.LitKind->token.Token",
193 "syntax.IntLit->token.INT", "syntax.FloatLit->token.FLOAT",
194 "syntax.ImagLit->token.IMAG", "syntax.RuneLit->token.CHAR",
195 "syntax.StringLit->token.STRING")
196 renameIdents(f, "syntax->ast")
197 },
198 "package.go": nil,
199 "pointer.go": nil,
200 "predicates.go": nil,
201 "range.go": func(f *ast.File) {
202 renameImportPath(f, `"cmd/compile/internal/syntax"->"go/ast"`)
203 renameSelectorExprs(f, "syntax.Name->ast.Ident", "syntax.ForStmt->ast.RangeStmt", "ident.Value->ident.Name")
204 renameIdents(f, "syntax->ast", "poser->positioner")
205 },
206 "recording.go": func(f *ast.File) {
207 renameImportPath(f, `"cmd/compile/internal/syntax"->"go/ast"`)
208 renameSelectorExprs(f, "syntax.Name->ast.Ident")
209 renameIdents(f, "syntax->ast")
210 fixAtPosCall(f)
211 },
212 "scope.go": func(f *ast.File) { fixTokenPos(f); renameIdents(f, "InsertLazy->_InsertLazy") },
213 "scope_test.go": func(f *ast.File) { fixTokenPos(f) },
214 "selection.go": nil,
215 "sizeof_test.go": nil,
216 "sizes.go": func(f *ast.File) {
217 renameIdents(f, "IsSyncAtomicAlign64->_IsSyncAtomicAlign64", "IsSyncAtomicAlign128->_IsSyncAtomicAlign128")
218 },
219 "sizes_test.go": func(f *ast.File) {
220 renameImportPath(f, `"cmd/compile/internal/syntax"->"go/ast"`, `"cmd/compile/internal/types2"->"go/types"`)
221 renameSelectorExprs(f, "syntax.Expr->ast.Expr")
222 renameIdents(f, "types2->types")
223 fixFSet(f)
224 },
225 "slice.go": nil,
226 "subst.go": func(f *ast.File) { fixTokenPos(f); renameSelectors(f, "Trace->_Trace") },
227 "termlist.go": nil,
228 "termlist_test.go": nil,
229 "trie.go": nil,
230 "trie_test.go": nil,
231 "tuple.go": nil,
232 "typelists.go": nil,
233 "typeset.go": func(f *ast.File) { fixTokenPos(f); renameSelectors(f, "Trace->_Trace") },
234 "typeset_test.go": func(f *ast.File) { renameImportPath(f, `"cmd/compile/internal/types2"->"go/types"`) },
235 "typeparam.go": nil,
236 "typeterm_test.go": nil,
237 "typeterm.go": nil,
238 "typestring.go": nil,
239 "typestring_test.go": func(f *ast.File) { renameImportPath(f, `"cmd/compile/internal/types2"->"go/types"`) },
240 "under.go": nil,
241 "unify.go": fixSprintf,
242 "union.go": func(f *ast.File) {
243 renameImportPath(f, `"cmd/compile/internal/syntax"->"go/ast"`)
244 renameSelectorExprs(f, "syntax.Expr->ast.Expr")
245 },
246 "universe.go": fixGlobalTypVarDecl,
247 "util_test.go": fixTokenPos,
248 "validtype.go": func(f *ast.File) { fixTokenPos(f); renameSelectors(f, "Trace->_Trace") },
249 "version.go": func(f *ast.File) { renameIdents(f, "poser->positioner") },
250 }
251
252
253
254
255
256 type renameMap map[string]string
257
258
259 func makeRenameMap(renames ...string) renameMap {
260 m := make(renameMap)
261 for _, r := range renames {
262 s := strings.Split(r, "->")
263 if len(s) != 2 {
264 panic("invalid rename entry: " + r)
265 }
266 m[s[0]] = s[1]
267 }
268 return m
269 }
270
271
272 func (m renameMap) rename(s *string) {
273 if r, ok := m[*s]; ok {
274 *s = r
275 }
276 }
277
278
279
280 func (m renameMap) renameSel(n *ast.SelectorExpr) {
281 if a, _ := n.X.(*ast.Ident); a != nil {
282 a_x := a.Name + "." + n.Sel.Name
283 if r, ok := m[a_x]; ok {
284 b_y := strings.Split(r, ".")
285 if len(b_y) != 2 {
286 panic("invalid selector expression: " + r)
287 }
288 a.Name = b_y[0]
289 n.Sel.Name = b_y[1]
290 }
291 }
292 }
293
294
295
296 func renameIdents(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.Ident:
301 m.rename(&n.Name)
302 return false
303 }
304 return true
305 })
306 }
307
308
309 func renameSelectors(f *ast.File, renames ...string) {
310 m := makeRenameMap(renames...)
311 ast.Inspect(f, func(n ast.Node) bool {
312 switch n := n.(type) {
313 case *ast.SelectorExpr:
314 m.rename(&n.Sel.Name)
315 return false
316 }
317 return true
318 })
319
320 }
321
322
323
324 func renameSelectorExprs(f *ast.File, renames ...string) {
325 m := makeRenameMap(renames...)
326 ast.Inspect(f, func(n ast.Node) bool {
327 switch n := n.(type) {
328 case *ast.SelectorExpr:
329 m.renameSel(n)
330 return false
331 }
332 return true
333 })
334 }
335
336
337 func renameImportPath(f *ast.File, renames ...string) {
338 m := makeRenameMap(renames...)
339 ast.Inspect(f, func(n ast.Node) bool {
340 switch n := n.(type) {
341 case *ast.ImportSpec:
342 if n.Path.Kind != token.STRING {
343 panic("invalid import path")
344 }
345 m.rename(&n.Path.Value)
346 return false
347 }
348 return true
349 })
350 }
351
352
353
354 func insertImportPath(f *ast.File, path string) {
355 for _, d := range f.Decls {
356 if g, _ := d.(*ast.GenDecl); g != nil && g.Tok == token.IMPORT {
357 g.Specs = append(g.Specs, &ast.ImportSpec{Path: &ast.BasicLit{ValuePos: g.End(), Kind: token.STRING, Value: path}})
358 return
359 }
360 }
361 panic("no import declaration present")
362 }
363
364
365
366 func fixTokenPos(f *ast.File) {
367 m := makeRenameMap(`"cmd/compile/internal/syntax"->"go/token"`, "syntax.Pos->token.Pos", "IsKnown->IsValid")
368 ast.Inspect(f, func(n ast.Node) bool {
369 switch n := n.(type) {
370 case *ast.ImportSpec:
371
372 if n.Path.Kind != token.STRING {
373 panic("invalid import path")
374 }
375 m.rename(&n.Path.Value)
376 return false
377 case *ast.SelectorExpr:
378
379 m.renameSel(n)
380 case *ast.CallExpr:
381
382 if fun, _ := n.Fun.(*ast.SelectorExpr); fun != nil && len(n.Args) == 0 {
383 m.rename(&fun.Sel.Name)
384 return false
385 }
386 }
387 return true
388 })
389 }
390
391
392 func fixSelValue(f *ast.File) {
393 ast.Inspect(f, func(n ast.Node) bool {
394 switch n := n.(type) {
395 case *ast.SelectorExpr:
396 if n.Sel.Name == "Value" {
397 if selx, _ := n.X.(*ast.SelectorExpr); selx != nil && selx.Sel.Name == "Sel" {
398 n.Sel.Name = "Name"
399 return false
400 }
401 }
402 }
403 return true
404 })
405 }
406
407
408
409
410 func fixInferSig(f *ast.File) {
411 ast.Inspect(f, func(n ast.Node) bool {
412 switch n := n.(type) {
413 case *ast.FuncDecl:
414 if n.Name.Name == "infer" {
415
416 par := n.Type.Params.List[0]
417 if len(par.Names) == 1 && par.Names[0].Name == "pos" {
418 par.Names[0] = newIdent(par.Names[0].Pos(), "posn")
419 par.Type = newIdent(par.Type.Pos(), "positioner")
420 return true
421 }
422 }
423 case *ast.CallExpr:
424 if selx, _ := n.Fun.(*ast.SelectorExpr); selx != nil {
425 switch selx.Sel.Name {
426 case "renameTParams":
427
428 if isIdent(n.Args[0], "pos") {
429 pos := n.Args[0].Pos()
430 fun := &ast.SelectorExpr{X: newIdent(pos, "posn"), Sel: newIdent(pos, "Pos")}
431 arg := &ast.CallExpr{Fun: fun, Lparen: pos, Args: nil, Ellipsis: token.NoPos, Rparen: pos}
432 n.Args[0] = arg
433 return false
434 }
435 case "addf":
436
437 if isIdent(n.Args[0], "pos") {
438 pos := n.Args[0].Pos()
439 arg := newIdent(pos, "posn")
440 n.Args[0] = arg
441 return false
442 }
443 case "allowVersion":
444
445 if isIdent(n.Args[0], "pos") {
446 pos := n.Args[0].Pos()
447 arg := newIdent(pos, "posn")
448 n.Args[0] = arg
449 return false
450 }
451 }
452 }
453 }
454 return true
455 })
456 }
457
458
459
460 func fixAtPosCall(f *ast.File) {
461 ast.Inspect(f, func(n ast.Node) bool {
462 switch n := n.(type) {
463 case *ast.CallExpr:
464 if selx, _ := n.Fun.(*ast.SelectorExpr); selx != nil && selx.Sel.Name == "dump" {
465 for i, arg := range n.Args {
466 if call, _ := arg.(*ast.CallExpr); call != nil {
467
468 if isIdent(call.Fun, "atPos") {
469 pos := call.Args[0].Pos()
470 fun := &ast.SelectorExpr{X: call.Args[0], Sel: newIdent(pos, "Pos")}
471 n.Args[i] = &ast.CallExpr{Fun: fun, Lparen: pos, Rparen: pos}
472 return false
473 }
474 }
475 }
476 }
477 }
478 return true
479 })
480 }
481
482
483 func fixErrErrorfCall(f *ast.File) {
484 ast.Inspect(f, func(n ast.Node) bool {
485 switch n := n.(type) {
486 case *ast.CallExpr:
487 if selx, _ := n.Fun.(*ast.SelectorExpr); selx != nil {
488 if isIdent(selx.X, "err") {
489 switch selx.Sel.Name {
490 case "errorf":
491
492 if ident, _ := n.Args[0].(*ast.Ident); ident != nil && ident.Name == "obj" {
493 pos := n.Args[0].Pos()
494 fun := &ast.SelectorExpr{X: ident, Sel: newIdent(pos, "Pos")}
495 n.Args[0] = &ast.CallExpr{Fun: fun, Lparen: pos, Rparen: pos}
496 return false
497 }
498 }
499 }
500 }
501 }
502 return true
503 })
504 }
505
506
507 func fixCheckErrorfCall(f *ast.File) {
508 ast.Inspect(f, func(n ast.Node) bool {
509 switch n := n.(type) {
510 case *ast.CallExpr:
511 if selx, _ := n.Fun.(*ast.SelectorExpr); selx != nil {
512 if isIdent(selx.X, "check") {
513 switch selx.Sel.Name {
514 case "errorf":
515
516 if ident := asIdent(n.Args[0], "pos"); ident != nil {
517 pos := n.Args[0].Pos()
518 fun := newIdent(pos, "atPos")
519 n.Args[0] = &ast.CallExpr{Fun: fun, Lparen: pos, Args: []ast.Expr{ident}, Rparen: pos}
520 return false
521 }
522 }
523 }
524 }
525 }
526 return true
527 })
528 }
529
530
531
532
533 func fixGlobalTypVarDecl(f *ast.File) {
534 ast.Inspect(f, func(n ast.Node) bool {
535 switch n := n.(type) {
536 case *ast.ValueSpec:
537
538 if len(n.Names) == 1 && n.Names[0].Name == "Typ" && len(n.Values) == 1 {
539 n.Values[0].(*ast.CompositeLit).Type.(*ast.ArrayType).Len = nil
540 return false
541 }
542 }
543 return true
544 })
545 }
546
547
548 func fixSprintf(f *ast.File) {
549 ast.Inspect(f, func(n ast.Node) bool {
550 switch n := n.(type) {
551 case *ast.CallExpr:
552 if isIdent(n.Fun, "sprintf") && len(n.Args) >= 4 {
553 n.Args = insert(n.Args, 1, newIdent(n.Args[1].Pos(), "nil"))
554 return false
555 }
556 }
557 return true
558 })
559 }
560
561
562
563
564 func fixFSet(f *ast.File) {
565 newFSet := func(pos token.Pos) *ast.Ident { return newIdent(pos, "testFSet") }
566 ast.Inspect(f, func(n ast.Node) bool {
567 switch n := n.(type) {
568 case *ast.CallExpr:
569 switch {
570 case isIdent(n.Fun, "defaultImporter"), isIdent(n.Fun, "pkgFiles"), isIdent(n.Fun, "mustParse"):
571 pos := n.Lparen
572 n.Args = insert(n.Args, 0, newFSet(pos))
573 return false
574 case isIdent(n.Fun, "NewChecker"):
575 pos := n.Args[0].Pos()
576 n.Args = insert(n.Args, 1, newFSet(pos))
577 return false
578 }
579 if sel, _ := n.Fun.(*ast.SelectorExpr); sel != nil {
580 switch sel.Sel.Name {
581 case "Check":
582 pos := n.Args[0].Pos()
583 n.Args = insert(n.Args, 1, newFSet(pos))
584 return false
585 case "Errorf":
586 for i, arg := range n.Args {
587 if call, _ := arg.(*ast.CallExpr); call != nil && len(call.Args) == 0 {
588 if sel, _ := call.Fun.(*ast.SelectorExpr); sel != nil && sel.Sel.Name == "Pos" {
589 pos := call.Pos()
590 fun := &ast.SelectorExpr{X: newFSet(pos), Sel: newIdent(pos, "Position")}
591 n.Args[i] = &ast.CallExpr{Fun: fun, Lparen: pos, Args: []ast.Expr{call}, Rparen: pos}
592 }
593 }
594 }
595 }
596 }
597 }
598 return true
599 })
600 }
601
602
603 func asIdent(x ast.Node, name string) *ast.Ident {
604 if ident, _ := x.(*ast.Ident); ident != nil && ident.Name == name {
605 return ident
606 }
607 return nil
608 }
609
610
611 func isIdent(x ast.Node, name string) bool {
612 return asIdent(x, name) != nil
613 }
614
615
616 func newIdent(pos token.Pos, name string) *ast.Ident {
617 id := ast.NewIdent(name)
618 id.NamePos = pos
619 return id
620 }
621
622
623 func insert(list []ast.Expr, at int, x ast.Expr) []ast.Expr {
624 list = append(list, nil)
625 copy(list[at+1:], list[at:])
626 list[at] = x
627 return list
628 }
629
View as plain text