1
2
3
4
5
6
7 package astutil
8
9 import (
10 "go/ast"
11 "reflect"
12 )
13
14
15
16 func CloneNode[T ast.Node](n T) T {
17 return cloneNode(n).(T)
18 }
19
20 func cloneNode(n ast.Node) ast.Node {
21 var clone func(x reflect.Value) reflect.Value
22 set := func(dst, src reflect.Value) {
23 src = clone(src)
24 if src.IsValid() {
25 dst.Set(src)
26 }
27 }
28 clone = func(x reflect.Value) reflect.Value {
29 switch x.Kind() {
30 case reflect.Pointer:
31 if x.IsNil() {
32 return x
33 }
34
35 switch x.Interface().(type) {
36 case *ast.Object, *ast.Scope:
37 return reflect.Zero(x.Type())
38 }
39 y := reflect.New(x.Type().Elem())
40 set(y.Elem(), x.Elem())
41 return y
42
43 case reflect.Struct:
44 y := reflect.New(x.Type()).Elem()
45 for i := 0; i < x.Type().NumField(); i++ {
46 set(y.Field(i), x.Field(i))
47 }
48 return y
49
50 case reflect.Slice:
51 if x.IsNil() {
52 return x
53 }
54 y := reflect.MakeSlice(x.Type(), x.Len(), x.Cap())
55 for i := 0; i < x.Len(); i++ {
56 set(y.Index(i), x.Index(i))
57 }
58 return y
59
60 case reflect.Interface:
61 y := reflect.New(x.Type()).Elem()
62 set(y, x.Elem())
63 return y
64
65 case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.UnsafePointer:
66 panic(x)
67
68 default:
69 return x
70 }
71 }
72 return clone(reflect.ValueOf(n)).Interface().(ast.Node)
73 }
74
View as plain text