summaryrefslogtreecommitdiff
path: root/src/cmd/gofix/reflect.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/gofix/reflect.go')
-rw-r--r--src/cmd/gofix/reflect.go843
1 files changed, 843 insertions, 0 deletions
diff --git a/src/cmd/gofix/reflect.go b/src/cmd/gofix/reflect.go
new file mode 100644
index 000000000..74ddb398f
--- /dev/null
+++ b/src/cmd/gofix/reflect.go
@@ -0,0 +1,843 @@
+// 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
+`,
+}
+
+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
+ })
+
+ 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
+}