golang.org/x/tools@v0.21.1-0.20240520172518-788d39e776b1/internal/astutil/clone.go (about) 1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package astutil 6 7 import ( 8 "go/ast" 9 "reflect" 10 ) 11 12 // CloneNode returns a deep copy of a Node. 13 // It omits pointers to ast.{Scope,Object} variables. 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 // Skip fields of types potentially involved in cycles. 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) // unreachable in AST 65 66 default: 67 return x // bool, string, number 68 } 69 } 70 return clone(reflect.ValueOf(n)).Interface().(ast.Node) 71 }