// Copyright 2021 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build ignore // copytermlist.go copies the term list algorithm from GOROOT/src/go/types. // Run it with: // GO111MODULE=off go run copytermlist.go package main import ( "bytes" "fmt" "go/ast" "go/format" "go/parser" "go/token" "os" "path/filepath" "reflect" "runtime" "strings" "golang.org/x/tools/go/ast/astutil" ) func main() { if err := doCopy(); err != nil { fmt.Fprintf(os.Stderr, "error copying from go/types: %v", err) os.Exit(1) } } func doCopy() error { dir := filepath.Join(runtime.GOROOT(), "src", "go", "types") for _, name := range []string{"typeterm.go", "termlist.go"} { path := filepath.Join(dir, name) fset := token.NewFileSet() file, err := parser.ParseFile(fset, path, nil, parser.ParseComments) if err != nil { return err } file.Name.Name = "typeparams" file.Doc = &ast.CommentGroup{List: []*ast.Comment{&ast.Comment{Text: "DO NOT MODIFY"}}} var needImport bool selectorType := reflect.TypeOf((*ast.SelectorExpr)(nil)) astutil.Apply(file, func(c *astutil.Cursor) bool { if id, _ := c.Node().(*ast.Ident); id != nil { // Check if this ident should be qualified with types. For simplicity, // assume the copied files do not themselves contain any exported // symbols. // As a simple heuristic, just verify that the ident may be replaced by // a selector. if !token.IsExported(id.Name) { return false } v := reflect.TypeOf(c.Parent()).Elem() // ast nodes are all pointers field, ok := v.FieldByName(c.Name()) if !ok { panic("missing field") } t := field.Type if c.Index() > 0 { // => t is a slice t = t.Elem() } if !selectorType.AssignableTo(t) { return false } needImport = true c.Replace(&ast.SelectorExpr{ X: ast.NewIdent("types"), Sel: ast.NewIdent(id.Name), }) } return true }, nil) if needImport { astutil.AddImport(fset, file, "go/types") } var b bytes.Buffer if err := format.Node(&b, fset, file); err != nil { return err } // Hack in the 'generated' byline. content := b.String() header := "// Code generated by copytermlist.go DO NOT EDIT.\n\npackage typeparams" content = strings.Replace(content, "package typeparams", header, 1) if err := os.WriteFile(name, []byte(content), 0644); err != nil { return err } } return nil }