// TODO(bradfitz): delete this function (and whole file) once // http://golang.org/issue/4380 is fixed. func clone(i interface{}) (cloned interface{}) { if debugClone { defer func() { if !reflect.DeepEqual(i, cloned) { log.Printf("cloned %T doesn't match: in=%#v out=%#v", i, i, cloned) } }() } switch v := i.(type) { case nil: return nil case *ast.File: o := &ast.File{ Doc: v.Doc, // shallow Package: v.Package, Comments: v.Comments, // shallow Name: v.Name, Scope: v.Scope, } for _, x := range v.Decls { o.Decls = append(o.Decls, clone(x).(ast.Decl)) } for _, x := range v.Imports { o.Imports = append(o.Imports, clone(x).(*ast.ImportSpec)) } for _, x := range v.Unresolved { o.Unresolved = append(o.Unresolved, x) } return o case *ast.GenDecl: o := new(ast.GenDecl) *o = *v o.Specs = nil for _, x := range v.Specs { o.Specs = append(o.Specs, clone(x).(ast.Spec)) } return o case *ast.TypeSpec: o := new(ast.TypeSpec) *o = *v o.Type = cloneExpr(v.Type) return o case *ast.InterfaceType: o := new(ast.InterfaceType) *o = *v o.Methods = clone(v.Methods).(*ast.FieldList) return o case *ast.FieldList: if v == nil { return v } o := new(ast.FieldList) *o = *v o.List = nil for _, x := range v.List { o.List = append(o.List, clone(x).(*ast.Field)) } return o case *ast.Field: o := &ast.Field{ Doc: v.Doc, // shallow Type: cloneExpr(v.Type), Tag: clone(v.Tag).(*ast.BasicLit), Comment: v.Comment, // shallow } for _, x := range v.Names { o.Names = append(o.Names, clone(x).(*ast.Ident)) } return o case *ast.FuncType: if v == nil { return v } return &ast.FuncType{ Func: v.Func, Params: clone(v.Params).(*ast.FieldList), Results: clone(v.Results).(*ast.FieldList), } case *ast.FuncDecl: if v == nil { return v } return &ast.FuncDecl{ Recv: clone(v.Recv).(*ast.FieldList), Name: v.Name, Type: clone(v.Type).(*ast.FuncType), Body: v.Body, // shallow } case *ast.ValueSpec: if v == nil { return v } o := &ast.ValueSpec{ Type: cloneExpr(v.Type), } for _, x := range v.Names { o.Names = append(o.Names, x) } for _, x := range v.Values { o.Values = append(o.Values, cloneExpr(x)) } return o case *ast.CallExpr: if v == nil { return v } o := &ast.CallExpr{} *o = *v o.Args = cloneExprs(v.Args) o.Fun = cloneExpr(v.Fun) return o case *ast.SelectorExpr: if v == nil { return nil } return &ast.SelectorExpr{ X: cloneExpr(v.X), Sel: v.Sel, } case *ast.ArrayType: return &ast.ArrayType{ Lbrack: v.Lbrack, Len: cloneExpr(v.Len), Elt: cloneExpr(v.Elt), } case *ast.StructType: return &ast.StructType{ Struct: v.Struct, Fields: clone(v.Fields).(*ast.FieldList), Incomplete: v.Incomplete, } case *ast.StarExpr: return &ast.StarExpr{ Star: v.Star, X: cloneExpr(v.X), } case *ast.CompositeLit: return &ast.CompositeLit{ Type: cloneExpr(v.Type), Lbrace: v.Lbrace, Elts: cloneExprs(v.Elts), Rbrace: v.Rbrace, } case *ast.UnaryExpr: return &ast.UnaryExpr{ OpPos: v.OpPos, Op: v.Op, X: cloneExpr(v.X), } case *ast.BinaryExpr: return &ast.BinaryExpr{ OpPos: v.OpPos, Op: v.Op, X: cloneExpr(v.X), Y: cloneExpr(v.Y), } case *ast.Ellipsis: return &ast.Ellipsis{ Ellipsis: v.Ellipsis, Elt: cloneExpr(v.Elt), } case *ast.KeyValueExpr: return &ast.KeyValueExpr{ Key: cloneExpr(v.Key), Colon: v.Colon, Value: cloneExpr(v.Value), } case *ast.FuncLit: return &ast.FuncLit{ Type: clone(v.Type).(*ast.FuncType), Body: v.Body, // shallow } case *ast.MapType: return &ast.MapType{ Map: v.Map, Key: cloneExpr(v.Key), Value: cloneExpr(v.Value), } case *ast.ParenExpr: return &ast.ParenExpr{ Lparen: v.Lparen, X: cloneExpr(v.X), Rparen: v.Rparen, } case *ast.Ident, *ast.BasicLit: return v case *ast.ImportSpec: return &ast.ImportSpec{ Doc: v.Doc, // shallow Name: v.Name, Path: clone(v.Path).(*ast.BasicLit), Comment: v.Comment, // shallow EndPos: v.EndPos, } case *ast.ChanType: return &ast.ChanType{ Begin: v.Begin, Arrow: v.Arrow, Dir: v.Dir, Value: cloneExpr(v.Value), } case *ast.TypeAssertExpr: return &ast.TypeAssertExpr{ X: cloneExpr(v.X), Type: cloneExpr(v.Type), } case *ast.IndexExpr: return &ast.IndexExpr{ X: cloneExpr(v.X), Index: cloneExpr(v.Index), Lbrack: v.Lbrack, Rbrack: v.Rbrack, } } panic(fmt.Sprintf("Uncloneable type %T", i)) }