1 | // Copyright 2021 The Go Authors. All rights reserved. |
---|---|
2 | // Use of this source code is governed by a BSD-style |
3 | // license that can be found in the LICENSE file. |
4 | |
5 | //go:build ignore |
6 | // +build ignore |
7 | |
8 | // copytermlist.go copies the term list algorithm from GOROOT/src/go/types. |
9 | |
10 | package main |
11 | |
12 | import ( |
13 | "bytes" |
14 | "fmt" |
15 | "go/ast" |
16 | "go/format" |
17 | "go/parser" |
18 | "go/token" |
19 | "os" |
20 | "path/filepath" |
21 | "reflect" |
22 | "runtime" |
23 | "strings" |
24 | |
25 | "golang.org/x/tools/go/ast/astutil" |
26 | ) |
27 | |
28 | func main() { |
29 | if err := doCopy(); err != nil { |
30 | fmt.Fprintf(os.Stderr, "error copying from go/types: %v", err) |
31 | os.Exit(1) |
32 | } |
33 | } |
34 | |
35 | func doCopy() error { |
36 | dir := filepath.Join(runtime.GOROOT(), "src", "go", "types") |
37 | for _, name := range []string{"typeterm.go", "termlist.go"} { |
38 | path := filepath.Join(dir, name) |
39 | fset := token.NewFileSet() |
40 | file, err := parser.ParseFile(fset, path, nil, parser.ParseComments) |
41 | if err != nil { |
42 | return err |
43 | } |
44 | file.Name.Name = "typeparams" |
45 | file.Doc = &ast.CommentGroup{List: []*ast.Comment{{Text: "DO NOT MODIFY"}}} |
46 | var needImport bool |
47 | selectorType := reflect.TypeOf((*ast.SelectorExpr)(nil)) |
48 | astutil.Apply(file, func(c *astutil.Cursor) bool { |
49 | if id, _ := c.Node().(*ast.Ident); id != nil { |
50 | // Check if this ident should be qualified with types. For simplicity, |
51 | // assume the copied files do not themselves contain any exported |
52 | // symbols. |
53 | |
54 | // As a simple heuristic, just verify that the ident may be replaced by |
55 | // a selector. |
56 | if !token.IsExported(id.Name) { |
57 | return false |
58 | } |
59 | v := reflect.TypeOf(c.Parent()).Elem() // ast nodes are all pointers |
60 | field, ok := v.FieldByName(c.Name()) |
61 | if !ok { |
62 | panic("missing field") |
63 | } |
64 | t := field.Type |
65 | if c.Index() > 0 { // => t is a slice |
66 | t = t.Elem() |
67 | } |
68 | if !selectorType.AssignableTo(t) { |
69 | return false |
70 | } |
71 | needImport = true |
72 | c.Replace(&ast.SelectorExpr{ |
73 | X: &ast.Ident{NamePos: id.NamePos, Name: "types"}, |
74 | Sel: &ast.Ident{NamePos: id.NamePos, Name: id.Name, Obj: id.Obj}, |
75 | }) |
76 | } |
77 | return true |
78 | }, nil) |
79 | if needImport { |
80 | astutil.AddImport(fset, file, "go/types") |
81 | } |
82 | |
83 | var b bytes.Buffer |
84 | if err := format.Node(&b, fset, file); err != nil { |
85 | return err |
86 | } |
87 | |
88 | // Hack in the 'generated' byline. |
89 | content := b.String() |
90 | header := "// Code generated by copytermlist.go DO NOT EDIT.\n\npackage typeparams" |
91 | content = strings.Replace(content, "package typeparams", header, 1) |
92 | |
93 | if err := os.WriteFile(name, []byte(content), 0644); err != nil { |
94 | return err |
95 | } |
96 | } |
97 | return nil |
98 | } |
99 |
Members