aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/_mkmalloc
diff options
context:
space:
mode:
authorMichael Matloob <matloob@golang.org>2025-03-17 11:45:52 -0400
committerMichael Matloob <matloob@google.com>2025-09-16 13:13:54 -0700
commita69395eab2a1f704a549d15260c896d01fc9ab34 (patch)
treed9a02ee6fa4430c1a6cba49216e7f5918795fbd6 /src/runtime/_mkmalloc
parentcbdad4fc3cecbdfcee4e9d30df04916a151bfc16 (diff)
downloadgo-a69395eab2a1f704a549d15260c896d01fc9ab34.tar.xz
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>
Diffstat (limited to 'src/runtime/_mkmalloc')
-rw-r--r--src/runtime/_mkmalloc/astutil/clone.go73
1 files changed, 73 insertions, 0 deletions
diff --git a/src/runtime/_mkmalloc/astutil/clone.go b/src/runtime/_mkmalloc/astutil/clone.go
new file mode 100644
index 0000000000..16ea7163ca
--- /dev/null
+++ b/src/runtime/_mkmalloc/astutil/clone.go
@@ -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)
+}