Skip to content

Commit a69395e

Browse files
committed
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 <[email protected]> Reviewed-by: Michael Knyszek <[email protected]> Reviewed-by: Michael Matloob <[email protected]>
1 parent cbdad4f commit a69395e

File tree

1 file changed

+73
-0
lines changed

1 file changed

+73
-0
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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+
}

0 commit comments

Comments
 (0)