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  }