src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

clone.go (1609B)


      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.Pointer:
     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 }