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