| // Copyright 2012 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 main | |
| import ( | |
| "fmt" | |
| "go/ast" | |
| "log" | |
| "reflect" | |
| ) | |
| const debugClone = false | |
| // 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)) | |
| } | |
| func cloneExpr(x ast.Expr) ast.Expr { | |
| if x == nil { | |
| return nil | |
| } | |
| return clone(x).(ast.Expr) | |
| } | |
| func cloneExprs(x []ast.Expr) []ast.Expr { | |
| if x == nil { | |
| return nil | |
| } | |
| o := make([]ast.Expr, len(x)) | |
| for i, x := range x { | |
| o[i] = cloneExpr(x) | |
| } | |
| return o | |
| } |