|
|
|
@ -129,10 +129,6 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
|
|
|
|
|
inputs := sets.NewString(context.Inputs...)
|
|
|
|
|
packages := generator.Packages{}
|
|
|
|
|
header := append([]byte(fmt.Sprintf("// +build !%s\n\n", arguments.GeneratedBuildTag)), boilerplate...)
|
|
|
|
|
header = append(header, []byte(`
|
|
|
|
|
// This file was autogenerated by deepcopy-gen. Do not edit it manually!
|
|
|
|
|
|
|
|
|
|
`)...)
|
|
|
|
|
|
|
|
|
|
boundingDirs := []string{}
|
|
|
|
|
if customArgs, ok := arguments.CustomArgs.(*CustomArgs); ok {
|
|
|
|
@ -286,27 +282,99 @@ func (g *genDeepCopy) copyableAndInBounds(t *types.Type) bool {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// hasDeepCopyMethod returns true if an appropriate DeepCopy() method is
|
|
|
|
|
// defined for the given type. This allows more efficient deep copy
|
|
|
|
|
// deepCopyMethod returns the signature of a DeepCopy() method, nil or an error
|
|
|
|
|
// if the type does not match. This allows more efficient deep copy
|
|
|
|
|
// implementations to be defined by the type's author. The correct signature
|
|
|
|
|
// for a type T is:
|
|
|
|
|
// func (t T) DeepCopy() T
|
|
|
|
|
// or:
|
|
|
|
|
// func (t *T) DeepCopy() T
|
|
|
|
|
func hasDeepCopyMethod(t *types.Type) bool {
|
|
|
|
|
for mn, mt := range t.Methods {
|
|
|
|
|
if mn != "DeepCopy" {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if len(mt.Signature.Parameters) != 0 {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if len(mt.Signature.Results) != 1 || mt.Signature.Results[0].Name != t.Name {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
// func (t *T) DeepCopy() *T
|
|
|
|
|
func deepCopyMethod(t *types.Type) (*types.Signature, error) {
|
|
|
|
|
f, found := t.Methods["DeepCopy"]
|
|
|
|
|
if !found {
|
|
|
|
|
return nil, nil
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
if len(f.Signature.Parameters) != 0 {
|
|
|
|
|
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected no parameters", t)
|
|
|
|
|
}
|
|
|
|
|
if len(f.Signature.Results) != 1 {
|
|
|
|
|
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected exactly one result", t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ptrResult := f.Signature.Results[0].Kind == types.Pointer && f.Signature.Results[0].Elem.Name == t.Name
|
|
|
|
|
nonPtrResult := f.Signature.Results[0].Name == t.Name
|
|
|
|
|
|
|
|
|
|
if !ptrResult && !nonPtrResult {
|
|
|
|
|
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected to return %s or *%s", t, t.Name.Name, t.Name.Name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ptrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Kind == types.Pointer && f.Signature.Receiver.Elem.Name == t.Name
|
|
|
|
|
nonPtrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Name == t.Name
|
|
|
|
|
|
|
|
|
|
if ptrRcvr && !ptrResult {
|
|
|
|
|
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected a *%s result for a *%s receiver", t, t.Name.Name, t.Name.Name)
|
|
|
|
|
}
|
|
|
|
|
if nonPtrRcvr && !nonPtrResult {
|
|
|
|
|
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected a %s result for a %s receiver", t, t.Name.Name, t.Name.Name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return f.Signature, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// deepCopyMethodOrDie returns the signatrue of a DeepCopy method, nil or calls glog.Fatalf
|
|
|
|
|
// if the type does not match.
|
|
|
|
|
func deepCopyMethodOrDie(t *types.Type) *types.Signature {
|
|
|
|
|
ret, err := deepCopyMethod(t)
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
return ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// deepCopyIntoMethod returns the signature of a DeepCopyInto() method, nil or an error
|
|
|
|
|
// if the type is wrong. DeepCopyInto allows more efficient deep copy
|
|
|
|
|
// implementations to be defined by the type's author. The correct signature
|
|
|
|
|
// for a type T is:
|
|
|
|
|
// func (t T) DeepCopyInto(t *T)
|
|
|
|
|
// or:
|
|
|
|
|
// func (t *T) DeepCopyInto(t *T)
|
|
|
|
|
func deepCopyIntoMethod(t *types.Type) (*types.Signature, error) {
|
|
|
|
|
f, found := t.Methods["DeepCopyInto"]
|
|
|
|
|
if !found {
|
|
|
|
|
return nil, nil
|
|
|
|
|
}
|
|
|
|
|
if len(f.Signature.Parameters) != 1 {
|
|
|
|
|
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected exactly one parameter", t)
|
|
|
|
|
}
|
|
|
|
|
if len(f.Signature.Results) != 0 {
|
|
|
|
|
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected no result type", t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ptrParam := f.Signature.Parameters[0].Kind == types.Pointer && f.Signature.Parameters[0].Elem.Name == t.Name
|
|
|
|
|
|
|
|
|
|
if !ptrParam {
|
|
|
|
|
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected parameter of type *%s", t, t.Name.Name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ptrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Kind == types.Pointer && f.Signature.Receiver.Elem.Name == t.Name
|
|
|
|
|
nonPtrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Name == t.Name
|
|
|
|
|
|
|
|
|
|
if !ptrRcvr && !nonPtrRcvr {
|
|
|
|
|
// this should never happen
|
|
|
|
|
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected a receiver of type %s or *%s", t, t.Name.Name, t.Name.Name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return f.Signature, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// deepCopyIntoMethodOrDie returns the signature of a DeepCopyInto() method, nil or calls glog.Fatalf
|
|
|
|
|
// if the type is wrong.
|
|
|
|
|
func deepCopyIntoMethodOrDie(t *types.Type) *types.Signature {
|
|
|
|
|
ret, err := deepCopyIntoMethod(t)
|
|
|
|
|
if err != nil {
|
|
|
|
|
glog.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
return ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func isRootedUnder(pkg string, roots []string) bool {
|
|
|
|
@ -327,17 +395,36 @@ func copyableType(t *types.Type) bool {
|
|
|
|
|
if ttag != nil && ttag.value == "false" {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
// TODO: Consider generating functions for other kinds too.
|
|
|
|
|
if t.Kind != types.Struct {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
// Also, filter out private types.
|
|
|
|
|
|
|
|
|
|
// Filter out private types.
|
|
|
|
|
if namer.IsPrivateGoName(t.Name.Name) {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if t.Kind == types.Alias {
|
|
|
|
|
// if the underlying built-in is not deepcopy-able, deepcopy is opt-in through definition of custom methods.
|
|
|
|
|
// Note that aliases of builtins, maps, slices can have deepcopy methods.
|
|
|
|
|
if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
|
|
|
|
|
return true
|
|
|
|
|
} else {
|
|
|
|
|
return t.Underlying.Kind != types.Builtin || copyableType(t.Underlying)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if t.Kind != types.Struct {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func underlyingType(t *types.Type) *types.Type {
|
|
|
|
|
for t.Kind == types.Alias {
|
|
|
|
|
t = t.Underlying
|
|
|
|
|
}
|
|
|
|
|
return t
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (g *genDeepCopy) isOtherPackage(pkg string) bool {
|
|
|
|
|
if pkg == g.targetPackage {
|
|
|
|
|
return false
|
|
|
|
@ -426,7 +513,7 @@ func extractNonPointerInterfaces(comments []string) (bool, error) {
|
|
|
|
|
return result, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (g *genDeepCopy) deepCopyableInterfaces(c *generator.Context, t *types.Type) ([]*types.Type, error) {
|
|
|
|
|
func (g *genDeepCopy) deepCopyableInterfacesInner(c *generator.Context, t *types.Type) ([]*types.Type, error) {
|
|
|
|
|
if t.Kind != types.Struct {
|
|
|
|
|
return nil, nil
|
|
|
|
|
}
|
|
|
|
@ -451,9 +538,9 @@ func (g *genDeepCopy) deepCopyableInterfaces(c *generator.Context, t *types.Type
|
|
|
|
|
return ts, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DeepCopyableInterfaces returns the interface types to implement and whether they apply to a non-pointer receiver.
|
|
|
|
|
func (g *genDeepCopy) DeepCopyableInterfaces(c *generator.Context, t *types.Type) ([]*types.Type, bool, error) {
|
|
|
|
|
ts, err := g.deepCopyableInterfaces(c, t)
|
|
|
|
|
// deepCopyableInterfaces returns the interface types to implement and whether they apply to a non-pointer receiver.
|
|
|
|
|
func (g *genDeepCopy) deepCopyableInterfaces(c *generator.Context, t *types.Type) ([]*types.Type, bool, error) {
|
|
|
|
|
ts, err := g.deepCopyableInterfacesInner(c, t)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, false, err
|
|
|
|
|
}
|
|
|
|
@ -494,12 +581,15 @@ func (g *genDeepCopy) GenerateType(c *generator.Context, t *types.Type, w io.Wri
|
|
|
|
|
sw := generator.NewSnippetWriter(w, c, "$", "$")
|
|
|
|
|
args := argsFromType(t)
|
|
|
|
|
|
|
|
|
|
_, foundDeepCopyInto := t.Methods["DeepCopyInto"]
|
|
|
|
|
_, foundDeepCopy := t.Methods["DeepCopy"]
|
|
|
|
|
if !foundDeepCopyInto {
|
|
|
|
|
if deepCopyIntoMethodOrDie(t) == nil {
|
|
|
|
|
sw.Do("// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\n", args)
|
|
|
|
|
sw.Do("func (in *$.type|raw$) DeepCopyInto(out *$.type|raw$) {\n", args)
|
|
|
|
|
if foundDeepCopy {
|
|
|
|
|
if isReference(t) {
|
|
|
|
|
sw.Do("func (in $.type|raw$) DeepCopyInto(out *$.type|raw$) {\n", args)
|
|
|
|
|
sw.Do("{in:=&in\n", nil)
|
|
|
|
|
} else {
|
|
|
|
|
sw.Do("func (in *$.type|raw$) DeepCopyInto(out *$.type|raw$) {\n", args)
|
|
|
|
|
}
|
|
|
|
|
if deepCopyMethodOrDie(t) != nil {
|
|
|
|
|
if t.Methods["DeepCopy"].Signature.Receiver.Kind == types.Pointer {
|
|
|
|
|
sw.Do("clone := in.DeepCopy()\n", nil)
|
|
|
|
|
sw.Do("*out = *clone\n", nil)
|
|
|
|
@ -511,20 +601,31 @@ func (g *genDeepCopy) GenerateType(c *generator.Context, t *types.Type, w io.Wri
|
|
|
|
|
g.generateFor(t, sw)
|
|
|
|
|
sw.Do("return\n", nil)
|
|
|
|
|
}
|
|
|
|
|
if isReference(t) {
|
|
|
|
|
sw.Do("}\n", nil)
|
|
|
|
|
}
|
|
|
|
|
sw.Do("}\n\n", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !foundDeepCopy {
|
|
|
|
|
if deepCopyMethodOrDie(t) == nil {
|
|
|
|
|
sw.Do("// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new $.type|raw$.\n", args)
|
|
|
|
|
sw.Do("func (in *$.type|raw$) DeepCopy() *$.type|raw$ {\n", args)
|
|
|
|
|
if isReference(t) {
|
|
|
|
|
sw.Do("func (in $.type|raw$) DeepCopy() $.type|raw$ {\n", args)
|
|
|
|
|
} else {
|
|
|
|
|
sw.Do("func (in *$.type|raw$) DeepCopy() *$.type|raw$ {\n", args)
|
|
|
|
|
}
|
|
|
|
|
sw.Do("if in == nil { return nil }\n", nil)
|
|
|
|
|
sw.Do("out := new($.type|raw$)\n", args)
|
|
|
|
|
sw.Do("in.DeepCopyInto(out)\n", nil)
|
|
|
|
|
sw.Do("return out\n", nil)
|
|
|
|
|
if isReference(t) {
|
|
|
|
|
sw.Do("return *out\n", nil)
|
|
|
|
|
} else {
|
|
|
|
|
sw.Do("return out\n", nil)
|
|
|
|
|
}
|
|
|
|
|
sw.Do("}\n\n", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
intfs, nonPointerReceiver, err := g.DeepCopyableInterfaces(c, t)
|
|
|
|
|
intfs, nonPointerReceiver, err := g.deepCopyableInterfaces(c, t)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
@ -538,21 +639,33 @@ func (g *genDeepCopy) GenerateType(c *generator.Context, t *types.Type, w io.Wri
|
|
|
|
|
sw.Do(fmt.Sprintf("func (in *$.type|raw$) DeepCopy%s() $.type2|raw$ {\n", intf.Name.Name), argsFromType(t, intf))
|
|
|
|
|
sw.Do("if c := in.DeepCopy(); c != nil {\n", nil)
|
|
|
|
|
sw.Do("return c\n", nil)
|
|
|
|
|
sw.Do("} else {\n", nil)
|
|
|
|
|
sw.Do("}\n", nil)
|
|
|
|
|
sw.Do("return nil\n", nil)
|
|
|
|
|
sw.Do("}}\n\n", nil)
|
|
|
|
|
sw.Do("}\n\n", nil)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sw.Error()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// isReference return true for pointer, maps, slices and aliases of those.
|
|
|
|
|
func isReference(t *types.Type) bool {
|
|
|
|
|
if t.Kind == types.Pointer || t.Kind == types.Map || t.Kind == types.Slice {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return t.Kind == types.Alias && isReference(underlyingType(t))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// we use the system of shadowing 'in' and 'out' so that the same code is valid
|
|
|
|
|
// at any nesting level. This makes the autogenerator easy to understand, and
|
|
|
|
|
// the compiler shouldn't care.
|
|
|
|
|
func (g *genDeepCopy) generateFor(t *types.Type, sw *generator.SnippetWriter) {
|
|
|
|
|
// derive inner types if t is an alias. We call the do* methods below with the alias type.
|
|
|
|
|
// basic rule: generate according to inner type, but construct objects with the alias type.
|
|
|
|
|
ut := underlyingType(t)
|
|
|
|
|
|
|
|
|
|
var f func(*types.Type, *generator.SnippetWriter)
|
|
|
|
|
switch t.Kind {
|
|
|
|
|
switch ut.Kind {
|
|
|
|
|
case types.Builtin:
|
|
|
|
|
f = g.doBuiltin
|
|
|
|
|
case types.Map:
|
|
|
|
@ -561,110 +674,147 @@ func (g *genDeepCopy) generateFor(t *types.Type, sw *generator.SnippetWriter) {
|
|
|
|
|
f = g.doSlice
|
|
|
|
|
case types.Struct:
|
|
|
|
|
f = g.doStruct
|
|
|
|
|
case types.Interface:
|
|
|
|
|
f = g.doInterface
|
|
|
|
|
case types.Pointer:
|
|
|
|
|
f = g.doPointer
|
|
|
|
|
case types.Interface:
|
|
|
|
|
// interfaces are handled in-line in the other cases
|
|
|
|
|
glog.Fatalf("Hit an interface type %v. This should never happen.", t)
|
|
|
|
|
case types.Alias:
|
|
|
|
|
f = g.doAlias
|
|
|
|
|
// can never happen because we branch on the underlying type which is never an alias
|
|
|
|
|
glog.Fatalf("Hit an alias type %v. This should never happen.", t)
|
|
|
|
|
default:
|
|
|
|
|
f = g.doUnknown
|
|
|
|
|
}
|
|
|
|
|
f(t, sw)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// doBuiltin generates code for a builtin or an alias to a builtin. The generated code is
|
|
|
|
|
// is the same for both cases, i.e. it's the code for the underlying type.
|
|
|
|
|
func (g *genDeepCopy) doBuiltin(t *types.Type, sw *generator.SnippetWriter) {
|
|
|
|
|
if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
|
|
|
|
|
sw.Do("*out = in.DeepCopy()\n", nil)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sw.Do("*out = *in\n", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// doMap generates code for a map or an alias to a map. The generated code is
|
|
|
|
|
// is the same for both cases, i.e. it's the code for the underlying type.
|
|
|
|
|
func (g *genDeepCopy) doMap(t *types.Type, sw *generator.SnippetWriter) {
|
|
|
|
|
ut := underlyingType(t)
|
|
|
|
|
uet := underlyingType(ut.Elem)
|
|
|
|
|
|
|
|
|
|
if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
|
|
|
|
|
sw.Do("*out = in.DeepCopy()\n", nil)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sw.Do("*out = make($.|raw$, len(*in))\n", t)
|
|
|
|
|
if t.Key.IsAssignable() {
|
|
|
|
|
if ut.Key.IsAssignable() {
|
|
|
|
|
dc, dci := deepCopyMethodOrDie(ut.Elem), deepCopyIntoMethodOrDie(ut.Elem)
|
|
|
|
|
switch {
|
|
|
|
|
case hasDeepCopyMethod(t.Elem):
|
|
|
|
|
case dc != nil || dci != nil:
|
|
|
|
|
sw.Do("for key, val := range *in {\n", nil)
|
|
|
|
|
sw.Do("(*out)[key] = val.DeepCopy()\n", nil)
|
|
|
|
|
// Note: a DeepCopy exists because it is added if DeepCopyInto is manually defined
|
|
|
|
|
leftPointer := ut.Elem.Kind == types.Pointer
|
|
|
|
|
rightPointer := !isReference(ut.Elem)
|
|
|
|
|
if dc != nil {
|
|
|
|
|
rightPointer = dc.Results[0].Kind == types.Pointer
|
|
|
|
|
}
|
|
|
|
|
if leftPointer == rightPointer {
|
|
|
|
|
sw.Do("(*out)[key] = val.DeepCopy()\n", nil)
|
|
|
|
|
} else if leftPointer {
|
|
|
|
|
sw.Do("x := val.DeepCopy()\n", nil)
|
|
|
|
|
sw.Do("(*out)[key] = &x\n", nil)
|
|
|
|
|
} else {
|
|
|
|
|
sw.Do("(*out)[key] = *val.DeepCopy()\n", nil)
|
|
|
|
|
}
|
|
|
|
|
sw.Do("}\n", nil)
|
|
|
|
|
case t.Elem.IsAnonymousStruct():
|
|
|
|
|
case ut.Elem.IsAnonymousStruct(): // not uet here because it needs type cast
|
|
|
|
|
sw.Do("for key := range *in {\n", nil)
|
|
|
|
|
sw.Do("(*out)[key] = struct{}{}\n", nil)
|
|
|
|
|
sw.Do("}\n", nil)
|
|
|
|
|
case t.Elem.IsAssignable():
|
|
|
|
|
case uet.IsAssignable():
|
|
|
|
|
sw.Do("for key, val := range *in {\n", nil)
|
|
|
|
|
sw.Do("(*out)[key] = val\n", nil)
|
|
|
|
|
sw.Do("}\n", nil)
|
|
|
|
|
case t.Elem.Kind == types.Interface:
|
|
|
|
|
case uet.Kind == types.Interface:
|
|
|
|
|
sw.Do("for key, val := range *in {\n", nil)
|
|
|
|
|
sw.Do("if val == nil {(*out)[key]=nil} else {\n", nil)
|
|
|
|
|
sw.Do(fmt.Sprintf("(*out)[key] = val.DeepCopy%s()\n", t.Elem.Name.Name), t)
|
|
|
|
|
// Note: if t.Elem has been an alias "J" of an interface "I" in Go, we will see it
|
|
|
|
|
// as kind Interface of name "J" here, i.e. generate val.DeepCopyJ(). The golang
|
|
|
|
|
// parser does not give us the underlying interface name. So we cannot do any better.
|
|
|
|
|
sw.Do(fmt.Sprintf("(*out)[key] = val.DeepCopy%s()\n", uet.Name.Name), nil)
|
|
|
|
|
sw.Do("}}\n", nil)
|
|
|
|
|
default:
|
|
|
|
|
sw.Do("for key, val := range *in {\n", nil)
|
|
|
|
|
if g.copyableAndInBounds(t.Elem) {
|
|
|
|
|
sw.Do("newVal := new($.|raw$)\n", t.Elem)
|
|
|
|
|
if g.copyableAndInBounds(uet) {
|
|
|
|
|
sw.Do("newVal := new($.|raw$)\n", ut.Elem)
|
|
|
|
|
sw.Do("val.DeepCopyInto(newVal)\n", nil)
|
|
|
|
|
sw.Do("(*out)[key] = *newVal\n", nil)
|
|
|
|
|
} else if t.Elem.Kind == types.Slice && t.Elem.Elem.Kind == types.Builtin {
|
|
|
|
|
} else if uet.Kind == types.Slice && underlyingType(uet.Elem).Kind == types.Builtin {
|
|
|
|
|
sw.Do("if val==nil { (*out)[key]=nil } else {\n", nil)
|
|
|
|
|
sw.Do("(*out)[key] = make($.|raw$, len(val))\n", t.Elem)
|
|
|
|
|
sw.Do("(*out)[key] = make($.|raw$, len(val))\n", uet)
|
|
|
|
|
sw.Do("copy((*out)[key], val)\n", nil)
|
|
|
|
|
sw.Do("}\n", nil)
|
|
|
|
|
} else if t.Elem.Kind == types.Alias && t.Elem.Underlying.Kind == types.Slice && t.Elem.Underlying.Elem.Kind == types.Builtin {
|
|
|
|
|
sw.Do("(*out)[key] = make($.|raw$, len(val))\n", t.Elem)
|
|
|
|
|
sw.Do("copy((*out)[key], val)\n", nil)
|
|
|
|
|
} else if t.Elem.Kind == types.Pointer {
|
|
|
|
|
} else if uet.Kind == types.Pointer {
|
|
|
|
|
sw.Do("if val==nil { (*out)[key]=nil } else {\n", nil)
|
|
|
|
|
sw.Do("(*out)[key] = new($.Elem|raw$)\n", t.Elem)
|
|
|
|
|
sw.Do("(*out)[key] = new($.Elem|raw$)\n", uet)
|
|
|
|
|
sw.Do("val.DeepCopyInto((*out)[key])\n", nil)
|
|
|
|
|
sw.Do("}\n", nil)
|
|
|
|
|
} else {
|
|
|
|
|
sw.Do("(*out)[key] = *val.DeepCopy()\n", t.Elem)
|
|
|
|
|
sw.Do("(*out)[key] = *val.DeepCopy()\n", uet)
|
|
|
|
|
}
|
|
|
|
|
sw.Do("}\n", nil)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// TODO: Implement it when necessary.
|
|
|
|
|
sw.Do("for range *in {\n", nil)
|
|
|
|
|
sw.Do("// FIXME: Copying unassignable keys unsupported $.|raw$\n", t.Key)
|
|
|
|
|
sw.Do("// FIXME: Copying unassignable keys unsupported $.|raw$\n", ut.Key)
|
|
|
|
|
sw.Do("}\n", nil)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// doSlice generates code for a slice or an alias to a slice. The generated code is
|
|
|
|
|
// is the same for both cases, i.e. it's the code for the underlying type.
|
|
|
|
|
func (g *genDeepCopy) doSlice(t *types.Type, sw *generator.SnippetWriter) {
|
|
|
|
|
if hasDeepCopyMethod(t) {
|
|
|
|
|
ut := underlyingType(t)
|
|
|
|
|
uet := underlyingType(ut.Elem)
|
|
|
|
|
|
|
|
|
|
if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
|
|
|
|
|
sw.Do("*out = in.DeepCopy()\n", nil)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sw.Do("*out = make($.|raw$, len(*in))\n", t)
|
|
|
|
|
if hasDeepCopyMethod(t.Elem) {
|
|
|
|
|
if deepCopyMethodOrDie(ut.Elem) != nil || deepCopyIntoMethodOrDie(ut.Elem) != nil {
|
|
|
|
|
sw.Do("for i := range *in {\n", nil)
|
|
|
|
|
sw.Do("(*out)[i] = (*in)[i].DeepCopy()\n", nil)
|
|
|
|
|
// Note: a DeepCopyInto exists because it is added if DeepCopy is manually defined
|
|
|
|
|
sw.Do("(*in)[i].DeepCopyInto(&(*out)[i])\n", nil)
|
|
|
|
|
sw.Do("}\n", nil)
|
|
|
|
|
} else if t.Elem.Kind == types.Builtin || t.Elem.IsAssignable() {
|
|
|
|
|
} else if uet.Kind == types.Builtin || uet.IsAssignable() {
|
|
|
|
|
sw.Do("copy(*out, *in)\n", nil)
|
|
|
|
|
} else {
|
|
|
|
|
sw.Do("for i := range *in {\n", nil)
|
|
|
|
|
if t.Elem.Kind == types.Slice {
|
|
|
|
|
if uet.Kind == types.Slice || uet.Kind == types.Map || deepCopyMethodOrDie(ut.Elem) != nil || deepCopyIntoMethodOrDie(ut.Elem) != nil {
|
|
|
|
|
sw.Do("if (*in)[i] != nil {\n", nil)
|
|
|
|
|
sw.Do("in, out := &(*in)[i], &(*out)[i]\n", nil)
|
|
|
|
|
g.generateFor(t.Elem, sw)
|
|
|
|
|
g.generateFor(ut.Elem, sw)
|
|
|
|
|
sw.Do("}\n", nil)
|
|
|
|
|
} else if hasDeepCopyMethod(t.Elem) {
|
|
|
|
|
sw.Do("(*out)[i] = (*in)[i].DeepCopy()\n", nil)
|
|
|
|
|
// REVISIT(sttts): the following is removed in master
|
|
|
|
|
//} else if t.Elem.IsAssignable() {
|
|
|
|
|
// sw.Do("(*out)[i] = (*in)[i]\n", nil)
|
|
|
|
|
} else if t.Elem.Kind == types.Interface {
|
|
|
|
|
} else if uet.Kind == types.Interface {
|
|
|
|
|
sw.Do("if (*in)[i] == nil {(*out)[i]=nil} else {\n", nil)
|
|
|
|
|
sw.Do(fmt.Sprintf("(*out)[i] = (*in)[i].DeepCopy%s()\n", t.Elem.Name.Name), t)
|
|
|
|
|
// Note: if t.Elem has been an alias "J" of an interface "I" in Go, we will see it
|
|
|
|
|
// as kind Interface of name "J" here, i.e. generate val.DeepCopyJ(). The golang
|
|
|
|
|
// parser does not give us the underlying interface name. So we cannot do any better.
|
|
|
|
|
sw.Do(fmt.Sprintf("(*out)[i] = (*in)[i].DeepCopy%s()\n", uet.Name.Name), nil)
|
|
|
|
|
sw.Do("}\n", nil)
|
|
|
|
|
} else if t.Elem.Kind == types.Pointer {
|
|
|
|
|
} else if uet.Kind == types.Pointer {
|
|
|
|
|
sw.Do("if (*in)[i]==nil { (*out)[i]=nil } else {\n", nil)
|
|
|
|
|
sw.Do("(*out)[i] = new($.Elem|raw$)\n", t.Elem)
|
|
|
|
|
sw.Do("(*out)[i] = new($.Elem|raw$)\n", uet)
|
|
|
|
|
sw.Do("(*in)[i].DeepCopyInto((*out)[i])\n", nil)
|
|
|
|
|
sw.Do("}\n", nil)
|
|
|
|
|
} else if t.Elem.Kind == types.Struct {
|
|
|
|
|
} else if uet.Kind == types.Struct {
|
|
|
|
|
sw.Do("(*in)[i].DeepCopyInto(&(*out)[i])\n", nil)
|
|
|
|
|
} else {
|
|
|
|
|
sw.Do("(*out)[i] = (*in)[i].DeepCopy()\n", nil)
|
|
|
|
@ -673,8 +823,12 @@ func (g *genDeepCopy) doSlice(t *types.Type, sw *generator.SnippetWriter) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// doStruct generates code for a struct or an alias to a struct. The generated code is
|
|
|
|
|
// is the same for both cases, i.e. it's the code for the underlying type.
|
|
|
|
|
func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) {
|
|
|
|
|
if hasDeepCopyMethod(t) {
|
|
|
|
|
ut := underlyingType(t)
|
|
|
|
|
|
|
|
|
|
if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
|
|
|
|
|
sw.Do("*out = in.DeepCopy()\n", nil)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@ -683,48 +837,52 @@ func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) {
|
|
|
|
|
sw.Do("*out = *in\n", nil)
|
|
|
|
|
|
|
|
|
|
// Now fix-up fields as needed.
|
|
|
|
|
for _, m := range t.Members {
|
|
|
|
|
t := m.Type
|
|
|
|
|
hasMethod := hasDeepCopyMethod(t)
|
|
|
|
|
if t.Kind == types.Alias {
|
|
|
|
|
copied := *t.Underlying
|
|
|
|
|
copied.Name = t.Name
|
|
|
|
|
t = &copied
|
|
|
|
|
}
|
|
|
|
|
for _, m := range ut.Members {
|
|
|
|
|
ft := m.Type
|
|
|
|
|
uft := underlyingType(ft)
|
|
|
|
|
|
|
|
|
|
args := generator.Args{
|
|
|
|
|
"type": t,
|
|
|
|
|
"kind": t.Kind,
|
|
|
|
|
"type": ft,
|
|
|
|
|
"kind": ft.Kind,
|
|
|
|
|
"name": m.Name,
|
|
|
|
|
}
|
|
|
|
|
switch t.Kind {
|
|
|
|
|
case types.Builtin:
|
|
|
|
|
if hasMethod {
|
|
|
|
|
sw.Do("out.$.name$ = in.$.name$.DeepCopy()\n", args)
|
|
|
|
|
dc, dci := deepCopyMethodOrDie(ft), deepCopyIntoMethodOrDie(ft)
|
|
|
|
|
switch {
|
|
|
|
|
case dc != nil || dci != nil:
|
|
|
|
|
// Note: a DeepCopyInto exists because it is added if DeepCopy is manually defined
|
|
|
|
|
leftPointer := ft.Kind == types.Pointer
|
|
|
|
|
rightPointer := !isReference(ft)
|
|
|
|
|
if dc != nil {
|
|
|
|
|
rightPointer = dc.Results[0].Kind == types.Pointer
|
|
|
|
|
}
|
|
|
|
|
// the initial *out = *in was enough
|
|
|
|
|
case types.Map, types.Slice, types.Pointer:
|
|
|
|
|
if hasMethod {
|
|
|
|
|
sw.Do("if in.$.name$ != nil {\n", args)
|
|
|
|
|
if leftPointer == rightPointer {
|
|
|
|
|
sw.Do("out.$.name$ = in.$.name$.DeepCopy()\n", args)
|
|
|
|
|
sw.Do("}\n", nil)
|
|
|
|
|
} else if leftPointer {
|
|
|
|
|
sw.Do("x := in.$.name$.DeepCopy()\n", args)
|
|
|
|
|
sw.Do("out.$.name$ = = &x\n", args)
|
|
|
|
|
} else {
|
|
|
|
|
// Fixup non-nil reference-semantic types.
|
|
|
|
|
sw.Do("if in.$.name$ != nil {\n", args)
|
|
|
|
|
sw.Do("in, out := &in.$.name$, &out.$.name$\n", args)
|
|
|
|
|
g.generateFor(t, sw)
|
|
|
|
|
sw.Do("}\n", nil)
|
|
|
|
|
sw.Do("in.$.name$.DeepCopyInto(&out.$.name$)\n", args)
|
|
|
|
|
}
|
|
|
|
|
case types.Struct:
|
|
|
|
|
if hasMethod {
|
|
|
|
|
sw.Do("out.$.name$ = in.$.name$.DeepCopy()\n", args)
|
|
|
|
|
} else if t.IsAssignable() {
|
|
|
|
|
case uft.Kind == types.Builtin:
|
|
|
|
|
// the initial *out = *in was enough
|
|
|
|
|
case uft.Kind == types.Map, uft.Kind == types.Slice, uft.Kind == types.Pointer:
|
|
|
|
|
// Fixup non-nil reference-semantic types.
|
|
|
|
|
sw.Do("if in.$.name$ != nil {\n", args)
|
|
|
|
|
sw.Do("in, out := &in.$.name$, &out.$.name$\n", args)
|
|
|
|
|
g.generateFor(ft, sw)
|
|
|
|
|
sw.Do("}\n", nil)
|
|
|
|
|
case uft.Kind == types.Struct:
|
|
|
|
|
if ft.IsAssignable() {
|
|
|
|
|
sw.Do("out.$.name$ = in.$.name$\n", args)
|
|
|
|
|
} else {
|
|
|
|
|
sw.Do("in.$.name$.DeepCopyInto(&out.$.name$)\n", args)
|
|
|
|
|
}
|
|
|
|
|
case types.Interface:
|
|
|
|
|
case uft.Kind == types.Interface:
|
|
|
|
|
sw.Do("if in.$.name$ == nil {out.$.name$=nil} else {\n", args)
|
|
|
|
|
sw.Do(fmt.Sprintf("out.$.name$ = in.$.name$.DeepCopy%s()\n", t.Name.Name), args)
|
|
|
|
|
// Note: if t.Elem has been an alias "J" of an interface "I" in Go, we will see it
|
|
|
|
|
// as kind Interface of name "J" here, i.e. generate val.DeepCopyJ(). The golang
|
|
|
|
|
// parser does not give us the underlying interface name. So we cannot do any better.
|
|
|
|
|
sw.Do(fmt.Sprintf("out.$.name$ = in.$.name$.DeepCopy%s()\n", uft.Name.Name), args)
|
|
|
|
|
sw.Do("}\n", nil)
|
|
|
|
|
default:
|
|
|
|
|
sw.Do("out.$.name$ = in.$.name$.DeepCopy()\n", args)
|
|
|
|
@ -732,40 +890,44 @@ func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (g *genDeepCopy) doInterface(t *types.Type, sw *generator.SnippetWriter) {
|
|
|
|
|
// TODO: Add support for interfaces.
|
|
|
|
|
g.doUnknown(t, sw)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// doPointer generates code for a pointer or an alias to a pointer. The generated code is
|
|
|
|
|
// is the same for both cases, i.e. it's the code for the underlying type.
|
|
|
|
|
func (g *genDeepCopy) doPointer(t *types.Type, sw *generator.SnippetWriter) {
|
|
|
|
|
ut := underlyingType(t)
|
|
|
|
|
uet := underlyingType(ut.Elem)
|
|
|
|
|
|
|
|
|
|
sw.Do("if *in == nil { *out = nil } else {\n", t)
|
|
|
|
|
if hasDeepCopyMethod(t.Elem) {
|
|
|
|
|
sw.Do("*out = new($.Elem|raw$)\n", t)
|
|
|
|
|
sw.Do("**out = (*in).DeepCopy()\n", nil)
|
|
|
|
|
} else if t.Elem.IsAssignable() {
|
|
|
|
|
sw.Do("*out = new($.Elem|raw$)\n", t)
|
|
|
|
|
dc, dci := deepCopyMethodOrDie(ut.Elem), deepCopyIntoMethodOrDie(ut.Elem)
|
|
|
|
|
if dc != nil || dci != nil {
|
|
|
|
|
rightPointer := !isReference(ut.Elem)
|
|
|
|
|
if dc != nil {
|
|
|
|
|
rightPointer = dc.Results[0].Kind == types.Pointer
|
|
|
|
|
}
|
|
|
|
|
if rightPointer {
|
|
|
|
|
sw.Do("*out = (*in).DeepCopy()\n", nil)
|
|
|
|
|
} else {
|
|
|
|
|
sw.Do("x := (*in).DeepCopy()\n", nil)
|
|
|
|
|
sw.Do("*out = &x\n", nil)
|
|
|
|
|
}
|
|
|
|
|
} else if uet.IsAssignable() {
|
|
|
|
|
sw.Do("*out = new($.Elem|raw$)\n", ut)
|
|
|
|
|
sw.Do("**out = **in", nil)
|
|
|
|
|
} else {
|
|
|
|
|
switch t.Elem.Kind {
|
|
|
|
|
switch uet.Kind {
|
|
|
|
|
case types.Map, types.Slice:
|
|
|
|
|
sw.Do("*out = new($.Elem|raw$)\n", t)
|
|
|
|
|
sw.Do("if **in != nil {\n", t)
|
|
|
|
|
sw.Do("*out = new($.Elem|raw$)\n", ut)
|
|
|
|
|
sw.Do("if **in != nil {\n", nil)
|
|
|
|
|
sw.Do("in, out := *in, *out\n", nil)
|
|
|
|
|
g.generateFor(t.Elem, sw)
|
|
|
|
|
g.generateFor(uet, sw)
|
|
|
|
|
sw.Do("}\n", nil)
|
|
|
|
|
default:
|
|
|
|
|
sw.Do("*out = new($.Elem|raw$)\n", t)
|
|
|
|
|
sw.Do("*out = new($.Elem|raw$)\n", ut)
|
|
|
|
|
sw.Do("(*in).DeepCopyInto(*out)\n", nil)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
sw.Do("}", t)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (g *genDeepCopy) doAlias(t *types.Type, sw *generator.SnippetWriter) {
|
|
|
|
|
// TODO: Add support for aliases.
|
|
|
|
|
g.doUnknown(t, sw)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (g *genDeepCopy) doUnknown(t *types.Type, sw *generator.SnippetWriter) {
|
|
|
|
|
sw.Do("// FIXME: Type $.|raw$ is unsupported.\n", t)
|
|
|
|
|
}
|
|
|
|
|