mirror of
https://github.com/golang/go
synced 2024-10-05 20:41:22 -06:00
41342dc73c
R=golang-dev, r CC=golang-dev https://golang.org/cl/4450053
862 lines
24 KiB
Go
862 lines
24 KiB
Go
// Copyright 2011 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.
|
|
|
|
// TODO(rsc): Once there is better support for writing
|
|
// multi-package commands, this should really be in
|
|
// its own package, and then we can drop all the "reflect"
|
|
// prefixes on the global variables and functions.
|
|
|
|
package main
|
|
|
|
import (
|
|
"go/ast"
|
|
"go/token"
|
|
"strings"
|
|
)
|
|
|
|
var reflectFix = fix{
|
|
"reflect",
|
|
reflectFn,
|
|
`Adapt code to new reflect API.
|
|
|
|
http://codereview.appspot.com/4281055
|
|
http://codereview.appspot.com/4433066
|
|
`,
|
|
}
|
|
|
|
func init() {
|
|
register(reflectFix)
|
|
}
|
|
|
|
// The reflect API change dropped the concrete types *reflect.ArrayType etc.
|
|
// Any type assertions prior to method calls can be deleted:
|
|
// x.(*reflect.ArrayType).Len() -> x.Len()
|
|
//
|
|
// Any type checks can be replaced by assignment and check of Kind:
|
|
// x, y := z.(*reflect.ArrayType)
|
|
// ->
|
|
// x := z
|
|
// y := x.Kind() == reflect.Array
|
|
//
|
|
// If z is an ordinary variable name and x is not subsequently assigned to,
|
|
// references to x can be replaced by z and the assignment deleted.
|
|
// We only bother if x and z are the same name.
|
|
// If y is not subsequently assigned to and neither is x, references to
|
|
// y can be replaced by its expression. We only bother when there is
|
|
// just one use or when the use appears in an if clause.
|
|
//
|
|
// Not all type checks result in a single Kind check. The rewrite of the type check for
|
|
// reflect.ArrayOrSliceType checks x.Kind() against reflect.Array and reflect.Slice.
|
|
// The rewrite for *reflect.IntType checks againt Int, Int8, Int16, Int32, Int64.
|
|
// The rewrite for *reflect.UintType adds Uintptr.
|
|
//
|
|
// A type switch turns into an assignment and a switch on Kind:
|
|
// switch x := y.(type) {
|
|
// case reflect.ArrayOrSliceType:
|
|
// ...
|
|
// case *reflect.ChanType:
|
|
// ...
|
|
// case *reflect.IntType:
|
|
// ...
|
|
// }
|
|
// ->
|
|
// switch x := y; x.Kind() {
|
|
// case reflect.Array, reflect.Slice:
|
|
// ...
|
|
// case reflect.Chan:
|
|
// ...
|
|
// case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
|
// ...
|
|
// }
|
|
//
|
|
// The same simplification applies: we drop x := x if x is not assigned
|
|
// to in the switch cases.
|
|
//
|
|
// Because the type check assignment includes a type assertion in its
|
|
// syntax and the rewrite traversal is bottom up, we must do a pass to
|
|
// rewrite the type check assignments and then a separate pass to
|
|
// rewrite the type assertions.
|
|
//
|
|
// The same process applies to the API changes for reflect.Value.
|
|
//
|
|
// For both cases, but especially Value, the code needs to be aware
|
|
// of the type of a receiver when rewriting a method call. For example,
|
|
// x.(*reflect.ArrayValue).Elem(i) becomes x.Index(i) while
|
|
// x.(*reflect.MapValue).Elem(v) becomes x.MapIndex(v).
|
|
// In general, reflectFn needs to know the type of the receiver expression.
|
|
// In most cases (and in all the cases in the Go source tree), the toy
|
|
// type checker in typecheck.go provides enough information for gofix
|
|
// to make the rewrite. If gofix misses a rewrite, the code that is left over
|
|
// will not compile, so it will be noticed immediately.
|
|
|
|
func reflectFn(f *ast.File) bool {
|
|
if !imports(f, "reflect") {
|
|
return false
|
|
}
|
|
|
|
fixed := false
|
|
|
|
// Rewrite names in method calls.
|
|
// Needs basic type information (see above).
|
|
typeof := typecheck(reflectTypeConfig, f)
|
|
walk(f, func(n interface{}) {
|
|
switch n := n.(type) {
|
|
case *ast.SelectorExpr:
|
|
typ := typeof[n.X]
|
|
if m := reflectRewriteMethod[typ]; m != nil {
|
|
if replace := m[n.Sel.Name]; replace != "" {
|
|
n.Sel.Name = replace
|
|
fixed = true
|
|
return
|
|
}
|
|
}
|
|
|
|
// For all reflect Values, replace SetValue with Set.
|
|
if isReflectValue[typ] && n.Sel.Name == "SetValue" {
|
|
n.Sel.Name = "Set"
|
|
fixed = true
|
|
return
|
|
}
|
|
|
|
// Replace reflect.MakeZero with reflect.Zero.
|
|
if isPkgDot(n, "reflect", "MakeZero") {
|
|
n.Sel.Name = "Zero"
|
|
fixed = true
|
|
return
|
|
}
|
|
}
|
|
})
|
|
|
|
// Replace PtrValue's PointTo(x) with Set(x.Addr()).
|
|
walk(f, func(n interface{}) {
|
|
call, ok := n.(*ast.CallExpr)
|
|
if !ok || len(call.Args) != 1 {
|
|
return
|
|
}
|
|
sel, ok := call.Fun.(*ast.SelectorExpr)
|
|
if !ok || sel.Sel.Name != "PointTo" {
|
|
return
|
|
}
|
|
typ := typeof[sel.X]
|
|
if typ != "*reflect.PtrValue" {
|
|
return
|
|
}
|
|
sel.Sel.Name = "Set"
|
|
if !isTopName(call.Args[0], "nil") {
|
|
call.Args[0] = &ast.SelectorExpr{
|
|
X: call.Args[0],
|
|
Sel: ast.NewIdent("Addr()"),
|
|
}
|
|
}
|
|
fixed = true
|
|
})
|
|
|
|
// Fix type switches.
|
|
walk(f, func(n interface{}) {
|
|
if reflectFixSwitch(n) {
|
|
fixed = true
|
|
}
|
|
})
|
|
|
|
// Fix type assertion checks (multiple assignment statements).
|
|
// Have to work on the statement context (statement list or if statement)
|
|
// so that we can insert an extra statement occasionally.
|
|
// Ignoring for and switch because they don't come up in
|
|
// typical code.
|
|
walk(f, func(n interface{}) {
|
|
switch n := n.(type) {
|
|
case *[]ast.Stmt:
|
|
// v is the replacement statement list.
|
|
var v []ast.Stmt
|
|
insert := func(x ast.Stmt) {
|
|
v = append(v, x)
|
|
}
|
|
for i, x := range *n {
|
|
// Tentatively append to v; if we rewrite x
|
|
// we'll have to update the entry, so remember
|
|
// the index.
|
|
j := len(v)
|
|
v = append(v, x)
|
|
if reflectFixTypecheck(&x, insert, (*n)[i+1:]) {
|
|
// reflectFixTypecheck may have overwritten x.
|
|
// Update the entry we appended just before the call.
|
|
v[j] = x
|
|
fixed = true
|
|
}
|
|
}
|
|
*n = v
|
|
case *ast.IfStmt:
|
|
x := &ast.ExprStmt{n.Cond}
|
|
if reflectFixTypecheck(&n.Init, nil, []ast.Stmt{x, n.Body, n.Else}) {
|
|
n.Cond = x.X
|
|
fixed = true
|
|
}
|
|
}
|
|
})
|
|
|
|
// Warn about any typecheck statements that we missed.
|
|
walk(f, reflectWarnTypecheckStmt)
|
|
|
|
// Now that those are gone, fix remaining type assertions.
|
|
// Delayed because the type checks have
|
|
// type assertions as part of their syntax.
|
|
walk(f, func(n interface{}) {
|
|
if reflectFixAssert(n) {
|
|
fixed = true
|
|
}
|
|
})
|
|
|
|
// Now that the type assertions are gone, rewrite remaining
|
|
// references to specific reflect types to use the general ones.
|
|
walk(f, func(n interface{}) {
|
|
ptr, ok := n.(*ast.Expr)
|
|
if !ok {
|
|
return
|
|
}
|
|
nn := *ptr
|
|
typ := reflectType(nn)
|
|
if typ == "" {
|
|
return
|
|
}
|
|
if strings.HasSuffix(typ, "Type") {
|
|
*ptr = newPkgDot(nn.Pos(), "reflect", "Type")
|
|
} else {
|
|
*ptr = newPkgDot(nn.Pos(), "reflect", "Value")
|
|
}
|
|
fixed = true
|
|
})
|
|
|
|
// Rewrite v.Set(nil) to v.Set(reflect.MakeZero(v.Type())).
|
|
walk(f, func(n interface{}) {
|
|
call, ok := n.(*ast.CallExpr)
|
|
if !ok || len(call.Args) != 1 || !isTopName(call.Args[0], "nil") {
|
|
return
|
|
}
|
|
sel, ok := call.Fun.(*ast.SelectorExpr)
|
|
if !ok || !isReflectValue[typeof[sel.X]] || sel.Sel.Name != "Set" {
|
|
return
|
|
}
|
|
call.Args[0] = &ast.CallExpr{
|
|
Fun: newPkgDot(call.Args[0].Pos(), "reflect", "Zero"),
|
|
Args: []ast.Expr{
|
|
&ast.CallExpr{
|
|
Fun: &ast.SelectorExpr{
|
|
X: sel.X,
|
|
Sel: &ast.Ident{Name: "Type"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
fixed = true
|
|
})
|
|
|
|
// Rewrite v != nil to v.IsValid().
|
|
// Rewrite nil used as reflect.Value (in function argument or return) to reflect.Value{}.
|
|
walk(f, func(n interface{}) {
|
|
ptr, ok := n.(*ast.Expr)
|
|
if !ok {
|
|
return
|
|
}
|
|
if isTopName(*ptr, "nil") && isReflectValue[typeof[*ptr]] {
|
|
*ptr = ast.NewIdent("reflect.Value{}")
|
|
fixed = true
|
|
return
|
|
}
|
|
nn, ok := (*ptr).(*ast.BinaryExpr)
|
|
if !ok || (nn.Op != token.EQL && nn.Op != token.NEQ) || !isTopName(nn.Y, "nil") || !isReflectValue[typeof[nn.X]] {
|
|
return
|
|
}
|
|
var call ast.Expr = &ast.CallExpr{
|
|
Fun: &ast.SelectorExpr{
|
|
X: nn.X,
|
|
Sel: &ast.Ident{Name: "IsValid"},
|
|
},
|
|
}
|
|
if nn.Op == token.EQL {
|
|
call = &ast.UnaryExpr{Op: token.NOT, X: call}
|
|
}
|
|
*ptr = call
|
|
fixed = true
|
|
})
|
|
|
|
// Rewrite
|
|
// reflect.Typeof -> reflect.TypeOf,
|
|
walk(f, func(n interface{}) {
|
|
sel, ok := n.(*ast.SelectorExpr)
|
|
if !ok {
|
|
return
|
|
}
|
|
if isTopName(sel.X, "reflect") && sel.Sel.Name == "Typeof" {
|
|
sel.Sel.Name = "TypeOf"
|
|
fixed = true
|
|
}
|
|
if isTopName(sel.X, "reflect") && sel.Sel.Name == "NewValue" {
|
|
sel.Sel.Name = "ValueOf"
|
|
fixed = true
|
|
}
|
|
})
|
|
|
|
return fixed
|
|
}
|
|
|
|
// reflectFixSwitch rewrites *n (if n is an *ast.Stmt) corresponding
|
|
// to a type switch.
|
|
func reflectFixSwitch(n interface{}) bool {
|
|
ptr, ok := n.(*ast.Stmt)
|
|
if !ok {
|
|
return false
|
|
}
|
|
n = *ptr
|
|
|
|
ts, ok := n.(*ast.TypeSwitchStmt)
|
|
if !ok {
|
|
return false
|
|
}
|
|
|
|
// Are any switch cases referring to reflect types?
|
|
// (That is, is this an old reflect type switch?)
|
|
for _, cas := range ts.Body.List {
|
|
for _, typ := range cas.(*ast.CaseClause).List {
|
|
if reflectType(typ) != "" {
|
|
goto haveReflect
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
|
|
haveReflect:
|
|
// Now we know it's an old reflect type switch. Prepare the new version,
|
|
// but don't replace or edit the original until we're sure of success.
|
|
|
|
// Figure out the initializer statement, if any, and the receiver for the Kind call.
|
|
var init ast.Stmt
|
|
var rcvr ast.Expr
|
|
|
|
init = ts.Init
|
|
switch n := ts.Assign.(type) {
|
|
default:
|
|
warn(ts.Pos(), "unexpected form in type switch")
|
|
return false
|
|
|
|
case *ast.AssignStmt:
|
|
as := n
|
|
ta := as.Rhs[0].(*ast.TypeAssertExpr)
|
|
x := isIdent(as.Lhs[0])
|
|
z := isIdent(ta.X)
|
|
|
|
if isBlank(x) || x != nil && z != nil && x.Name == z.Name && !assignsTo(x, ts.Body.List) {
|
|
// Can drop the variable creation.
|
|
rcvr = ta.X
|
|
} else {
|
|
// Need to use initialization statement.
|
|
if init != nil {
|
|
warn(ts.Pos(), "cannot rewrite reflect type switch with initializing statement")
|
|
return false
|
|
}
|
|
init = &ast.AssignStmt{
|
|
Lhs: []ast.Expr{as.Lhs[0]},
|
|
TokPos: as.TokPos,
|
|
Tok: token.DEFINE,
|
|
Rhs: []ast.Expr{ta.X},
|
|
}
|
|
rcvr = as.Lhs[0]
|
|
}
|
|
|
|
case *ast.ExprStmt:
|
|
rcvr = n.X.(*ast.TypeAssertExpr).X
|
|
}
|
|
|
|
// Prepare rewritten type switch (see large comment above for form).
|
|
sw := &ast.SwitchStmt{
|
|
Switch: ts.Switch,
|
|
Init: init,
|
|
Tag: &ast.CallExpr{
|
|
Fun: &ast.SelectorExpr{
|
|
X: rcvr,
|
|
Sel: &ast.Ident{
|
|
NamePos: rcvr.End(),
|
|
Name: "Kind",
|
|
Obj: nil,
|
|
},
|
|
},
|
|
Lparen: rcvr.End(),
|
|
Rparen: rcvr.End(),
|
|
},
|
|
Body: &ast.BlockStmt{
|
|
Lbrace: ts.Body.Lbrace,
|
|
List: nil, // to be filled in
|
|
Rbrace: ts.Body.Rbrace,
|
|
},
|
|
}
|
|
|
|
// Translate cases.
|
|
for _, tcas := range ts.Body.List {
|
|
tcas := tcas.(*ast.CaseClause)
|
|
cas := &ast.CaseClause{
|
|
Case: tcas.Case,
|
|
Colon: tcas.Colon,
|
|
Body: tcas.Body,
|
|
}
|
|
for _, t := range tcas.List {
|
|
if isTopName(t, "nil") {
|
|
cas.List = append(cas.List, newPkgDot(t.Pos(), "reflect", "Invalid"))
|
|
continue
|
|
}
|
|
|
|
typ := reflectType(t)
|
|
if typ == "" {
|
|
warn(t.Pos(), "cannot rewrite reflect type switch case with non-reflect type %s", gofmt(t))
|
|
cas.List = append(cas.List, t)
|
|
continue
|
|
}
|
|
|
|
for _, k := range reflectKind[typ] {
|
|
cas.List = append(cas.List, newPkgDot(t.Pos(), "reflect", k))
|
|
}
|
|
}
|
|
sw.Body.List = append(sw.Body.List, cas)
|
|
}
|
|
|
|
// Everything worked. Rewrite AST.
|
|
*ptr = sw
|
|
return true
|
|
}
|
|
|
|
// Rewrite x, y = z.(T) into
|
|
// x = z
|
|
// y = x.Kind() == K
|
|
// as described in the long comment above.
|
|
//
|
|
// If insert != nil, it can be called to insert a statement after *ptr in its block.
|
|
// If insert == nil, insertion is not possible.
|
|
// At most one call to insert is allowed.
|
|
//
|
|
// Scope gives the statements for which a declaration
|
|
// in *ptr would be in scope.
|
|
//
|
|
// The result is true of the statement was rewritten.
|
|
//
|
|
func reflectFixTypecheck(ptr *ast.Stmt, insert func(ast.Stmt), scope []ast.Stmt) bool {
|
|
st := *ptr
|
|
as, ok := st.(*ast.AssignStmt)
|
|
if !ok || len(as.Lhs) != 2 || len(as.Rhs) != 1 {
|
|
return false
|
|
}
|
|
|
|
ta, ok := as.Rhs[0].(*ast.TypeAssertExpr)
|
|
if !ok {
|
|
return false
|
|
}
|
|
typ := reflectType(ta.Type)
|
|
if typ == "" {
|
|
return false
|
|
}
|
|
|
|
// Have x, y := z.(t).
|
|
x := isIdent(as.Lhs[0])
|
|
y := isIdent(as.Lhs[1])
|
|
z := isIdent(ta.X)
|
|
|
|
// First step is x := z, unless it's x := x and the resulting x is never reassigned.
|
|
// rcvr is the x in x.Kind().
|
|
var rcvr ast.Expr
|
|
if isBlank(x) ||
|
|
as.Tok == token.DEFINE && x != nil && z != nil && x.Name == z.Name && !assignsTo(x, scope) {
|
|
// Can drop the statement.
|
|
// If we need to insert a statement later, now we have a slot.
|
|
*ptr = &ast.EmptyStmt{}
|
|
insert = func(x ast.Stmt) { *ptr = x }
|
|
rcvr = ta.X
|
|
} else {
|
|
*ptr = &ast.AssignStmt{
|
|
Lhs: []ast.Expr{as.Lhs[0]},
|
|
TokPos: as.TokPos,
|
|
Tok: as.Tok,
|
|
Rhs: []ast.Expr{ta.X},
|
|
}
|
|
rcvr = as.Lhs[0]
|
|
}
|
|
|
|
// Prepare x.Kind() == T expression appropriate to t.
|
|
// If x is not a simple identifier, warn that we might be
|
|
// reevaluating x.
|
|
if x == nil {
|
|
warn(as.Pos(), "rewrite reevaluates expr with possible side effects: %s", gofmt(as.Lhs[0]))
|
|
}
|
|
yExpr, yNotExpr := reflectKindEq(rcvr, reflectKind[typ])
|
|
|
|
// Second step is y := x.Kind() == T, unless it's only used once
|
|
// or we have no way to insert that statement.
|
|
var yStmt *ast.AssignStmt
|
|
if as.Tok == token.DEFINE && countUses(y, scope) <= 1 || insert == nil {
|
|
// Can drop the statement and use the expression directly.
|
|
rewriteUses(y,
|
|
func(token.Pos) ast.Expr { return yExpr },
|
|
func(token.Pos) ast.Expr { return yNotExpr },
|
|
scope)
|
|
} else {
|
|
yStmt = &ast.AssignStmt{
|
|
Lhs: []ast.Expr{as.Lhs[1]},
|
|
TokPos: as.End(),
|
|
Tok: as.Tok,
|
|
Rhs: []ast.Expr{yExpr},
|
|
}
|
|
insert(yStmt)
|
|
}
|
|
return true
|
|
}
|
|
|
|
// reflectKindEq returns the expression z.Kind() == kinds[0] || z.Kind() == kinds[1] || ...
|
|
// and its negation.
|
|
// The qualifier "reflect." is inserted before each kinds[i] expression.
|
|
func reflectKindEq(z ast.Expr, kinds []string) (ast.Expr, ast.Expr) {
|
|
n := len(kinds)
|
|
if n == 1 {
|
|
y := &ast.BinaryExpr{
|
|
X: &ast.CallExpr{
|
|
Fun: &ast.SelectorExpr{
|
|
X: z,
|
|
Sel: ast.NewIdent("Kind"),
|
|
},
|
|
},
|
|
Op: token.EQL,
|
|
Y: newPkgDot(token.NoPos, "reflect", kinds[0]),
|
|
}
|
|
ynot := &ast.BinaryExpr{
|
|
X: &ast.CallExpr{
|
|
Fun: &ast.SelectorExpr{
|
|
X: z,
|
|
Sel: ast.NewIdent("Kind"),
|
|
},
|
|
},
|
|
Op: token.NEQ,
|
|
Y: newPkgDot(token.NoPos, "reflect", kinds[0]),
|
|
}
|
|
return y, ynot
|
|
}
|
|
|
|
x, xnot := reflectKindEq(z, kinds[0:n-1])
|
|
y, ynot := reflectKindEq(z, kinds[n-1:])
|
|
|
|
or := &ast.BinaryExpr{
|
|
X: x,
|
|
Op: token.LOR,
|
|
Y: y,
|
|
}
|
|
andnot := &ast.BinaryExpr{
|
|
X: xnot,
|
|
Op: token.LAND,
|
|
Y: ynot,
|
|
}
|
|
return or, andnot
|
|
}
|
|
|
|
// if x represents a known old reflect type/value like *reflect.PtrType or reflect.ArrayOrSliceValue,
|
|
// reflectType returns the string form of that type.
|
|
func reflectType(x ast.Expr) string {
|
|
ptr, ok := x.(*ast.StarExpr)
|
|
if ok {
|
|
x = ptr.X
|
|
}
|
|
|
|
sel, ok := x.(*ast.SelectorExpr)
|
|
if !ok || !isName(sel.X, "reflect") {
|
|
return ""
|
|
}
|
|
|
|
var s = "reflect."
|
|
if ptr != nil {
|
|
s = "*reflect."
|
|
}
|
|
s += sel.Sel.Name
|
|
|
|
if reflectKind[s] != nil {
|
|
return s
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// reflectWarnTypecheckStmt warns about statements
|
|
// of the form x, y = z.(T) for any old reflect type T.
|
|
// The last pass should have gotten them all, and if it didn't,
|
|
// the next pass is going to turn them into x, y = z.
|
|
func reflectWarnTypecheckStmt(n interface{}) {
|
|
as, ok := n.(*ast.AssignStmt)
|
|
if !ok || len(as.Lhs) != 2 || len(as.Rhs) != 1 {
|
|
return
|
|
}
|
|
ta, ok := as.Rhs[0].(*ast.TypeAssertExpr)
|
|
if !ok || reflectType(ta.Type) == "" {
|
|
return
|
|
}
|
|
warn(n.(ast.Node).Pos(), "unfixed reflect type check")
|
|
}
|
|
|
|
// reflectFixAssert rewrites x.(T) to x for any old reflect type T.
|
|
func reflectFixAssert(n interface{}) bool {
|
|
ptr, ok := n.(*ast.Expr)
|
|
if ok {
|
|
ta, ok := (*ptr).(*ast.TypeAssertExpr)
|
|
if ok && reflectType(ta.Type) != "" {
|
|
*ptr = ta.X
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Tables describing the transformations.
|
|
|
|
// Description of old reflect API for partial type checking.
|
|
// We pretend the Elem method is on Type and Value instead
|
|
// of enumerating all the types it is actually on.
|
|
// Also, we pretend that ArrayType etc embeds Type for the
|
|
// purposes of describing the API. (In fact they embed commonType,
|
|
// which implements Type.)
|
|
var reflectTypeConfig = &TypeConfig{
|
|
Type: map[string]*Type{
|
|
"reflect.ArrayOrSliceType": &Type{Embed: []string{"reflect.Type"}},
|
|
"reflect.ArrayOrSliceValue": &Type{Embed: []string{"reflect.Value"}},
|
|
"reflect.ArrayType": &Type{Embed: []string{"reflect.Type"}},
|
|
"reflect.ArrayValue": &Type{Embed: []string{"reflect.Value"}},
|
|
"reflect.BoolType": &Type{Embed: []string{"reflect.Type"}},
|
|
"reflect.BoolValue": &Type{Embed: []string{"reflect.Value"}},
|
|
"reflect.ChanType": &Type{Embed: []string{"reflect.Type"}},
|
|
"reflect.ChanValue": &Type{
|
|
Method: map[string]string{
|
|
"Recv": "func() (reflect.Value, bool)",
|
|
"TryRecv": "func() (reflect.Value, bool)",
|
|
},
|
|
Embed: []string{"reflect.Value"},
|
|
},
|
|
"reflect.ComplexType": &Type{Embed: []string{"reflect.Type"}},
|
|
"reflect.ComplexValue": &Type{Embed: []string{"reflect.Value"}},
|
|
"reflect.FloatType": &Type{Embed: []string{"reflect.Type"}},
|
|
"reflect.FloatValue": &Type{Embed: []string{"reflect.Value"}},
|
|
"reflect.FuncType": &Type{
|
|
Method: map[string]string{
|
|
"In": "func(int) reflect.Type",
|
|
"Out": "func(int) reflect.Type",
|
|
},
|
|
Embed: []string{"reflect.Type"},
|
|
},
|
|
"reflect.FuncValue": &Type{
|
|
Method: map[string]string{
|
|
"Call": "func([]reflect.Value) []reflect.Value",
|
|
},
|
|
},
|
|
"reflect.IntType": &Type{Embed: []string{"reflect.Type"}},
|
|
"reflect.IntValue": &Type{Embed: []string{"reflect.Value"}},
|
|
"reflect.InterfaceType": &Type{Embed: []string{"reflect.Type"}},
|
|
"reflect.InterfaceValue": &Type{Embed: []string{"reflect.Value"}},
|
|
"reflect.MapType": &Type{
|
|
Method: map[string]string{
|
|
"Key": "func() reflect.Type",
|
|
},
|
|
Embed: []string{"reflect.Type"},
|
|
},
|
|
"reflect.MapValue": &Type{
|
|
Method: map[string]string{
|
|
"Keys": "func() []reflect.Value",
|
|
},
|
|
Embed: []string{"reflect.Value"},
|
|
},
|
|
"reflect.Method": &Type{
|
|
Field: map[string]string{
|
|
"Type": "*reflect.FuncType",
|
|
"Func": "*reflect.FuncValue",
|
|
},
|
|
},
|
|
"reflect.PtrType": &Type{Embed: []string{"reflect.Type"}},
|
|
"reflect.PtrValue": &Type{Embed: []string{"reflect.Value"}},
|
|
"reflect.SliceType": &Type{Embed: []string{"reflect.Type"}},
|
|
"reflect.SliceValue": &Type{
|
|
Method: map[string]string{
|
|
"Slice": "func(int, int) *reflect.SliceValue",
|
|
},
|
|
Embed: []string{"reflect.Value"},
|
|
},
|
|
"reflect.StringType": &Type{Embed: []string{"reflect.Type"}},
|
|
"reflect.StringValue": &Type{Embed: []string{"reflect.Value"}},
|
|
"reflect.StructField": &Type{
|
|
Field: map[string]string{
|
|
"Type": "reflect.Type",
|
|
},
|
|
},
|
|
"reflect.StructType": &Type{
|
|
Method: map[string]string{
|
|
"Field": "func() reflect.StructField",
|
|
"FieldByIndex": "func() reflect.StructField",
|
|
"FieldByName": "func() reflect.StructField,bool",
|
|
"FieldByNameFunc": "func() reflect.StructField,bool",
|
|
},
|
|
Embed: []string{"reflect.Type"},
|
|
},
|
|
"reflect.StructValue": &Type{
|
|
Method: map[string]string{
|
|
"Field": "func() reflect.Value",
|
|
"FieldByIndex": "func() reflect.Value",
|
|
"FieldByName": "func() reflect.Value",
|
|
"FieldByNameFunc": "func() reflect.Value",
|
|
},
|
|
Embed: []string{"reflect.Value"},
|
|
},
|
|
"reflect.Type": &Type{
|
|
Method: map[string]string{
|
|
"Elem": "func() reflect.Type",
|
|
"Method": "func() reflect.Method",
|
|
},
|
|
},
|
|
"reflect.UintType": &Type{Embed: []string{"reflect.Type"}},
|
|
"reflect.UintValue": &Type{Embed: []string{"reflect.Value"}},
|
|
"reflect.UnsafePointerType": &Type{Embed: []string{"reflect.Type"}},
|
|
"reflect.UnsafePointerValue": &Type{Embed: []string{"reflect.Value"}},
|
|
"reflect.Value": &Type{
|
|
Method: map[string]string{
|
|
"Addr": "func() *reflect.PtrValue",
|
|
"Elem": "func() reflect.Value",
|
|
"Method": "func() *reflect.FuncValue",
|
|
"SetValue": "func(reflect.Value)",
|
|
},
|
|
},
|
|
},
|
|
Func: map[string]string{
|
|
"reflect.Append": "*reflect.SliceValue",
|
|
"reflect.AppendSlice": "*reflect.SliceValue",
|
|
"reflect.Indirect": "reflect.Value",
|
|
"reflect.MakeSlice": "*reflect.SliceValue",
|
|
"reflect.MakeChan": "*reflect.ChanValue",
|
|
"reflect.MakeMap": "*reflect.MapValue",
|
|
"reflect.MakeZero": "reflect.Value",
|
|
"reflect.NewValue": "reflect.Value",
|
|
"reflect.PtrTo": "*reflect.PtrType",
|
|
"reflect.Typeof": "reflect.Type",
|
|
},
|
|
}
|
|
|
|
var reflectRewriteMethod = map[string]map[string]string{
|
|
// The type API didn't change much.
|
|
"*reflect.ChanType": {"Dir": "ChanDir"},
|
|
"*reflect.FuncType": {"DotDotDot": "IsVariadic"},
|
|
|
|
// The value API has longer names to disambiguate
|
|
// methods with different signatures.
|
|
"reflect.ArrayOrSliceValue": { // interface, not pointer
|
|
"Elem": "Index",
|
|
},
|
|
"*reflect.ArrayValue": {
|
|
"Elem": "Index",
|
|
},
|
|
"*reflect.BoolValue": {
|
|
"Get": "Bool",
|
|
"Set": "SetBool",
|
|
},
|
|
"*reflect.ChanValue": {
|
|
"Get": "Pointer",
|
|
},
|
|
"*reflect.ComplexValue": {
|
|
"Get": "Complex",
|
|
"Set": "SetComplex",
|
|
"Overflow": "OverflowComplex",
|
|
},
|
|
"*reflect.FloatValue": {
|
|
"Get": "Float",
|
|
"Set": "SetFloat",
|
|
"Overflow": "OverflowFloat",
|
|
},
|
|
"*reflect.FuncValue": {
|
|
"Get": "Pointer",
|
|
},
|
|
"*reflect.IntValue": {
|
|
"Get": "Int",
|
|
"Set": "SetInt",
|
|
"Overflow": "OverflowInt",
|
|
},
|
|
"*reflect.InterfaceValue": {
|
|
"Get": "InterfaceData",
|
|
},
|
|
"*reflect.MapValue": {
|
|
"Elem": "MapIndex",
|
|
"Get": "Pointer",
|
|
"Keys": "MapKeys",
|
|
"SetElem": "SetMapIndex",
|
|
},
|
|
"*reflect.PtrValue": {
|
|
"Get": "Pointer",
|
|
},
|
|
"*reflect.SliceValue": {
|
|
"Elem": "Index",
|
|
"Get": "Pointer",
|
|
},
|
|
"*reflect.StringValue": {
|
|
"Get": "String",
|
|
"Set": "SetString",
|
|
},
|
|
"*reflect.UintValue": {
|
|
"Get": "Uint",
|
|
"Set": "SetUint",
|
|
"Overflow": "OverflowUint",
|
|
},
|
|
"*reflect.UnsafePointerValue": {
|
|
"Get": "Pointer",
|
|
"Set": "SetPointer",
|
|
},
|
|
}
|
|
|
|
var reflectKind = map[string][]string{
|
|
"reflect.ArrayOrSliceType": {"Array", "Slice"}, // interface, not pointer
|
|
"*reflect.ArrayType": {"Array"},
|
|
"*reflect.BoolType": {"Bool"},
|
|
"*reflect.ChanType": {"Chan"},
|
|
"*reflect.ComplexType": {"Complex64", "Complex128"},
|
|
"*reflect.FloatType": {"Float32", "Float64"},
|
|
"*reflect.FuncType": {"Func"},
|
|
"*reflect.IntType": {"Int", "Int8", "Int16", "Int32", "Int64"},
|
|
"*reflect.InterfaceType": {"Interface"},
|
|
"*reflect.MapType": {"Map"},
|
|
"*reflect.PtrType": {"Ptr"},
|
|
"*reflect.SliceType": {"Slice"},
|
|
"*reflect.StringType": {"String"},
|
|
"*reflect.StructType": {"Struct"},
|
|
"*reflect.UintType": {"Uint", "Uint8", "Uint16", "Uint32", "Uint64", "Uintptr"},
|
|
"*reflect.UnsafePointerType": {"UnsafePointer"},
|
|
|
|
"reflect.ArrayOrSliceValue": {"Array", "Slice"}, // interface, not pointer
|
|
"*reflect.ArrayValue": {"Array"},
|
|
"*reflect.BoolValue": {"Bool"},
|
|
"*reflect.ChanValue": {"Chan"},
|
|
"*reflect.ComplexValue": {"Complex64", "Complex128"},
|
|
"*reflect.FloatValue": {"Float32", "Float64"},
|
|
"*reflect.FuncValue": {"Func"},
|
|
"*reflect.IntValue": {"Int", "Int8", "Int16", "Int32", "Int64"},
|
|
"*reflect.InterfaceValue": {"Interface"},
|
|
"*reflect.MapValue": {"Map"},
|
|
"*reflect.PtrValue": {"Ptr"},
|
|
"*reflect.SliceValue": {"Slice"},
|
|
"*reflect.StringValue": {"String"},
|
|
"*reflect.StructValue": {"Struct"},
|
|
"*reflect.UintValue": {"Uint", "Uint8", "Uint16", "Uint32", "Uint64", "Uintptr"},
|
|
"*reflect.UnsafePointerValue": {"UnsafePointer"},
|
|
}
|
|
|
|
var isReflectValue = map[string]bool{
|
|
"reflect.ArrayOrSliceValue": true, // interface, not pointer
|
|
"*reflect.ArrayValue": true,
|
|
"*reflect.BoolValue": true,
|
|
"*reflect.ChanValue": true,
|
|
"*reflect.ComplexValue": true,
|
|
"*reflect.FloatValue": true,
|
|
"*reflect.FuncValue": true,
|
|
"*reflect.IntValue": true,
|
|
"*reflect.InterfaceValue": true,
|
|
"*reflect.MapValue": true,
|
|
"*reflect.PtrValue": true,
|
|
"*reflect.SliceValue": true,
|
|
"*reflect.StringValue": true,
|
|
"*reflect.StructValue": true,
|
|
"*reflect.UintValue": true,
|
|
"*reflect.UnsafePointerValue": true,
|
|
"reflect.Value": true, // interface, not pointer
|
|
}
|