github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/internal/typeparams/copytermlist.go (about)

     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  	"github.com/powerman/golang-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{&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.NewIdent("types"),
    74  					Sel: ast.NewIdent(id.Name),
    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  }