|  | // Copyright 2023 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 astutil | 
|  |  | 
|  | import ( | 
|  | "go/ast" | 
|  | "reflect" | 
|  | ) | 
|  |  | 
|  | // CloneNode returns a deep copy of a Node. | 
|  | // It omits pointers to ast.{Scope,Object} variables. | 
|  | 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.Ptr: | 
|  | if x.IsNil() { | 
|  | return x | 
|  | } | 
|  | // Skip fields of types potentially involved in cycles. | 
|  | 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) // unreachable in AST | 
|  |  | 
|  | default: | 
|  | return x // bool, string, number | 
|  | } | 
|  | } | 
|  | return clone(reflect.ValueOf(n)).Interface().(ast.Node) | 
|  | } |