diff options
| author | Michael Matloob <matloob@golang.org> | 2025-03-17 11:45:52 -0400 |
|---|---|---|
| committer | Michael Matloob <matloob@google.com> | 2025-09-16 13:13:54 -0700 |
| commit | a69395eab2a1f704a549d15260c896d01fc9ab34 (patch) | |
| tree | d9a02ee6fa4430c1a6cba49216e7f5918795fbd6 /src/runtime/_mkmalloc | |
| parent | cbdad4fc3cecbdfcee4e9d30df04916a151bfc16 (diff) | |
| download | go-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.go | 73 |
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) +} |
