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