blob: 180215f4b9c2863e6816b815f1882d1fa09a6f6c [file] [log] [blame]
// 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
}