mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
runtime/_mkmalloc: add a copy of cloneNode
cloneNode is defined in golang.org/x/tools/internal/astutil. Make a copy of it so we can easily clone AST nodes. Change-Id: I6a6a6964132e663e64faa00fa6037cf6e8d4cbc6 Reviewed-on: https://go-review.googlesource.com/c/go/+/703396 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Knyszek <mknyszek@google.com> Reviewed-by: Michael Matloob <matloob@google.com>
This commit is contained in:
parent
cbdad4fc3c
commit
a69395eab2
1 changed files with 73 additions and 0 deletions
73
src/runtime/_mkmalloc/astutil/clone.go
Normal file
73
src/runtime/_mkmalloc/astutil/clone.go
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// This file is a copy of golang.org/x/tools/internal/astutil/clone.go
|
||||||
|
|
||||||
|
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.Pointer:
|
||||||
|
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)
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue