| | |
| | |
| | |
| |
|
| | |
| |
|
| | package astutil |
| |
|
| | import ( |
| | "go/ast" |
| | "reflect" |
| | ) |
| |
|
| | |
| | |
| | func CloneNode[T ast.Node](n T) T { |
| | return cloneNode(n).(T) |
| | } |
| |
|
| | func cloneNode(n ast.Node) ast.Node { |
| | var clone func(x reflect.Value) reflect.Value |
| | set := func(dst, src reflect.Value) { |
| | src = clone(src) |
| | if src.IsValid() { |
| | dst.Set(src) |
| | } |
| | } |
| | clone = func(x reflect.Value) reflect.Value { |
| | switch x.Kind() { |
| | case reflect.Pointer: |
| | if x.IsNil() { |
| | return x |
| | } |
| | |
| | switch x.Interface().(type) { |
| | case *ast.Object, *ast.Scope: |
| | return reflect.Zero(x.Type()) |
| | } |
| | y := reflect.New(x.Type().Elem()) |
| | set(y.Elem(), x.Elem()) |
| | return y |
| |
|
| | case reflect.Struct: |
| | y := reflect.New(x.Type()).Elem() |
| | for i := 0; i < x.Type().NumField(); i++ { |
| | set(y.Field(i), x.Field(i)) |
| | } |
| | return y |
| |
|
| | case reflect.Slice: |
| | if x.IsNil() { |
| | return x |
| | } |
| | y := reflect.MakeSlice(x.Type(), x.Len(), x.Cap()) |
| | for i := 0; i < x.Len(); i++ { |
| | set(y.Index(i), x.Index(i)) |
| | } |
| | return y |
| |
|
| | case reflect.Interface: |
| | y := reflect.New(x.Type()).Elem() |
| | set(y, x.Elem()) |
| | return y |
| |
|
| | case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.UnsafePointer: |
| | panic(x) |
| |
|
| | default: |
| | return x |
| | } |
| | } |
| | return clone(reflect.ValueOf(n)).Interface().(ast.Node) |
| | } |
| |
|