Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.0.1-2020.1.5 / cmd / keyify / keyify.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/honnef.co/go/tools@v0.0.1-2020.1.5/cmd/keyify/keyify.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/honnef.co/go/tools@v0.0.1-2020.1.5/cmd/keyify/keyify.go
new file mode 100644 (file)
index 0000000..c4a56e1
--- /dev/null
@@ -0,0 +1,409 @@
+// keyify transforms unkeyed struct literals into a keyed ones.
+package main
+
+import (
+       "bytes"
+       "encoding/json"
+       "flag"
+       "fmt"
+       "go/ast"
+       "go/build"
+       "go/constant"
+       "go/printer"
+       "go/token"
+       "go/types"
+       "log"
+       "os"
+       "path/filepath"
+
+       "honnef.co/go/tools/version"
+
+       "golang.org/x/tools/go/ast/astutil"
+       "golang.org/x/tools/go/buildutil"
+       "golang.org/x/tools/go/loader"
+)
+
+var (
+       fRecursive bool
+       fOneLine   bool
+       fJSON      bool
+       fMinify    bool
+       fModified  bool
+       fVersion   bool
+)
+
+func init() {
+       flag.BoolVar(&fRecursive, "r", false, "keyify struct initializers recursively")
+       flag.BoolVar(&fOneLine, "o", false, "print new struct initializer on a single line")
+       flag.BoolVar(&fJSON, "json", false, "print new struct initializer as JSON")
+       flag.BoolVar(&fMinify, "m", false, "omit fields that are set to their zero value")
+       flag.BoolVar(&fModified, "modified", false, "read an archive of modified files from standard input")
+       flag.BoolVar(&fVersion, "version", false, "Print version and exit")
+}
+
+func usage() {
+       fmt.Printf("Usage: %s [flags] <position>\n\n", os.Args[0])
+       flag.PrintDefaults()
+}
+
+func main() {
+       log.SetFlags(0)
+       flag.Usage = usage
+       flag.Parse()
+
+       if fVersion {
+               version.Print()
+               os.Exit(0)
+       }
+
+       if flag.NArg() != 1 {
+               flag.Usage()
+               os.Exit(2)
+       }
+       pos := flag.Args()[0]
+       name, start, _, err := parsePos(pos)
+       if err != nil {
+               log.Fatal(err)
+       }
+       eval, err := filepath.EvalSymlinks(name)
+       if err != nil {
+               log.Fatal(err)
+       }
+       name, err = filepath.Abs(eval)
+       if err != nil {
+               log.Fatal(err)
+       }
+       cwd, err := os.Getwd()
+       if err != nil {
+               log.Fatal(err)
+       }
+       ctx := &build.Default
+       if fModified {
+               overlay, err := buildutil.ParseOverlayArchive(os.Stdin)
+               if err != nil {
+                       log.Fatal(err)
+               }
+               ctx = buildutil.OverlayContext(ctx, overlay)
+       }
+       bpkg, err := buildutil.ContainingPackage(ctx, cwd, name)
+       if err != nil {
+               log.Fatal(err)
+       }
+       conf := &loader.Config{
+               Build: ctx,
+       }
+       conf.TypeCheckFuncBodies = func(s string) bool {
+               return s == bpkg.ImportPath || s == bpkg.ImportPath+"_test"
+       }
+       conf.ImportWithTests(bpkg.ImportPath)
+       lprog, err := conf.Load()
+       if err != nil {
+               log.Fatal(err)
+       }
+       var tf *token.File
+       var af *ast.File
+       var pkg *loader.PackageInfo
+outer:
+       for _, pkg = range lprog.InitialPackages() {
+               for _, ff := range pkg.Files {
+                       file := lprog.Fset.File(ff.Pos())
+                       if file.Name() == name {
+                               af = ff
+                               tf = file
+                               break outer
+                       }
+               }
+       }
+       if tf == nil {
+               log.Fatalf("couldn't find file %s", name)
+       }
+       tstart, tend, err := fileOffsetToPos(tf, start, start)
+       if err != nil {
+               log.Fatal(err)
+       }
+       path, _ := astutil.PathEnclosingInterval(af, tstart, tend)
+       var complit *ast.CompositeLit
+       for _, p := range path {
+               if p, ok := p.(*ast.CompositeLit); ok {
+                       complit = p
+                       break
+               }
+       }
+       if complit == nil {
+               log.Fatal("no composite literal found near point")
+       }
+       if len(complit.Elts) == 0 {
+               printComplit(complit, complit, lprog.Fset, lprog.Fset)
+               return
+       }
+       if _, ok := complit.Elts[0].(*ast.KeyValueExpr); ok {
+               lit := complit
+               if fOneLine {
+                       lit = copyExpr(complit, 1).(*ast.CompositeLit)
+               }
+               printComplit(complit, lit, lprog.Fset, lprog.Fset)
+               return
+       }
+       _, ok := pkg.TypeOf(complit).Underlying().(*types.Struct)
+       if !ok {
+               log.Fatal("not a struct initialiser")
+               return
+       }
+
+       newComplit, lines := keyify(pkg, complit)
+       newFset := token.NewFileSet()
+       newFile := newFset.AddFile("", -1, lines)
+       for i := 1; i <= lines; i++ {
+               newFile.AddLine(i)
+       }
+       printComplit(complit, newComplit, lprog.Fset, newFset)
+}
+
+func keyify(
+       pkg *loader.PackageInfo,
+       complit *ast.CompositeLit,
+) (*ast.CompositeLit, int) {
+       var calcPos func(int) token.Pos
+       if fOneLine {
+               calcPos = func(int) token.Pos { return token.Pos(1) }
+       } else {
+               calcPos = func(i int) token.Pos { return token.Pos(2 + i) }
+       }
+
+       st, _ := pkg.TypeOf(complit).Underlying().(*types.Struct)
+       newComplit := &ast.CompositeLit{
+               Type:   complit.Type,
+               Lbrace: 1,
+               Rbrace: token.Pos(st.NumFields() + 2),
+       }
+       if fOneLine {
+               newComplit.Rbrace = 1
+       }
+       numLines := 2 + st.NumFields()
+       n := 0
+       for i := 0; i < st.NumFields(); i++ {
+               field := st.Field(i)
+               val := complit.Elts[i]
+               if fRecursive {
+                       if val2, ok := val.(*ast.CompositeLit); ok {
+                               if _, ok := pkg.TypeOf(val2.Type).Underlying().(*types.Struct); ok {
+                                       // FIXME(dh): this code is obviously wrong. But
+                                       // what were we intending to do here?
+                                       var lines int
+                                       numLines += lines
+                                       //lint:ignore SA4006 See FIXME above.
+                                       val, lines = keyify(pkg, val2)
+                               }
+                       }
+               }
+               _, isIface := st.Field(i).Type().Underlying().(*types.Interface)
+               if fMinify && (isNil(val, pkg) || (!isIface && isZero(val, pkg))) {
+                       continue
+               }
+               elt := &ast.KeyValueExpr{
+                       Key:   &ast.Ident{NamePos: calcPos(n), Name: field.Name()},
+                       Value: copyExpr(val, calcPos(n)),
+               }
+               newComplit.Elts = append(newComplit.Elts, elt)
+               n++
+       }
+       return newComplit, numLines
+}
+
+func isNil(val ast.Expr, pkg *loader.PackageInfo) bool {
+       ident, ok := val.(*ast.Ident)
+       if !ok {
+               return false
+       }
+       if _, ok := pkg.ObjectOf(ident).(*types.Nil); ok {
+               return true
+       }
+       if c, ok := pkg.ObjectOf(ident).(*types.Const); ok {
+               if c.Val().Kind() != constant.Bool {
+                       return false
+               }
+               return !constant.BoolVal(c.Val())
+       }
+       return false
+}
+
+func isZero(val ast.Expr, pkg *loader.PackageInfo) bool {
+       switch val := val.(type) {
+       case *ast.BasicLit:
+               switch val.Value {
+               case `""`, "``", "0", "0.0", "0i", "0.":
+                       return true
+               default:
+                       return false
+               }
+       case *ast.Ident:
+               return isNil(val, pkg)
+       case *ast.CompositeLit:
+               typ := pkg.TypeOf(val.Type)
+               if typ == nil {
+                       return false
+               }
+               isIface := false
+               switch typ := typ.Underlying().(type) {
+               case *types.Struct:
+               case *types.Array:
+                       _, isIface = typ.Elem().Underlying().(*types.Interface)
+               default:
+                       return false
+               }
+               for _, elt := range val.Elts {
+                       if isNil(elt, pkg) || (!isIface && !isZero(elt, pkg)) {
+                               return false
+                       }
+               }
+               return true
+       }
+       return false
+}
+
+func printComplit(oldlit, newlit *ast.CompositeLit, oldfset, newfset *token.FileSet) {
+       buf := &bytes.Buffer{}
+       cfg := printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 8}
+       _ = cfg.Fprint(buf, newfset, newlit)
+       if fJSON {
+               output := struct {
+                       Start       int    `json:"start"`
+                       End         int    `json:"end"`
+                       Replacement string `json:"replacement"`
+               }{
+                       oldfset.Position(oldlit.Pos()).Offset,
+                       oldfset.Position(oldlit.End()).Offset,
+                       buf.String(),
+               }
+               _ = json.NewEncoder(os.Stdout).Encode(output)
+       } else {
+               fmt.Println(buf.String())
+       }
+}
+
+func copyExpr(expr ast.Expr, line token.Pos) ast.Expr {
+       switch expr := expr.(type) {
+       case *ast.BasicLit:
+               cp := *expr
+               cp.ValuePos = 0
+               return &cp
+       case *ast.BinaryExpr:
+               cp := *expr
+               cp.X = copyExpr(cp.X, line)
+               cp.OpPos = 0
+               cp.Y = copyExpr(cp.Y, line)
+               return &cp
+       case *ast.CallExpr:
+               cp := *expr
+               cp.Fun = copyExpr(cp.Fun, line)
+               cp.Lparen = 0
+               for i, v := range cp.Args {
+                       cp.Args[i] = copyExpr(v, line)
+               }
+               if cp.Ellipsis != 0 {
+                       cp.Ellipsis = line
+               }
+               cp.Rparen = 0
+               return &cp
+       case *ast.CompositeLit:
+               cp := *expr
+               cp.Type = copyExpr(cp.Type, line)
+               cp.Lbrace = 0
+               for i, v := range cp.Elts {
+                       cp.Elts[i] = copyExpr(v, line)
+               }
+               cp.Rbrace = 0
+               return &cp
+       case *ast.Ident:
+               cp := *expr
+               cp.NamePos = 0
+               return &cp
+       case *ast.IndexExpr:
+               cp := *expr
+               cp.X = copyExpr(cp.X, line)
+               cp.Lbrack = 0
+               cp.Index = copyExpr(cp.Index, line)
+               cp.Rbrack = 0
+               return &cp
+       case *ast.KeyValueExpr:
+               cp := *expr
+               cp.Key = copyExpr(cp.Key, line)
+               cp.Colon = 0
+               cp.Value = copyExpr(cp.Value, line)
+               return &cp
+       case *ast.ParenExpr:
+               cp := *expr
+               cp.Lparen = 0
+               cp.X = copyExpr(cp.X, line)
+               cp.Rparen = 0
+               return &cp
+       case *ast.SelectorExpr:
+               cp := *expr
+               cp.X = copyExpr(cp.X, line)
+               cp.Sel = copyExpr(cp.Sel, line).(*ast.Ident)
+               return &cp
+       case *ast.SliceExpr:
+               cp := *expr
+               cp.X = copyExpr(cp.X, line)
+               cp.Lbrack = 0
+               cp.Low = copyExpr(cp.Low, line)
+               cp.High = copyExpr(cp.High, line)
+               cp.Max = copyExpr(cp.Max, line)
+               cp.Rbrack = 0
+               return &cp
+       case *ast.StarExpr:
+               cp := *expr
+               cp.Star = 0
+               cp.X = copyExpr(cp.X, line)
+               return &cp
+       case *ast.TypeAssertExpr:
+               cp := *expr
+               cp.X = copyExpr(cp.X, line)
+               cp.Lparen = 0
+               cp.Type = copyExpr(cp.Type, line)
+               cp.Rparen = 0
+               return &cp
+       case *ast.UnaryExpr:
+               cp := *expr
+               cp.OpPos = 0
+               cp.X = copyExpr(cp.X, line)
+               return &cp
+       case *ast.MapType:
+               cp := *expr
+               cp.Map = 0
+               cp.Key = copyExpr(cp.Key, line)
+               cp.Value = copyExpr(cp.Value, line)
+               return &cp
+       case *ast.ArrayType:
+               cp := *expr
+               cp.Lbrack = 0
+               cp.Len = copyExpr(cp.Len, line)
+               cp.Elt = copyExpr(cp.Elt, line)
+               return &cp
+       case *ast.Ellipsis:
+               cp := *expr
+               cp.Elt = copyExpr(cp.Elt, line)
+               cp.Ellipsis = line
+               return &cp
+       case *ast.InterfaceType:
+               cp := *expr
+               cp.Interface = 0
+               return &cp
+       case *ast.StructType:
+               cp := *expr
+               cp.Struct = 0
+               return &cp
+       case *ast.FuncLit:
+               return expr
+       case *ast.ChanType:
+               cp := *expr
+               cp.Arrow = 0
+               cp.Begin = 0
+               cp.Value = copyExpr(cp.Value, line)
+               return &cp
+       case nil:
+               return nil
+       default:
+               panic(fmt.Sprintf("shouldn't happen: unknown ast.Expr of type %T", expr))
+       }
+}