Add generated file
This PR adds generated files under pkg/client and vendor folder.
This commit is contained in:
221
vendor/golang.org/x/tools/go/pointer/query.go
generated
vendored
Normal file
221
vendor/golang.org/x/tools/go/pointer/query.go
generated
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
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.(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.(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
|
||||
}
|
Reference in New Issue
Block a user