mirror of
https://github.com/tailscale/tailscale.git
synced 2024-12-01 14:05:39 +00:00
util/codegen: add ContainsPointers
And use it in cmd/cloner. Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
This commit is contained in:
parent
d5a0a4297e
commit
3cd85c0ca6
@ -156,7 +156,7 @@ func gen(buf *bytes.Buffer, imports map[string]struct{}, typ *types.Named, thisP
|
|||||||
for i := 0; i < t.NumFields(); i++ {
|
for i := 0; i < t.NumFields(); i++ {
|
||||||
fname := t.Field(i).Name()
|
fname := t.Field(i).Name()
|
||||||
ft := t.Field(i).Type()
|
ft := t.Field(i).Type()
|
||||||
if !containsPointers(ft) {
|
if !codegen.ContainsPointers(ft) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if named, _ := ft.(*types.Named); named != nil && !hasBasicUnderlying(ft) {
|
if named, _ := ft.(*types.Named); named != nil && !hasBasicUnderlying(ft) {
|
||||||
@ -165,7 +165,7 @@ func gen(buf *bytes.Buffer, imports map[string]struct{}, typ *types.Named, thisP
|
|||||||
}
|
}
|
||||||
switch ft := ft.Underlying().(type) {
|
switch ft := ft.Underlying().(type) {
|
||||||
case *types.Slice:
|
case *types.Slice:
|
||||||
if containsPointers(ft.Elem()) {
|
if codegen.ContainsPointers(ft.Elem()) {
|
||||||
n := importedName(ft.Elem())
|
n := importedName(ft.Elem())
|
||||||
writef("dst.%s = make([]%s, len(src.%s))", fname, n, fname)
|
writef("dst.%s = make([]%s, len(src.%s))", fname, n, fname)
|
||||||
writef("for i := range dst.%s {", fname)
|
writef("for i := range dst.%s {", fname)
|
||||||
@ -179,7 +179,7 @@ func gen(buf *bytes.Buffer, imports map[string]struct{}, typ *types.Named, thisP
|
|||||||
writef("dst.%s = append(src.%s[:0:0], src.%s...)", fname, fname, fname)
|
writef("dst.%s = append(src.%s[:0:0], src.%s...)", fname, fname, fname)
|
||||||
}
|
}
|
||||||
case *types.Pointer:
|
case *types.Pointer:
|
||||||
if named, _ := ft.Elem().(*types.Named); named != nil && containsPointers(ft.Elem()) {
|
if named, _ := ft.Elem().(*types.Named); named != nil && codegen.ContainsPointers(ft.Elem()) {
|
||||||
writef("dst.%s = src.%s.Clone()", fname, fname)
|
writef("dst.%s = src.%s.Clone()", fname, fname)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -187,7 +187,7 @@ func gen(buf *bytes.Buffer, imports map[string]struct{}, typ *types.Named, thisP
|
|||||||
writef("if dst.%s != nil {", fname)
|
writef("if dst.%s != nil {", fname)
|
||||||
writef("\tdst.%s = new(%s)", fname, n)
|
writef("\tdst.%s = new(%s)", fname, n)
|
||||||
writef("\t*dst.%s = *src.%s", fname, fname)
|
writef("\t*dst.%s = *src.%s", fname, fname)
|
||||||
if containsPointers(ft.Elem()) {
|
if codegen.ContainsPointers(ft.Elem()) {
|
||||||
writef("\t" + `panic("TODO pointers in pointers")`)
|
writef("\t" + `panic("TODO pointers in pointers")`)
|
||||||
}
|
}
|
||||||
writef("}")
|
writef("}")
|
||||||
@ -201,7 +201,7 @@ func gen(buf *bytes.Buffer, imports map[string]struct{}, typ *types.Named, thisP
|
|||||||
// the key is always copied.
|
// the key is always copied.
|
||||||
writef("\t\tdst.%s[k] = append([]%s{}, src.%s[k]...)", fname, n, fname)
|
writef("\t\tdst.%s[k] = append([]%s{}, src.%s[k]...)", fname, n, fname)
|
||||||
writef("\t}")
|
writef("\t}")
|
||||||
} else if containsPointers(ft.Elem()) {
|
} else if codegen.ContainsPointers(ft.Elem()) {
|
||||||
writef("\tfor k, v := range src.%s {", fname)
|
writef("\tfor k, v := range src.%s {", fname)
|
||||||
writef("\t\tdst.%s[k] = v.Clone()", fname)
|
writef("\t\tdst.%s[k] = v.Clone()", fname)
|
||||||
writef("\t}")
|
writef("\t}")
|
||||||
@ -229,34 +229,3 @@ func hasBasicUnderlying(typ types.Type) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func containsPointers(typ types.Type) bool {
|
|
||||||
switch typ.String() {
|
|
||||||
case "time.Time":
|
|
||||||
// time.Time contains a pointer that does not need copying
|
|
||||||
return false
|
|
||||||
case "inet.af/netaddr.IP":
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
switch ft := typ.Underlying().(type) {
|
|
||||||
case *types.Array:
|
|
||||||
return containsPointers(ft.Elem())
|
|
||||||
case *types.Chan:
|
|
||||||
return true
|
|
||||||
case *types.Interface:
|
|
||||||
return true // a little too broad
|
|
||||||
case *types.Map:
|
|
||||||
return true
|
|
||||||
case *types.Pointer:
|
|
||||||
return true
|
|
||||||
case *types.Slice:
|
|
||||||
return true
|
|
||||||
case *types.Struct:
|
|
||||||
for i := 0; i < ft.NumFields(); i++ {
|
|
||||||
if containsPointers(ft.Field(i).Type()) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
@ -109,3 +109,38 @@ func importedName(t types.Type, thisPkg *types.Package) (qualifiedName, importPk
|
|||||||
}
|
}
|
||||||
return types.TypeString(t, qual), importPkg
|
return types.TypeString(t, qual), importPkg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ContainsPointers reports whether typ contains any pointers,
|
||||||
|
// either explicitly or implicitly.
|
||||||
|
// It has special handling for some types that contain pointers
|
||||||
|
// that we know are free from memory aliasing/mutation concerns.
|
||||||
|
func ContainsPointers(typ types.Type) bool {
|
||||||
|
switch typ.String() {
|
||||||
|
case "time.Time":
|
||||||
|
// time.Time contains a pointer that does not need copying
|
||||||
|
return false
|
||||||
|
case "inet.af/netaddr.IP":
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch ft := typ.Underlying().(type) {
|
||||||
|
case *types.Array:
|
||||||
|
return ContainsPointers(ft.Elem())
|
||||||
|
case *types.Chan:
|
||||||
|
return true
|
||||||
|
case *types.Interface:
|
||||||
|
return true // a little too broad
|
||||||
|
case *types.Map:
|
||||||
|
return true
|
||||||
|
case *types.Pointer:
|
||||||
|
return true
|
||||||
|
case *types.Slice:
|
||||||
|
return true
|
||||||
|
case *types.Struct:
|
||||||
|
for i := 0; i < ft.NumFields(); i++ {
|
||||||
|
if ContainsPointers(ft.Field(i).Type()) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user