From 081be3e96b5c3983e0c1818b31730aa977a811f1 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 16 Sep 2021 16:00:34 -0700 Subject: [PATCH] cmd/cloner: simplify code Change from a single-case type switch to a type assertion with an early return. That exposes that the name arg to gen is unneeded. Signed-off-by: Josh Bleecher Snyder --- cmd/cloner/cloner.go | 156 ++++++++++++++++++++++--------------------- 1 file changed, 79 insertions(+), 77 deletions(-) diff --git a/cmd/cloner/cloner.go b/cmd/cloner/cloner.go index 19f20a771..61cf01331 100644 --- a/cmd/cloner/cloner.go +++ b/cmd/cloner/cloner.go @@ -85,7 +85,7 @@ func main() { continue } pkg := typeNameObj.Pkg() - gen(buf, imports, typeName, typ, pkg) + gen(buf, imports, typ, pkg) found = true } } @@ -150,7 +150,7 @@ package %s ` -func gen(buf *bytes.Buffer, imports map[string]struct{}, name string, typ *types.Named, thisPkg *types.Package) { +func gen(buf *bytes.Buffer, imports map[string]struct{}, typ *types.Named, thisPkg *types.Package) { pkgQual := func(pkg *types.Package) string { if thisPkg == pkg { return "" @@ -162,89 +162,91 @@ func gen(buf *bytes.Buffer, imports map[string]struct{}, name string, typ *types return types.TypeString(t, pkgQual) } - switch t := typ.Underlying().(type) { - case *types.Struct: - name := typ.Obj().Name() - fmt.Fprintf(buf, "// Clone makes a deep copy of %s.\n", name) - fmt.Fprintf(buf, "// The result aliases no memory with the original.\n") - fmt.Fprintf(buf, "func (src *%s) Clone() *%s {\n", name, name) - writef := func(format string, args ...interface{}) { - fmt.Fprintf(buf, "\t"+format+"\n", args...) + t, ok := typ.Underlying().(*types.Struct) + if !ok { + return + } + + name := typ.Obj().Name() + fmt.Fprintf(buf, "// Clone makes a deep copy of %s.\n", name) + fmt.Fprintf(buf, "// The result aliases no memory with the original.\n") + fmt.Fprintf(buf, "func (src *%s) Clone() *%s {\n", name, name) + writef := func(format string, args ...interface{}) { + fmt.Fprintf(buf, "\t"+format+"\n", args...) + } + writef("if src == nil {") + writef("\treturn nil") + writef("}") + writef("dst := new(%s)", name) + writef("*dst = *src") + for i := 0; i < t.NumFields(); i++ { + fname := t.Field(i).Name() + ft := t.Field(i).Type() + if !containsPointers(ft) { + continue } - writef("if src == nil {") - writef("\treturn nil") - writef("}") - writef("dst := new(%s)", name) - writef("*dst = *src") - for i := 0; i < t.NumFields(); i++ { - fname := t.Field(i).Name() - ft := t.Field(i).Type() - if !containsPointers(ft) { - continue - } - if named, _ := ft.(*types.Named); named != nil && !hasBasicUnderlying(ft) { - writef("dst.%s = *src.%s.Clone()", fname, fname) - continue - } - switch ft := ft.Underlying().(type) { - case *types.Slice: - if containsPointers(ft.Elem()) { - n := importedName(ft.Elem()) - writef("dst.%s = make([]%s, len(src.%s))", fname, n, fname) - writef("for i := range dst.%s {", fname) - if _, isPtr := ft.Elem().(*types.Pointer); isPtr { - writef("\tdst.%s[i] = src.%s[i].Clone()", fname, fname) - } else { - writef("\tdst.%s[i] = *src.%s[i].Clone()", fname, fname) - } - writef("}") - } else { - writef("dst.%s = append(src.%s[:0:0], src.%s...)", fname, fname, fname) - } - case *types.Pointer: - if named, _ := ft.Elem().(*types.Named); named != nil && containsPointers(ft.Elem()) { - writef("dst.%s = src.%s.Clone()", fname, fname) - continue - } + if named, _ := ft.(*types.Named); named != nil && !hasBasicUnderlying(ft) { + writef("dst.%s = *src.%s.Clone()", fname, fname) + continue + } + switch ft := ft.Underlying().(type) { + case *types.Slice: + if containsPointers(ft.Elem()) { n := importedName(ft.Elem()) - writef("if dst.%s != nil {", fname) - writef("\tdst.%s = new(%s)", fname, n) - writef("\t*dst.%s = *src.%s", fname, fname) - if containsPointers(ft.Elem()) { - writef("\t" + `panic("TODO pointers in pointers")`) - } - writef("}") - case *types.Map: - writef("if dst.%s != nil {", fname) - writef("\tdst.%s = map[%s]%s{}", fname, importedName(ft.Key()), importedName(ft.Elem())) - if sliceType, isSlice := ft.Elem().(*types.Slice); isSlice { - n := importedName(sliceType.Elem()) - writef("\tfor k := range src.%s {", fname) - // use zero-length slice instead of nil to ensure - // the key is always copied. - writef("\t\tdst.%s[k] = append([]%s{}, src.%s[k]...)", fname, n, fname) - writef("\t}") - } else if containsPointers(ft.Elem()) { - writef("\tfor k, v := range src.%s {", fname) - writef("\t\tdst.%s[k] = v.Clone()", fname) - writef("\t}") + writef("dst.%s = make([]%s, len(src.%s))", fname, n, fname) + writef("for i := range dst.%s {", fname) + if _, isPtr := ft.Elem().(*types.Pointer); isPtr { + writef("\tdst.%s[i] = src.%s[i].Clone()", fname, fname) } else { - writef("\tfor k, v := range src.%s {", fname) - writef("\t\tdst.%s[k] = v", fname) - writef("\t}") + writef("\tdst.%s[i] = *src.%s[i].Clone()", fname, fname) } writef("}") - case *types.Struct: - writef(`panic("TODO struct %s")`, fname) - default: - writef(`panic(fmt.Sprintf("TODO: %T", ft))`) + } else { + writef("dst.%s = append(src.%s[:0:0], src.%s...)", fname, fname, fname) } + case *types.Pointer: + if named, _ := ft.Elem().(*types.Named); named != nil && containsPointers(ft.Elem()) { + writef("dst.%s = src.%s.Clone()", fname, fname) + continue + } + n := importedName(ft.Elem()) + writef("if dst.%s != nil {", fname) + writef("\tdst.%s = new(%s)", fname, n) + writef("\t*dst.%s = *src.%s", fname, fname) + if containsPointers(ft.Elem()) { + writef("\t" + `panic("TODO pointers in pointers")`) + } + writef("}") + case *types.Map: + writef("if dst.%s != nil {", fname) + writef("\tdst.%s = map[%s]%s{}", fname, importedName(ft.Key()), importedName(ft.Elem())) + if sliceType, isSlice := ft.Elem().(*types.Slice); isSlice { + n := importedName(sliceType.Elem()) + writef("\tfor k := range src.%s {", fname) + // use zero-length slice instead of nil to ensure + // the key is always copied. + writef("\t\tdst.%s[k] = append([]%s{}, src.%s[k]...)", fname, n, fname) + writef("\t}") + } else if containsPointers(ft.Elem()) { + writef("\tfor k, v := range src.%s {", fname) + writef("\t\tdst.%s[k] = v.Clone()", fname) + writef("\t}") + } else { + writef("\tfor k, v := range src.%s {", fname) + writef("\t\tdst.%s[k] = v", fname) + writef("\t}") + } + writef("}") + case *types.Struct: + writef(`panic("TODO struct %s")`, fname) + default: + writef(`panic(fmt.Sprintf("TODO: %T", ft))`) } - writef("return dst") - fmt.Fprintf(buf, "}\n\n") - - buf.Write(codegen.AssertStructUnchanged(t, name, "Clone", thisPkg, imports)) } + writef("return dst") + fmt.Fprintf(buf, "}\n\n") + + buf.Write(codegen.AssertStructUnchanged(t, name, "Clone", thisPkg, imports)) } func hasBasicUnderlying(typ types.Type) bool {