.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.1-0.20210319172145-bda8f5cee399 / go / pointer / query.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.1-0.20210319172145-bda8f5cee399/go/pointer/query.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.1.1-0.20210319172145-bda8f5cee399/go/pointer/query.go
new file mode 100644 (file)
index 0000000..58aa868
--- /dev/null
@@ -0,0 +1,225 @@
+// Copyright 2017 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.
+
+package pointer
+
+import (
+       "errors"
+       "fmt"
+       "go/ast"
+       "go/parser"
+       "go/token"
+       "go/types"
+       "strconv"
+)
+
+// An extendedQuery represents a sequence of destructuring operations
+// applied to an ssa.Value (denoted by "x").
+type extendedQuery struct {
+       ops []interface{}
+       ptr *Pointer
+}
+
+// indexValue returns the value of an integer literal used as an
+// index.
+func indexValue(expr ast.Expr) (int, error) {
+       lit, ok := expr.(*ast.BasicLit)
+       if !ok {
+               return 0, fmt.Errorf("non-integer index (%T)", expr)
+       }
+       if lit.Kind != token.INT {
+               return 0, fmt.Errorf("non-integer index %s", lit.Value)
+       }
+       return strconv.Atoi(lit.Value)
+}
+
+// parseExtendedQuery parses and validates a destructuring Go
+// expression and returns the sequence of destructuring operations.
+// See parseDestructuringExpr for details.
+func parseExtendedQuery(typ types.Type, query string) ([]interface{}, types.Type, error) {
+       expr, err := parser.ParseExpr(query)
+       if err != nil {
+               return nil, nil, err
+       }
+       ops, typ, err := destructuringOps(typ, expr)
+       if err != nil {
+               return nil, nil, err
+       }
+       if len(ops) == 0 {
+               return nil, nil, errors.New("invalid query: must not be empty")
+       }
+       if ops[0] != "x" {
+               return nil, nil, fmt.Errorf("invalid query: query operand must be named x")
+       }
+       if !CanPoint(typ) {
+               return nil, nil, fmt.Errorf("query does not describe a pointer-like value: %s", typ)
+       }
+       return ops, typ, nil
+}
+
+// destructuringOps parses a Go expression consisting only of an
+// identifier "x", field selections, indexing, channel receives, load
+// operations and parens---for example: "<-(*x[i])[key]"--- and
+// returns the sequence of destructuring operations on x.
+func destructuringOps(typ types.Type, expr ast.Expr) ([]interface{}, types.Type, error) {
+       switch expr := expr.(type) {
+       case *ast.SelectorExpr:
+               out, typ, err := destructuringOps(typ, expr.X)
+               if err != nil {
+                       return nil, nil, err
+               }
+
+               var structT *types.Struct
+               switch typ := typ.Underlying().(type) {
+               case *types.Pointer:
+                       var ok bool
+                       structT, ok = typ.Elem().Underlying().(*types.Struct)
+                       if !ok {
+                               return nil, nil, fmt.Errorf("cannot access field %s of pointer to type %s", expr.Sel.Name, typ.Elem())
+                       }
+
+                       out = append(out, "load")
+               case *types.Struct:
+                       structT = typ
+               default:
+                       return nil, nil, fmt.Errorf("cannot access field %s of type %s", expr.Sel.Name, typ)
+               }
+
+               for i := 0; i < structT.NumFields(); i++ {
+                       field := structT.Field(i)
+                       if field.Name() == expr.Sel.Name {
+                               out = append(out, "field", i)
+                               return out, field.Type().Underlying(), nil
+                       }
+               }
+               // TODO(dh): supporting embedding would need something like
+               // types.LookupFieldOrMethod, but without taking package
+               // boundaries into account, because we may want to access
+               // unexported fields. If we were only interested in one level
+               // of unexported name, we could determine the appropriate
+               // package and run LookupFieldOrMethod with that. However, a
+               // single query may want to cross multiple package boundaries,
+               // and at this point it's not really worth the complexity.
+               return nil, nil, fmt.Errorf("no field %s in %s (embedded fields must be resolved manually)", expr.Sel.Name, structT)
+       case *ast.Ident:
+               return []interface{}{expr.Name}, typ, nil
+       case *ast.BasicLit:
+               return []interface{}{expr.Value}, nil, nil
+       case *ast.IndexExpr:
+               out, typ, err := destructuringOps(typ, expr.X)
+               if err != nil {
+                       return nil, nil, err
+               }
+               switch typ := typ.Underlying().(type) {
+               case *types.Array:
+                       out = append(out, "arrayelem")
+                       return out, typ.Elem().Underlying(), nil
+               case *types.Slice:
+                       out = append(out, "sliceelem")
+                       return out, typ.Elem().Underlying(), nil
+               case *types.Map:
+                       out = append(out, "mapelem")
+                       return out, typ.Elem().Underlying(), nil
+               case *types.Tuple:
+                       out = append(out, "index")
+                       idx, err := indexValue(expr.Index)
+                       if err != nil {
+                               return nil, nil, err
+                       }
+                       out = append(out, idx)
+                       if idx >= typ.Len() || idx < 0 {
+                               return nil, nil, fmt.Errorf("tuple index %d out of bounds", idx)
+                       }
+                       return out, typ.At(idx).Type().Underlying(), nil
+               default:
+                       return nil, nil, fmt.Errorf("cannot index type %s", typ)
+               }
+
+       case *ast.UnaryExpr:
+               if expr.Op != token.ARROW {
+                       return nil, nil, fmt.Errorf("unsupported unary operator %s", expr.Op)
+               }
+               out, typ, err := destructuringOps(typ, expr.X)
+               if err != nil {
+                       return nil, nil, err
+               }
+               ch, ok := typ.(*types.Chan)
+               if !ok {
+                       return nil, nil, fmt.Errorf("cannot receive from value of type %s", typ)
+               }
+               out = append(out, "recv")
+               return out, ch.Elem().Underlying(), err
+       case *ast.ParenExpr:
+               return destructuringOps(typ, expr.X)
+       case *ast.StarExpr:
+               out, typ, err := destructuringOps(typ, expr.X)
+               if err != nil {
+                       return nil, nil, err
+               }
+               ptr, ok := typ.(*types.Pointer)
+               if !ok {
+                       return nil, nil, fmt.Errorf("cannot dereference type %s", typ)
+               }
+               out = append(out, "load")
+               return out, ptr.Elem().Underlying(), err
+       default:
+               return nil, nil, fmt.Errorf("unsupported expression %T", expr)
+       }
+}
+
+func (a *analysis) evalExtendedQuery(t types.Type, id nodeid, ops []interface{}) (types.Type, nodeid) {
+       pid := id
+       // TODO(dh): we're allocating intermediary nodes each time
+       // evalExtendedQuery is called. We should probably only generate
+       // them once per (v, ops) pair.
+       for i := 1; i < len(ops); i++ {
+               var nid nodeid
+               switch ops[i] {
+               case "recv":
+                       t = t.(*types.Chan).Elem().Underlying()
+                       nid = a.addNodes(t, "query.extended")
+                       a.load(nid, pid, 0, a.sizeof(t))
+               case "field":
+                       i++ // fetch field index
+                       tt := t.(*types.Struct)
+                       idx := ops[i].(int)
+                       offset := a.offsetOf(t, idx)
+                       t = tt.Field(idx).Type().Underlying()
+                       nid = a.addNodes(t, "query.extended")
+                       a.copy(nid, pid+nodeid(offset), a.sizeof(t))
+               case "arrayelem":
+                       t = t.(*types.Array).Elem().Underlying()
+                       nid = a.addNodes(t, "query.extended")
+                       a.copy(nid, 1+pid, a.sizeof(t))
+               case "sliceelem":
+                       t = t.(*types.Slice).Elem().Underlying()
+                       nid = a.addNodes(t, "query.extended")
+                       a.load(nid, pid, 1, a.sizeof(t))
+               case "mapelem":
+                       tt := t.(*types.Map)
+                       t = tt.Elem()
+                       ksize := a.sizeof(tt.Key())
+                       vsize := a.sizeof(tt.Elem())
+                       nid = a.addNodes(t, "query.extended")
+                       a.load(nid, pid, ksize, vsize)
+               case "index":
+                       i++ // fetch index
+                       tt := t.(*types.Tuple)
+                       idx := ops[i].(int)
+                       t = tt.At(idx).Type().Underlying()
+                       nid = a.addNodes(t, "query.extended")
+                       a.copy(nid, pid+nodeid(idx), a.sizeof(t))
+               case "load":
+                       t = t.(*types.Pointer).Elem().Underlying()
+                       nid = a.addNodes(t, "query.extended")
+                       a.load(nid, pid, 0, a.sizeof(t))
+               default:
+                       // shouldn't happen
+                       panic(fmt.Sprintf("unknown op %q", ops[i]))
+               }
+               pid = nid
+       }
+
+       return t, pid
+}