Source file src/runtime/_mkmalloc/astutil/clone.go

     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  // This file is a copy of golang.org/x/tools/internal/astutil/clone.go
     6  
     7  package astutil
     8  
     9  import (
    10  	"go/ast"
    11  	"reflect"
    12  )
    13  
    14  // CloneNode returns a deep copy of a Node.
    15  // It omits pointers to ast.{Scope,Object} variables.
    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  			// Skip fields of types potentially involved in cycles.
    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) // unreachable in AST
    67  
    68  		default:
    69  			return x // bool, string, number
    70  		}
    71  	}
    72  	return clone(reflect.ValueOf(n)).Interface().(ast.Node)
    73  }
    74  

View as plain text