diff --git a/build/tools.go b/build/tools.go index cd404c702c9..12b785da2cf 100644 --- a/build/tools.go +++ b/build/tools.go @@ -23,10 +23,10 @@ package tools import ( // build script dependencies _ "github.com/onsi/ginkgo/v2/ginkgo" + _ "k8s.io/code-generator/cmd/deepcopy-gen" _ "k8s.io/code-generator/cmd/go-to-protobuf" _ "k8s.io/code-generator/cmd/go-to-protobuf/protoc-gen-gogo" _ "k8s.io/code-generator/cmd/import-boss" - _ "k8s.io/gengo/v2/examples/deepcopy-gen/generators" _ "k8s.io/gengo/v2/examples/defaulter-gen/generators" _ "k8s.io/kube-openapi/cmd/openapi-gen" diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/args/args.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/args/args.go index e884be8979f..bd3b64763e9 100644 --- a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/args/args.go +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/args/args.go @@ -21,17 +21,20 @@ import ( "github.com/spf13/pflag" "k8s.io/gengo/v2/args" - "k8s.io/gengo/v2/examples/deepcopy-gen/generators" ) // CustomArgs is used by the gengo framework to pass args specific to this generator. -type CustomArgs generators.CustomArgs +type CustomArgs struct { + OutputFile string + BoundingDirs []string // Only deal with types rooted under these dirs. + GoHeaderFile string +} // NewDefaults returns default arguments for the generator. func NewDefaults() (*args.GeneratorArgs, *CustomArgs) { genericArgs := args.Default() customArgs := &CustomArgs{} - genericArgs.CustomArgs = (*generators.CustomArgs)(customArgs) // convert to upstream type to make type-casts work there + genericArgs.CustomArgs = (*CustomArgs)(customArgs) // convert to upstream type to make type-casts work there return genericArgs, customArgs } @@ -47,7 +50,7 @@ func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet) { // Validate checks the given arguments. func Validate(genericArgs *args.GeneratorArgs) error { - custom := genericArgs.CustomArgs.(*generators.CustomArgs) + custom := genericArgs.CustomArgs.(*CustomArgs) if len(custom.OutputFile) == 0 { return fmt.Errorf("--output-file must be specified") diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/generators/deepcopy.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/generators/deepcopy.go new file mode 100644 index 00000000000..8ba9e723f52 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/generators/deepcopy.go @@ -0,0 +1,897 @@ +/* +Copyright 2015 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "fmt" + "io" + "path/filepath" + "sort" + "strings" + + deepcopyargs "k8s.io/code-generator/cmd/deepcopy-gen/args" + "k8s.io/gengo/v2/args" + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" + "k8s.io/klog/v2" +) + +// This is the comment tag that carries parameters for deep-copy generation. +const ( + tagEnabledName = "k8s:deepcopy-gen" + interfacesTagName = tagEnabledName + ":interfaces" + interfacesNonPointerTagName = tagEnabledName + ":nonpointer-interfaces" // attach the DeepCopy methods to the +) + +// Known values for the comment tag. +const tagValuePackage = "package" + +// enabledTagValue holds parameters from a tagName tag. +type enabledTagValue struct { + value string + register bool +} + +func extractEnabledTypeTag(t *types.Type) *enabledTagValue { + comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...) + return extractEnabledTag(comments) +} + +func extractEnabledTag(comments []string) *enabledTagValue { + tagVals := types.ExtractCommentTags("+", comments)[tagEnabledName] + if tagVals == nil { + // No match for the tag. + return nil + } + // If there are multiple values, abort. + if len(tagVals) > 1 { + klog.Fatalf("Found %d %s tags: %q", len(tagVals), tagEnabledName, tagVals) + } + + // If we got here we are returning something. + tag := &enabledTagValue{} + + // Get the primary value. + parts := strings.Split(tagVals[0], ",") + if len(parts) >= 1 { + tag.value = parts[0] + } + + // Parse extra arguments. + parts = parts[1:] + for i := range parts { + kv := strings.SplitN(parts[i], "=", 2) + k := kv[0] + v := "" + if len(kv) == 2 { + v = kv[1] + } + switch k { + case "register": + if v != "false" { + tag.register = true + } + default: + klog.Fatalf("Unsupported %s param: %q", tagEnabledName, parts[i]) + } + } + return tag +} + +// TODO: This is created only to reduce number of changes in a single PR. +// Remove it and use PublicNamer instead. +func deepCopyNamer() *namer.NameStrategy { + return &namer.NameStrategy{ + Join: func(pre string, in []string, post string) string { + return strings.Join(in, "_") + }, + PrependPackageNames: 1, + } +} + +// NameSystems returns the name system used by the generators in this package. +func NameSystems() namer.NameSystems { + return namer.NameSystems{ + "public": deepCopyNamer(), + "raw": namer.NewRawNamer("", nil), + } +} + +// DefaultNameSystem returns the default name system for ordering the types to be +// processed by the generators in this package. +func DefaultNameSystem() string { + return "public" +} + +func GetTargets(context *generator.Context, arguments *args.GeneratorArgs) []generator.Target { + customArgs := arguments.CustomArgs.(*deepcopyargs.CustomArgs) + + boilerplate, err := args.GoBoilerplate(customArgs.GoHeaderFile, args.StdBuildTag, args.StdGeneratedBy) + if err != nil { + klog.Fatalf("Failed loading boilerplate: %v", err) + } + + boundingDirs := []string{} + if customArgs.BoundingDirs == nil { + customArgs.BoundingDirs = context.Inputs + } + for i := range customArgs.BoundingDirs { + // Strip any trailing slashes - they are not exactly "correct" but + // this is friendlier. + boundingDirs = append(boundingDirs, strings.TrimRight(customArgs.BoundingDirs[i], "/")) + } + + targets := []generator.Target{} + + for _, i := range context.Inputs { + klog.V(3).Infof("Considering pkg %q", i) + pkg := context.Universe[i] + if pkg == nil { + // If the input had no Go files, for example. + continue + } + + ptag := extractEnabledTag(pkg.Comments) + ptagValue := "" + ptagRegister := false + if ptag != nil { + ptagValue = ptag.value + if ptagValue != tagValuePackage { + klog.Fatalf("Package %v: unsupported %s value: %q", i, tagEnabledName, ptagValue) + } + ptagRegister = ptag.register + klog.V(3).Infof(" tag.value: %q, tag.register: %t", ptagValue, ptagRegister) + } else { + klog.V(3).Infof(" no tag") + } + + // If the pkg-scoped tag says to generate, we can skip scanning types. + pkgNeedsGeneration := (ptagValue == tagValuePackage) + if !pkgNeedsGeneration { + // If the pkg-scoped tag did not exist, scan all types for one that + // explicitly wants generation. Ensure all types that want generation + // can be copied. + var uncopyable []string + for _, t := range pkg.Types { + klog.V(3).Infof(" considering type %q", t.Name.String()) + ttag := extractEnabledTypeTag(t) + if ttag != nil && ttag.value == "true" { + klog.V(3).Infof(" tag=true") + if !copyableType(t) { + uncopyable = append(uncopyable, fmt.Sprintf("%v", t)) + } else { + pkgNeedsGeneration = true + } + } + } + if len(uncopyable) > 0 { + klog.Fatalf("Types requested deepcopy generation but are not copyable: %s", + strings.Join(uncopyable, ", ")) + } + } + + if pkgNeedsGeneration { + klog.V(3).Infof("Package %q needs generation", i) + targets = append(targets, + &generator.SimpleTarget{ + PkgName: strings.Split(filepath.Base(pkg.Path), ".")[0], + PkgPath: pkg.Path, + PkgDir: pkg.SourcePath, // output pkg is the same as the input + HeaderComment: boilerplate, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + return t.Name.Package == pkg.Path + }, + GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) { + return []generator.Generator{ + NewGenDeepCopy(customArgs.OutputFile, pkg.Path, boundingDirs, (ptagValue == tagValuePackage), ptagRegister), + } + }, + }) + } + } + return targets +} + +// genDeepCopy produces a file with autogenerated deep-copy functions. +type genDeepCopy struct { + generator.GoGenerator + targetPackage string + boundingDirs []string + allTypes bool + registerTypes bool + imports namer.ImportTracker + typesForInit []*types.Type +} + +func NewGenDeepCopy(outputFilename, targetPackage string, boundingDirs []string, allTypes, registerTypes bool) generator.Generator { + return &genDeepCopy{ + GoGenerator: generator.GoGenerator{ + OutputFilename: outputFilename, + }, + targetPackage: targetPackage, + boundingDirs: boundingDirs, + allTypes: allTypes, + registerTypes: registerTypes, + imports: generator.NewImportTracker(), + typesForInit: make([]*types.Type, 0), + } +} + +func (g *genDeepCopy) Namers(c *generator.Context) namer.NameSystems { + // Have the raw namer for this file track what it imports. + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.targetPackage, g.imports), + } +} + +func (g *genDeepCopy) Filter(c *generator.Context, t *types.Type) bool { + // Filter out types not being processed or not copyable within the package. + enabled := g.allTypes + if !enabled { + ttag := extractEnabledTypeTag(t) + if ttag != nil && ttag.value == "true" { + enabled = true + } + } + if !enabled { + return false + } + if !copyableType(t) { + klog.V(3).Infof("Type %v is not copyable", t) + return false + } + klog.V(3).Infof("Type %v is copyable", t) + g.typesForInit = append(g.typesForInit, t) + return true +} + +// 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 deepCopyMethod(t *types.Type) (*types.Signature, error) { + f, found := t.Methods["DeepCopy"] + if !found { + return nil, nil + } + 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 klog.Fatalf +// if the type does not match. +func deepCopyMethodOrDie(t *types.Type) *types.Signature { + ret, err := deepCopyMethod(t) + if err != nil { + klog.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 klog.Fatalf +// if the type is wrong. +func deepCopyIntoMethodOrDie(t *types.Type) *types.Signature { + ret, err := deepCopyIntoMethod(t) + if err != nil { + klog.Fatal(err) + } + return ret +} + +func copyableType(t *types.Type) bool { + // If the type opts out of copy-generation, stop. + ttag := extractEnabledTypeTag(t) + if ttag != nil && ttag.value == "false" { + return false + } + + // 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 + } + if strings.HasSuffix(pkg, "\""+g.targetPackage+"\"") { + return false + } + return true +} + +func (g *genDeepCopy) Imports(c *generator.Context) (imports []string) { + importLines := []string{} + for _, singleImport := range g.imports.ImportLines() { + if g.isOtherPackage(singleImport) { + importLines = append(importLines, singleImport) + } + } + return importLines +} + +func argsFromType(ts ...*types.Type) generator.Args { + a := generator.Args{ + "type": ts[0], + } + for i, t := range ts { + a[fmt.Sprintf("type%d", i+1)] = t + } + return a +} + +func (g *genDeepCopy) Init(c *generator.Context, w io.Writer) error { + return nil +} + +func (g *genDeepCopy) needsGeneration(t *types.Type) bool { + tag := extractEnabledTypeTag(t) + tv := "" + if tag != nil { + tv = tag.value + if tv != "true" && tv != "false" { + klog.Fatalf("Type %v: unsupported %s value: %q", t, tagEnabledName, tag.value) + } + } + if g.allTypes && tv == "false" { + // The whole package is being generated, but this type has opted out. + klog.V(2).Infof("Not generating for type %v because type opted out", t) + return false + } + if !g.allTypes && tv != "true" { + // The whole package is NOT being generated, and this type has NOT opted in. + klog.V(2).Infof("Not generating for type %v because type did not opt in", t) + return false + } + return true +} + +func extractInterfacesTag(t *types.Type) []string { + var result []string + comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...) + values := types.ExtractCommentTags("+", comments)[interfacesTagName] + for _, v := range values { + if len(v) == 0 { + continue + } + intfs := strings.Split(v, ",") + for _, intf := range intfs { + if intf == "" { + continue + } + result = append(result, intf) + } + } + return result +} + +func extractNonPointerInterfaces(t *types.Type) (bool, error) { + comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...) + values := types.ExtractCommentTags("+", comments)[interfacesNonPointerTagName] + if len(values) == 0 { + return false, nil + } + result := values[0] == "true" + for _, v := range values { + if v == "true" != result { + return false, fmt.Errorf("contradicting %v value %q found to previous value %v", interfacesNonPointerTagName, v, result) + } + } + return result, nil +} + +func (g *genDeepCopy) deepCopyableInterfacesInner(c *generator.Context, t *types.Type) ([]*types.Type, error) { + if t.Kind != types.Struct { + return nil, nil + } + + intfs := extractInterfacesTag(t) + + var ts []*types.Type + for _, intf := range intfs { + t := types.ParseFullyQualifiedName(intf) + klog.V(3).Infof("Loading package for interface %v", intf) + _, err := c.LoadPackages(t.Package) + if err != nil { + return nil, err + } + intfT := c.Universe.Type(t) + if intfT == nil { + return nil, fmt.Errorf("unknown type %q in %s tag of type %s", intf, interfacesTagName, intfT) + } + if intfT.Kind != types.Interface { + return nil, fmt.Errorf("type %q in %s tag of type %s is not an interface, but: %q", intf, interfacesTagName, t, intfT.Kind) + } + g.imports.AddType(intfT) + ts = append(ts, intfT) + } + + 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.deepCopyableInterfacesInner(c, t) + if err != nil { + return nil, false, err + } + + set := map[string]*types.Type{} + for _, t := range ts { + set[t.String()] = t + } + + result := []*types.Type{} + for _, t := range set { + result = append(result, t) + } + + TypeSlice(result).Sort() // we need a stable sorting because it determines the order in generation + + nonPointerReceiver, err := extractNonPointerInterfaces(t) + if err != nil { + return nil, false, err + } + + return result, nonPointerReceiver, nil +} + +type TypeSlice []*types.Type + +func (s TypeSlice) Len() int { return len(s) } +func (s TypeSlice) Less(i, j int) bool { return s[i].String() < s[j].String() } +func (s TypeSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s TypeSlice) Sort() { sort.Sort(s) } + +func (g *genDeepCopy) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + if !g.needsGeneration(t) { + return nil + } + klog.V(2).Infof("Generating deepcopy functions for type %v", t) + + sw := generator.NewSnippetWriter(w, c, "$", "$") + args := argsFromType(t) + + 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) + 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) + } else { + sw.Do("*out = in.DeepCopy()\n", nil) + } + sw.Do("return\n", nil) + } else { + g.generateFor(t, sw) + sw.Do("return\n", nil) + } + if isReference(t) { + sw.Do("}\n", nil) + } + sw.Do("}\n\n", nil) + } + + if deepCopyMethodOrDie(t) == nil { + sw.Do("// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new $.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) + 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) + if err != nil { + return err + } + for _, intf := range intfs { + sw.Do(fmt.Sprintf("// DeepCopy%s is an autogenerated deepcopy function, copying the receiver, creating a new $.type2|raw$.\n", intf.Name.Name), argsFromType(t, intf)) + if nonPointerReceiver { + sw.Do(fmt.Sprintf("func (in $.type|raw$) DeepCopy%s() $.type2|raw$ {\n", intf.Name.Name), argsFromType(t, intf)) + sw.Do("return *in.DeepCopy()", nil) + sw.Do("}\n\n", nil) + } else { + 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("}\n", nil) + sw.Do("return nil\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 ut.Kind { + case types.Builtin: + f = g.doBuiltin + case types.Map: + f = g.doMap + case types.Slice: + f = g.doSlice + case types.Struct: + f = g.doStruct + case types.Pointer: + f = g.doPointer + case types.Interface: + // interfaces are handled in-line in the other cases + klog.Fatalf("Hit an interface type %v. This should never happen.", t) + case types.Alias: + // can never happen because we branch on the underlying type which is never an alias + klog.Fatalf("Hit an alias type %v. This should never happen.", t) + default: + klog.Fatalf("Hit an unsupported type %v.", t) + } + 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 + } + + if !ut.Key.IsAssignable() { + klog.Fatalf("Hit an unsupported type %v for: %v", uet, t) + } + + sw.Do("*out = make($.|raw$, len(*in))\n", t) + sw.Do("for key, val := range *in {\n", nil) + dc, dci := deepCopyMethodOrDie(ut.Elem), deepCopyIntoMethodOrDie(ut.Elem) + switch { + case dc != nil || dci != 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) + } + case ut.Elem.IsAnonymousStruct(): // not uet here because it needs type cast + sw.Do("(*out)[key] = val\n", nil) + case uet.IsAssignable(): + sw.Do("(*out)[key] = val\n", nil) + case uet.Kind == types.Interface: + // Note: do not generate code that won't compile as `DeepCopyinterface{}()` is not a valid function + if uet.Name.Name == "interface{}" { + klog.Fatalf("DeepCopy of %q is unsupported. Instead, use named interfaces with DeepCopy as one of the methods.", uet.Name.Name) + } + sw.Do("if val == nil {(*out)[key]=nil} else {\n", nil) + // 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) + case uet.Kind == types.Slice || uet.Kind == types.Map || uet.Kind == types.Pointer: + sw.Do("var outVal $.|raw$\n", uet) + sw.Do("if val == nil { (*out)[key] = nil } else {\n", nil) + sw.Do("in, out := &val, &outVal\n", uet) + g.generateFor(ut.Elem, sw) + sw.Do("}\n", nil) + sw.Do("(*out)[key] = outVal\n", nil) + case uet.Kind == types.Struct: + sw.Do("(*out)[key] = *val.DeepCopy()\n", uet) + default: + klog.Fatalf("Hit an unsupported type %v for %v", uet, t) + } + 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) { + 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 deepCopyMethodOrDie(ut.Elem) != nil || deepCopyIntoMethodOrDie(ut.Elem) != nil { + sw.Do("for i := range *in {\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 uet.Kind == types.Builtin || uet.IsAssignable() { + sw.Do("copy(*out, *in)\n", nil) + } else { + sw.Do("for i := range *in {\n", nil) + if uet.Kind == types.Slice || uet.Kind == types.Map || uet.Kind == types.Pointer || 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(ut.Elem, sw) + sw.Do("}\n", nil) + } else if uet.Kind == types.Interface { + // Note: do not generate code that won't compile as `DeepCopyinterface{}()` is not a valid function + if uet.Name.Name == "interface{}" { + klog.Fatalf("DeepCopy of %q is unsupported. Instead, use named interfaces with DeepCopy as one of the methods.", uet.Name.Name) + } + sw.Do("if (*in)[i] != nil {\n", nil) + // 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 uet.Kind == types.Struct { + sw.Do("(*in)[i].DeepCopyInto(&(*out)[i])\n", nil) + } else { + klog.Fatalf("Hit an unsupported type %v for %v", uet, t) + } + sw.Do("}\n", nil) + } +} + +// 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) { + ut := underlyingType(t) + + if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil { + sw.Do("*out = in.DeepCopy()\n", nil) + return + } + + // Simple copy covers a lot of cases. + sw.Do("*out = *in\n", nil) + + // Now fix-up fields as needed. + for _, m := range ut.Members { + ft := m.Type + uft := underlyingType(ft) + + args := generator.Args{ + "type": ft, + "kind": ft.Kind, + "name": m.Name, + } + 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 + } + if leftPointer == rightPointer { + sw.Do("out.$.name$ = in.$.name$.DeepCopy()\n", args) + } else if leftPointer { + sw.Do("x := in.$.name$.DeepCopy()\n", args) + sw.Do("out.$.name$ = = &x\n", args) + } else { + sw.Do("in.$.name$.DeepCopyInto(&out.$.name$)\n", args) + } + 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.Array: + sw.Do("out.$.name$ = in.$.name$\n", args) + 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 uft.Kind == types.Interface: + // Note: do not generate code that won't compile as `DeepCopyinterface{}()` is not a valid function + if uft.Name.Name == "interface{}" { + klog.Fatalf("DeepCopy of %q is unsupported. Instead, use named interfaces with DeepCopy as one of the methods.", uft.Name.Name) + } + sw.Do("if in.$.name$ != nil {\n", 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: + klog.Fatalf("Hit an unsupported type '%v' for '%v', from %v.%v", uft, ft, t, m.Name) + } + } +} + +// 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) + + dc, dci := deepCopyMethodOrDie(ut.Elem), deepCopyIntoMethodOrDie(ut.Elem) + switch { + case 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) + } + case uet.IsAssignable(): + sw.Do("*out = new($.Elem|raw$)\n", ut) + sw.Do("**out = **in", nil) + case uet.Kind == types.Map, uet.Kind == types.Slice, uet.Kind == types.Pointer: + 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(uet, sw) + sw.Do("}\n", nil) + case uet.Kind == types.Struct: + sw.Do("*out = new($.Elem|raw$)\n", ut) + sw.Do("(*in).DeepCopyInto(*out)\n", nil) + default: + klog.Fatalf("Hit an unsupported type %v for %v", uet, t) + } +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/generators/deepcopy_test.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/generators/deepcopy_test.go new file mode 100644 index 00000000000..7a42eecd5e2 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/generators/deepcopy_test.go @@ -0,0 +1,666 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package generators + +import ( + "reflect" + "testing" + + "k8s.io/gengo/v2/types" +) + +func Test_deepCopyMethod(t *testing.T) { + testCases := []struct { + typ types.Type + expect bool + error bool + }{ + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + // No DeepCopy method. + Methods: map[string]*types.Type{}, + }, + expect: false, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // No DeepCopy method. + "method": { + Name: types.Name{Package: "pkgname", Name: "func()"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{}, + Results: []*types.Type{}, + }, + }, + }, + }, + expect: false, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (no result). + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func()"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{}, + Results: []*types.Type{}, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (wrong result). + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func() int"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{}, + Results: []*types.Type{ + { + Name: types.Name{Name: "int"}, + Kind: types.Builtin, + }, + }, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature with pointer receiver, but non-pointer result. + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{}, + Results: []*types.Type{ + { + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + }, + }, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature with non-pointer receiver, but pointer result. + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + Parameters: []*types.Type{}, + Results: []*types.Type{ + { + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + }, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Correct signature with non-pointer receiver. + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + Parameters: []*types.Type{}, + Results: []*types.Type{ + { + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + }, + }, + }, + }, + }, + }, + expect: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Correct signature with pointer receiver. + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{}, + Results: []*types.Type{ + { + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + }, + }, + }, + }, + }, + expect: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (has params). + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func(int) pkgname.typename"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{ + { + Name: types.Name{Name: "int"}, + Kind: types.Builtin, + }, + }, + Results: []*types.Type{ + { + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + }, + }, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (extra results). + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func() (pkgname.typename, int)"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{}, + Results: []*types.Type{ + { + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + }, + { + Name: types.Name{Name: "int"}, + Kind: types.Builtin, + }, + }, + }, + }, + }, + }, + expect: false, + error: true, + }, + } + + for i, tc := range testCases { + r, err := deepCopyMethod(&tc.typ) + if tc.error && err == nil { + t.Errorf("case[%d]: expected an error, got none", i) + } else if !tc.error && err != nil { + t.Errorf("case[%d]: expected no error, got: %v", i, err) + } else if !tc.error && (r != nil) != tc.expect { + t.Errorf("case[%d]: expected result %v, got: %v", i, tc.expect, r) + } + } +} + +func Test_deepCopyIntoMethod(t *testing.T) { + testCases := []struct { + typ types.Type + expect bool + error bool + }{ + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + // No DeepCopyInto method. + Methods: map[string]*types.Type{}, + }, + expect: false, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // No DeepCopyInto method. + "method": { + Name: types.Name{Package: "pkgname", Name: "func()"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{}, + Results: []*types.Type{}, + }, + }, + }, + }, + expect: false, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (no parameter). + "DeepCopyInto": { + Name: types.Name{Package: "pkgname", Name: "func()"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{}, + Results: []*types.Type{}, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (unexpected result). + "DeepCopyInto": { + Name: types.Name{Package: "pkgname", Name: "func(*pkgname.typename) int"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{ + { + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + }, + Results: []*types.Type{ + { + Name: types.Name{Name: "int"}, + Kind: types.Builtin, + }, + }, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (non-pointer parameter, pointer receiver). + "DeepCopyInto": { + Name: types.Name{Package: "pkgname", Name: "func(pkgname.typename)"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{ + {Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Results: []*types.Type{}, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (non-pointer parameter, non-pointer receiver). + "DeepCopyInto": { + Name: types.Name{Package: "pkgname", Name: "func(pkgname.typename)"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + Parameters: []*types.Type{ + {Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Results: []*types.Type{}, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Correct signature with non-pointer receiver. + "DeepCopyInto": { + Name: types.Name{Package: "pkgname", Name: "func(*pkgname.typename)"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + Parameters: []*types.Type{ + { + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + }, + Results: []*types.Type{}, + }, + }, + }, + }, + expect: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Correct signature with pointer receiver. + "DeepCopyInto": { + Name: types.Name{Package: "pkgname", Name: "func(*pkgname.typename)"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.Type{ + { + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + }, + Results: []*types.Type{}, + }, + }, + }, + }, + expect: true, + }, + } + + for i, tc := range testCases { + r, err := deepCopyIntoMethod(&tc.typ) + if tc.error && err == nil { + t.Errorf("case[%d]: expected an error, got none", i) + } else if !tc.error && err != nil { + t.Errorf("case[%d]: expected no error, got: %v", i, err) + } else if !tc.error && (r != nil) != tc.expect { + t.Errorf("case[%d]: expected result %v, got: %v", i, tc.expect, r) + } + } +} + +func Test_extractTagParams(t *testing.T) { + testCases := []struct { + comments []string + expect *enabledTagValue + }{ + { + comments: []string{ + "Human comment", + }, + expect: nil, + }, + { + comments: []string{ + "Human comment", + "+k8s:deepcopy-gen", + }, + expect: &enabledTagValue{ + value: "", + register: false, + }, + }, + { + comments: []string{ + "Human comment", + "+k8s:deepcopy-gen=package", + }, + expect: &enabledTagValue{ + value: "package", + register: false, + }, + }, + { + comments: []string{ + "Human comment", + "+k8s:deepcopy-gen=package,register", + }, + expect: &enabledTagValue{ + value: "package", + register: true, + }, + }, + { + comments: []string{ + "Human comment", + "+k8s:deepcopy-gen=package,register=true", + }, + expect: &enabledTagValue{ + value: "package", + register: true, + }, + }, + { + comments: []string{ + "Human comment", + "+k8s:deepcopy-gen=package,register=false", + }, + expect: &enabledTagValue{ + value: "package", + register: false, + }, + }, + } + + for i, tc := range testCases { + r := extractEnabledTag(tc.comments) + if r == nil && tc.expect != nil { + t.Errorf("case[%d]: expected non-nil", i) + } + if r != nil && tc.expect == nil { + t.Errorf("case[%d]: expected nil, got %v", i, *r) + } + if r != nil && *r != *tc.expect { + t.Errorf("case[%d]: expected %v, got %v", i, *tc.expect, *r) + } + } +} + +func Test_extractInterfacesTag(t *testing.T) { + testCases := []struct { + comments, secondComments []string + expect []string + }{ + { + comments: []string{}, + expect: nil, + }, + { + comments: []string{ + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", + }, + expect: []string{ + "k8s.io/kubernetes/runtime.Object", + }, + }, + { + comments: []string{ + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.List", + }, + expect: []string{ + "k8s.io/kubernetes/runtime.Object", + "k8s.io/kubernetes/runtime.List", + }, + }, + { + comments: []string{ + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", + }, + expect: []string{ + "k8s.io/kubernetes/runtime.Object", + "k8s.io/kubernetes/runtime.Object", + }, + }, + { + secondComments: []string{ + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", + }, + expect: []string{ + "k8s.io/kubernetes/runtime.Object", + }, + }, + { + comments: []string{ + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", + }, + secondComments: []string{ + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.List", + }, + expect: []string{ + "k8s.io/kubernetes/runtime.List", + "k8s.io/kubernetes/runtime.Object", + }, + }, + { + comments: []string{ + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", + }, + secondComments: []string{ + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", + }, + expect: []string{ + "k8s.io/kubernetes/runtime.Object", + "k8s.io/kubernetes/runtime.Object", + }, + }, + } + + for i, tc := range testCases { + typ := &types.Type{ + CommentLines: tc.comments, + SecondClosestCommentLines: tc.secondComments, + } + r := extractInterfacesTag(typ) + if r == nil && tc.expect != nil { + t.Errorf("case[%d]: expected non-nil", i) + } + if r != nil && tc.expect == nil { + t.Errorf("case[%d]: expected nil, got %v", i, r) + } + if r != nil && !reflect.DeepEqual(r, tc.expect) { + t.Errorf("case[%d]: expected %v, got %v", i, tc.expect, r) + } + } +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/main.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/main.go index 0cb3bd3f79e..23bdf5d50af 100644 --- a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/main.go +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/main.go @@ -16,14 +16,24 @@ limitations under the License. // deepcopy-gen is a tool for auto-generating DeepCopy functions. // -// Given a list of input directories, it will generate functions that -// efficiently perform a full deep-copy of each type. For any type that -// offers a `.DeepCopy()` method, it will simply call that. Otherwise it will -// use standard value assignment whenever possible. If that is not possible it -// will try to call its own generated copy function for the type, if the type is -// within the allowed root packages. Failing that, it will fall back on -// `conversion.Cloner.DeepCopy(val)` to make the copy. The resulting file will -// be stored in the same directory as the processed source package. +// Given a list of input directories, it will generate DeepCopy and +// DeepCopyInto methods that efficiently perform a full deep-copy of each type. +// If these methods already exist (are predefined by the developer), they are +// used instead of generating new ones. Generated code will use standard value +// assignment whenever possible. If that is not possible it will try to call +// its own generated copy function for the type. Failing that, it will fall +// back on `conversion.Cloner.DeepCopy(val)` to make the copy. The resulting +// file will be stored in the same directory as the processed source package. +// +// If interfaces are referenced in types, it is expected that corresponding +// DeepCopyInterfaceName methods exist, e.g. DeepCopyObject for runtime.Object. +// These can be predefined by the developer or generated through tags, see +// below. They must be added to the interfaces themselves manually, e.g. +// +// type Object interface { +// ... +// DeepCopyObject() Object +// } // // Generation is governed by comment tags in the source. Any package may // request DeepCopy generation by including a comment in the file-comments of @@ -32,17 +42,30 @@ limitations under the License. // // +k8s:deepcopy-gen=package // // DeepCopy functions can be generated for individual types, rather than the -// entire package by specifying a comment on the type definion of the form: +// entire package by specifying a comment on the type definition of the form: // // // +k8s:deepcopy-gen=true // // When generating for a whole package, individual types may opt out of -// DeepCopy generation by specifying a comment on the of the form: +// DeepCopy generation by specifying a comment on the type definition of the +// form: // // // +k8s:deepcopy-gen=false // -// Note that registration is a whole-package option, and is not available for -// individual types. +// Additional DeepCopyInterfaceName methods can be generated by specifying a +// comment on the type definition of the form: +// +// // +k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object,k8s.io/kubernetes/runtime.List +// +// This leads to the generation of DeepCopyObject and DeepCopyList with the given +// interfaces as return types. We say that the tagged type implements deepcopy for the +// interfaces. +// +// The deepcopy funcs for interfaces using "+k8s:deepcopy-gen:interfaces" use the pointer +// of the type as receiver. For those special cases where the non-pointer object should +// implement the interface, this can be done with: +// +// // +k8s:deepcopy-gen:nonpointer-interfaces=true package main import ( @@ -50,8 +73,8 @@ import ( "github.com/spf13/pflag" generatorargs "k8s.io/code-generator/cmd/deepcopy-gen/args" + "k8s.io/code-generator/cmd/deepcopy-gen/generators" "k8s.io/gengo/v2/args" - "k8s.io/gengo/v2/examples/deepcopy-gen/generators" "k8s.io/klog/v2" ) diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/aliases/doc.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/aliases/doc.go new file mode 100644 index 00000000000..d007d34f784 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/aliases/doc.go @@ -0,0 +1,89 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package + +// This is a test package. +package aliases + +// Note: the following AliasInterface and AliasAliasInterface +k8s:deepcopy-gen:interfaces tags +// are necessary because Golang flattens interface alias in the type system. I.e. an alias J of +// an interface I is actually equivalent to I. So support deepcopies of those aliases, we have +// to implement all aliases of that interface. + +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/aliases.Interface +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/aliases.AliasInterface +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/aliases.AliasAliasInterface +type Foo struct { + X int +} + +type Interface interface { + DeepCopyInterface() Interface + DeepCopyAliasInterface() AliasInterface + DeepCopyAliasAliasInterface() AliasAliasInterface +} + +type Builtin int +type Slice []int +type Pointer *int +type PointerAlias *Builtin +type Struct Foo +type Map map[string]int + +type FooAlias Foo +type FooSlice []Foo +type FooPointer *Foo +type FooMap map[string]Foo + +type AliasBuiltin Builtin +type AliasSlice Slice +type AliasPointer Pointer +type AliasStruct Struct +type AliasMap Map + +type AliasInterface Interface +type AliasAliasInterface AliasInterface +type AliasInterfaceMap map[string]AliasInterface +type AliasInterfaceSlice []AliasInterface + +// Aliases +type Ttest struct { + Builtin Builtin + Slice Slice + Pointer Pointer + PointerAlias PointerAlias + Struct Struct + Map Map + SliceSlice []Slice + MapSlice map[string]Slice + + FooAlias FooAlias + FooSlice FooSlice + FooPointer FooPointer + FooMap FooMap + + AliasBuiltin AliasBuiltin + AliasSlice AliasSlice + AliasPointer AliasPointer + AliasStruct AliasStruct + AliasMap AliasMap + + AliasInterface AliasInterface + AliasAliasInterface AliasAliasInterface + AliasInterfaceMap AliasInterfaceMap + AliasInterfaceSlice AliasInterfaceSlice +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/aliases/zz_generated.deepcopy.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/aliases/zz_generated.deepcopy.go new file mode 100644 index 00000000000..e7c6827f02c --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/aliases/zz_generated.deepcopy.go @@ -0,0 +1,413 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package aliases + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in AliasInterfaceMap) DeepCopyInto(out *AliasInterfaceMap) { + { + in := &in + *out = make(AliasInterfaceMap, len(*in)) + for key, val := range *in { + if val == nil { + (*out)[key] = nil + } else { + (*out)[key] = val.DeepCopyAliasInterface() + } + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AliasInterfaceMap. +func (in AliasInterfaceMap) DeepCopy() AliasInterfaceMap { + if in == nil { + return nil + } + out := new(AliasInterfaceMap) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in AliasInterfaceSlice) DeepCopyInto(out *AliasInterfaceSlice) { + { + in := &in + *out = make(AliasInterfaceSlice, len(*in)) + for i := range *in { + if (*in)[i] != nil { + (*out)[i] = (*in)[i].DeepCopyAliasInterface() + } + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AliasInterfaceSlice. +func (in AliasInterfaceSlice) DeepCopy() AliasInterfaceSlice { + if in == nil { + return nil + } + out := new(AliasInterfaceSlice) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in AliasMap) DeepCopyInto(out *AliasMap) { + { + in := &in + *out = make(AliasMap, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AliasMap. +func (in AliasMap) DeepCopy() AliasMap { + if in == nil { + return nil + } + out := new(AliasMap) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in AliasSlice) DeepCopyInto(out *AliasSlice) { + { + in := &in + *out = make(AliasSlice, len(*in)) + copy(*out, *in) + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AliasSlice. +func (in AliasSlice) DeepCopy() AliasSlice { + if in == nil { + return nil + } + out := new(AliasSlice) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AliasStruct) DeepCopyInto(out *AliasStruct) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AliasStruct. +func (in *AliasStruct) DeepCopy() *AliasStruct { + if in == nil { + return nil + } + out := new(AliasStruct) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Foo) DeepCopyInto(out *Foo) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Foo. +func (in *Foo) DeepCopy() *Foo { + if in == nil { + return nil + } + out := new(Foo) + in.DeepCopyInto(out) + return out +} + +// DeepCopyAliasAliasInterface is an autogenerated deepcopy function, copying the receiver, creating a new AliasAliasInterface. +func (in *Foo) DeepCopyAliasAliasInterface() AliasAliasInterface { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyAliasInterface is an autogenerated deepcopy function, copying the receiver, creating a new AliasInterface. +func (in *Foo) DeepCopyAliasInterface() AliasInterface { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new Interface. +func (in *Foo) DeepCopyInterface() Interface { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FooAlias) DeepCopyInto(out *FooAlias) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FooAlias. +func (in *FooAlias) DeepCopy() *FooAlias { + if in == nil { + return nil + } + out := new(FooAlias) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in FooMap) DeepCopyInto(out *FooMap) { + { + in := &in + *out = make(FooMap, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FooMap. +func (in FooMap) DeepCopy() FooMap { + if in == nil { + return nil + } + out := new(FooMap) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in FooSlice) DeepCopyInto(out *FooSlice) { + { + in := &in + *out = make(FooSlice, len(*in)) + copy(*out, *in) + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FooSlice. +func (in FooSlice) DeepCopy() FooSlice { + if in == nil { + return nil + } + out := new(FooSlice) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in Map) DeepCopyInto(out *Map) { + { + in := &in + *out = make(Map, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Map. +func (in Map) DeepCopy() Map { + if in == nil { + return nil + } + out := new(Map) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in Slice) DeepCopyInto(out *Slice) { + { + in := &in + *out = make(Slice, len(*in)) + copy(*out, *in) + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Slice. +func (in Slice) DeepCopy() Slice { + if in == nil { + return nil + } + out := new(Slice) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Struct) DeepCopyInto(out *Struct) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct. +func (in *Struct) DeepCopy() *Struct { + if in == nil { + return nil + } + out := new(Struct) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Ttest) DeepCopyInto(out *Ttest) { + *out = *in + if in.Slice != nil { + in, out := &in.Slice, &out.Slice + *out = make(Slice, len(*in)) + copy(*out, *in) + } + if in.Pointer != nil { + in, out := &in.Pointer, &out.Pointer + *out = new(int) + **out = **in + } + if in.PointerAlias != nil { + in, out := &in.PointerAlias, &out.PointerAlias + *out = new(Builtin) + **out = **in + } + out.Struct = in.Struct + if in.Map != nil { + in, out := &in.Map, &out.Map + *out = make(Map, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.SliceSlice != nil { + in, out := &in.SliceSlice, &out.SliceSlice + *out = make([]Slice, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = make(Slice, len(*in)) + copy(*out, *in) + } + } + } + if in.MapSlice != nil { + in, out := &in.MapSlice, &out.MapSlice + *out = make(map[string]Slice, len(*in)) + for key, val := range *in { + var outVal []int + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = make(Slice, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal + } + } + out.FooAlias = in.FooAlias + if in.FooSlice != nil { + in, out := &in.FooSlice, &out.FooSlice + *out = make(FooSlice, len(*in)) + copy(*out, *in) + } + if in.FooPointer != nil { + in, out := &in.FooPointer, &out.FooPointer + *out = new(Foo) + **out = **in + } + if in.FooMap != nil { + in, out := &in.FooMap, &out.FooMap + *out = make(FooMap, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.AliasSlice != nil { + in, out := &in.AliasSlice, &out.AliasSlice + *out = make(AliasSlice, len(*in)) + copy(*out, *in) + } + if in.AliasPointer != nil { + in, out := &in.AliasPointer, &out.AliasPointer + *out = new(int) + **out = **in + } + out.AliasStruct = in.AliasStruct + if in.AliasMap != nil { + in, out := &in.AliasMap, &out.AliasMap + *out = make(AliasMap, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.AliasInterface != nil { + out.AliasInterface = in.AliasInterface.DeepCopyAliasInterface() + } + if in.AliasAliasInterface != nil { + out.AliasAliasInterface = in.AliasAliasInterface.DeepCopyAliasAliasInterface() + } + if in.AliasInterfaceMap != nil { + in, out := &in.AliasInterfaceMap, &out.AliasInterfaceMap + *out = make(AliasInterfaceMap, len(*in)) + for key, val := range *in { + if val == nil { + (*out)[key] = nil + } else { + (*out)[key] = val.DeepCopyAliasInterface() + } + } + } + if in.AliasInterfaceSlice != nil { + in, out := &in.AliasInterfaceSlice, &out.AliasInterfaceSlice + *out = make(AliasInterfaceSlice, len(*in)) + for i := range *in { + if (*in)[i] != nil { + (*out)[i] = (*in)[i].DeepCopyAliasInterface() + } + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest. +func (in *Ttest) DeepCopy() *Ttest { + if in == nil { + return nil + } + out := new(Ttest) + in.DeepCopyInto(out) + return out +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/builtins/doc.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/builtins/doc.go new file mode 100644 index 00000000000..34097c84dfa --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/builtins/doc.go @@ -0,0 +1,35 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package + +// This is a test package. +package builtins + +type Ttest struct { + Byte byte + // Int8 int8 // TODO: int8 becomes byte in SnippetWriter + Int16 int16 + Int32 int32 + Int64 int64 + Uint8 uint8 + Uint16 uint16 + Uint32 uint32 + Uint64 uint64 + Float32 float32 + Float64 float64 + String string +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/builtins/zz_generated.deepcopy.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/builtins/zz_generated.deepcopy.go new file mode 100644 index 00000000000..afc71ffb071 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/builtins/zz_generated.deepcopy.go @@ -0,0 +1,38 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package builtins + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Ttest) DeepCopyInto(out *Ttest) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest. +func (in *Ttest) DeepCopy() *Ttest { + if in == nil { + return nil + } + out := new(Ttest) + in.DeepCopyInto(out) + return out +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/generate.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/generate.go new file mode 100644 index 00000000000..9ae99ee9ba2 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/generate.go @@ -0,0 +1,18 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +//go:generate go run k8s.io/code-generator/cmd/deepcopy-gen --output-file zz_generated.deepcopy.go --go-header-file=../../../examples/hack/boilerplate.go.txt k8s.io/code-generator/cmd/deepcopy-gen/output_tests/... +package outputtests diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/interface_fuzzer.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/interface_fuzzer.go new file mode 100644 index 00000000000..11fdb84bff8 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/interface_fuzzer.go @@ -0,0 +1,131 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package outputtests + +import ( + "github.com/google/gofuzz" + + "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/aliases" + "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/interfaces" +) + +// interfaceFuzzers contains fuzzer that set all interface to nil because our +// JSON deepcopy does not work with it. +// TODO: test also interface deepcopy +var interfaceFuzzers = []interface{}{ + func(s *aliases.AliasAliasInterface, c fuzz.Continue) { + if c.RandBool() { + *s = nil + } else { + *s = &aliasAliasInterfaceInstance{X: c.Int()} + } + }, + func(s *aliases.AliasInterface, c fuzz.Continue) { + if c.RandBool() { + *s = nil + } else { + *s = &aliasAliasInterfaceInstance{X: c.Int()} + } + }, + func(s *aliases.Interface, c fuzz.Continue) { + if c.RandBool() { + *s = nil + } else { + *s = &aliasAliasInterfaceInstance{X: c.Int()} + } + }, + func(s *aliases.AliasInterfaceMap, c fuzz.Continue) { + if c.RandBool() { + *s = nil + } else { + *s = make(aliases.AliasInterfaceMap) + for i := 0; i < c.Intn(3); i++ { + if c.RandBool() { + (*s)[c.RandString()] = nil + } else { + (*s)[c.RandString()] = &aliasAliasInterfaceInstance{X: c.Int()} + } + } + } + + }, + func(s *aliases.AliasInterfaceSlice, c fuzz.Continue) { + if c.RandBool() { + *s = nil + } else { + *s = make(aliases.AliasInterfaceSlice, 0) + for i := 0; i < c.Intn(3); i++ { + if c.RandBool() { + *s = append(*s, nil) + } else { + *s = append(*s, &aliasAliasInterfaceInstance{X: c.Int()}) + } + } + } + }, + func(s *interfaces.Inner, c fuzz.Continue) { + if c.RandBool() { + *s = nil + } else { + *s = &interfacesInnerInstance{X: c.Float64()} + } + }, +} + +type aliasAliasInterfaceInstance struct { + X int +} + +func (i *aliasAliasInterfaceInstance) DeepCopyInterface() aliases.Interface { + if i == nil { + return nil + } + + return &aliasAliasInterfaceInstance{X: i.X} +} + +func (i *aliasAliasInterfaceInstance) DeepCopyAliasInterface() aliases.AliasInterface { + if i == nil { + return nil + } + + return &aliasAliasInterfaceInstance{X: i.X} +} + +func (i *aliasAliasInterfaceInstance) DeepCopyAliasAliasInterface() aliases.AliasAliasInterface { + if i == nil { + return nil + } + + return &aliasAliasInterfaceInstance{X: i.X} +} + +type interfacesInnerInstance struct { + X float64 +} + +func (i *interfacesInnerInstance) DeepCopyInner() interfaces.Inner { + if i == nil { + return nil + } + + return &interfacesInnerInstance{X: i.X} +} + +func (i *interfacesInnerInstance) Function() float64 { + return i.X +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/interfaces/doc.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/interfaces/doc.go new file mode 100644 index 00000000000..2d01f2e601f --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/interfaces/doc.go @@ -0,0 +1,29 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package + +// This is a test package. +package interfaces + +type Inner interface { + Function() float64 + DeepCopyInner() Inner +} + +type Ttest struct { + I []Inner +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/interfaces/zz_generated.deepcopy.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/interfaces/zz_generated.deepcopy.go new file mode 100644 index 00000000000..abaa51b163d --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/interfaces/zz_generated.deepcopy.go @@ -0,0 +1,47 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package interfaces + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Ttest) DeepCopyInto(out *Ttest) { + *out = *in + if in.I != nil { + in, out := &in.I, &out.I + *out = make([]Inner, len(*in)) + for i := range *in { + if (*in)[i] != nil { + (*out)[i] = (*in)[i].DeepCopyInner() + } + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest. +func (in *Ttest) DeepCopy() *Ttest { + if in == nil { + return nil + } + out := new(Ttest) + in.DeepCopyInto(out) + return out +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/maps/doc.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/maps/doc.go new file mode 100644 index 00000000000..01871e44d43 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/maps/doc.go @@ -0,0 +1,43 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package + +// This is a test package. +package maps + +type Ttest struct { + Byte map[string]byte + // Int8 map[string]int8 //TODO: int8 becomes byte in SnippetWriter + Int16 map[string]int16 + Int32 map[string]int32 + Int64 map[string]int64 + Uint8 map[string]uint8 + Uint16 map[string]uint16 + Uint32 map[string]uint32 + Uint64 map[string]uint64 + Float32 map[string]float32 + Float64 map[string]float64 + String map[string]string + StringPtr map[string]*string + StringPtrPtr map[string]**string + Map map[string]map[string]string + MapPtr map[string]*map[string]string + Slice map[string][]string + SlicePtr map[string]*[]string + Struct map[string]Ttest + StructPtr map[string]*Ttest +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/maps/zz_generated.deepcopy.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/maps/zz_generated.deepcopy.go new file mode 100644 index 00000000000..77103245a74 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/maps/zz_generated.deepcopy.go @@ -0,0 +1,243 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package maps + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Ttest) DeepCopyInto(out *Ttest) { + *out = *in + if in.Byte != nil { + in, out := &in.Byte, &out.Byte + *out = make(map[string]byte, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Int16 != nil { + in, out := &in.Int16, &out.Int16 + *out = make(map[string]int16, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Int32 != nil { + in, out := &in.Int32, &out.Int32 + *out = make(map[string]int32, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Int64 != nil { + in, out := &in.Int64, &out.Int64 + *out = make(map[string]int64, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Uint8 != nil { + in, out := &in.Uint8, &out.Uint8 + *out = make(map[string]byte, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Uint16 != nil { + in, out := &in.Uint16, &out.Uint16 + *out = make(map[string]uint16, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Uint32 != nil { + in, out := &in.Uint32, &out.Uint32 + *out = make(map[string]uint32, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Uint64 != nil { + in, out := &in.Uint64, &out.Uint64 + *out = make(map[string]uint64, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Float32 != nil { + in, out := &in.Float32, &out.Float32 + *out = make(map[string]float32, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Float64 != nil { + in, out := &in.Float64, &out.Float64 + *out = make(map[string]float64, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.String != nil { + in, out := &in.String, &out.String + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.StringPtr != nil { + in, out := &in.StringPtr, &out.StringPtr + *out = make(map[string]*string, len(*in)) + for key, val := range *in { + var outVal *string + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new(string) + **out = **in + } + (*out)[key] = outVal + } + } + if in.StringPtrPtr != nil { + in, out := &in.StringPtrPtr, &out.StringPtrPtr + *out = make(map[string]**string, len(*in)) + for key, val := range *in { + var outVal **string + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new(*string) + if **in != nil { + in, out := *in, *out + *out = new(string) + **out = **in + } + } + (*out)[key] = outVal + } + } + if in.Map != nil { + in, out := &in.Map, &out.Map + *out = make(map[string]map[string]string, len(*in)) + for key, val := range *in { + var outVal map[string]string + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + (*out)[key] = outVal + } + } + if in.MapPtr != nil { + in, out := &in.MapPtr, &out.MapPtr + *out = make(map[string]*map[string]string, len(*in)) + for key, val := range *in { + var outVal *map[string]string + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new(map[string]string) + if **in != nil { + in, out := *in, *out + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + } + (*out)[key] = outVal + } + } + if in.Slice != nil { + in, out := &in.Slice, &out.Slice + *out = make(map[string][]string, len(*in)) + for key, val := range *in { + var outVal []string + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = make([]string, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal + } + } + if in.SlicePtr != nil { + in, out := &in.SlicePtr, &out.SlicePtr + *out = make(map[string]*[]string, len(*in)) + for key, val := range *in { + var outVal *[]string + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new([]string) + if **in != nil { + in, out := *in, *out + *out = make([]string, len(*in)) + copy(*out, *in) + } + } + (*out)[key] = outVal + } + } + if in.Struct != nil { + in, out := &in.Struct, &out.Struct + *out = make(map[string]Ttest, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + if in.StructPtr != nil { + in, out := &in.StructPtr, &out.StructPtr + *out = make(map[string]*Ttest, len(*in)) + for key, val := range *in { + var outVal *Ttest + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new(Ttest) + (*in).DeepCopyInto(*out) + } + (*out)[key] = outVal + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest. +func (in *Ttest) DeepCopy() *Ttest { + if in == nil { + return nil + } + out := new(Ttest) + in.DeepCopyInto(out) + return out +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/otherpkg/interfaces.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/otherpkg/interfaces.go new file mode 100644 index 00000000000..980fab01318 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/otherpkg/interfaces.go @@ -0,0 +1,25 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package otherpkg + +type Object interface { + DeepCopyObject() Object +} + +type List interface { + DeepCopyList() List +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/output_test.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/output_test.go new file mode 100644 index 00000000000..6b899496334 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/output_test.go @@ -0,0 +1,173 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package outputtests + +import ( + "fmt" + "reflect" + "testing" + + "github.com/davecgh/go-spew/spew" + "github.com/google/gofuzz" + + "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/aliases" + "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/builtins" + "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/interfaces" + "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/maps" + "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/pointer" + "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/slices" + "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/structs" +) + +func TestWithValueFuzzer(t *testing.T) { + tests := []interface{}{ + aliases.Ttest{}, + builtins.Ttest{}, + interfaces.Ttest{}, + maps.Ttest{}, + pointer.Ttest{}, + slices.Ttest{}, + structs.Ttest{}, + } + + fuzzer := fuzz.New() + fuzzer.NilChance(0.5) + fuzzer.NumElements(0, 2) + fuzzer.Funcs(interfaceFuzzers...) + + for _, test := range tests { + t.Run(fmt.Sprintf("%T", test), func(t *testing.T) { + N := 1000 + for i := 0; i < N; i++ { + original := reflect.New(reflect.TypeOf(test)).Interface() + + fuzzer.Fuzz(original) + + reflectCopy := ReflectDeepCopy(original) + + if !reflect.DeepEqual(original, reflectCopy) { + t.Errorf("original and reflectCopy are different:\n\n original = %s\n\n jsonCopy = %s", spew.Sdump(original), spew.Sdump(reflectCopy)) + } + + deepCopy := reflect.ValueOf(original).MethodByName("DeepCopy").Call(nil)[0].Interface() + + if !reflect.DeepEqual(original, deepCopy) { + t.Fatalf("original and deepCopy are different:\n\n original = %s\n\n deepCopy() = %s", spew.Sdump(original), spew.Sdump(deepCopy)) + } + + ValueFuzz(original) + + if !reflect.DeepEqual(reflectCopy, deepCopy) { + t.Fatalf("reflectCopy and deepCopy are different:\n\n origin = %s\n\n jsonCopy() = %s", spew.Sdump(original), spew.Sdump(deepCopy)) + } + } + }) + } +} + +func BenchmarkReflectDeepCopy(b *testing.B) { + fourtytwo := "fourtytwo" + fourtytwoPtr := &fourtytwo + var nilMap map[string]string + var nilSlice []string + mapPtr := &map[string]string{"0": "fourtytwo", "1": "fourtytwo"} + slicePtr := &[]string{"fourtytwo", "fourtytwo", "fourtytwo"} + structPtr := &pointer.Ttest{ + Builtin: &fourtytwo, + Ptr: &fourtytwoPtr, + } + + tests := []interface{}{ + maps.Ttest{ + Byte: map[string]byte{"0": 42, "1": 42, "3": 42}, + Int16: map[string]int16{"0": 42, "1": 42, "3": 42}, + Int32: map[string]int32{"0": 42, "1": 42, "3": 42}, + Int64: map[string]int64{"0": 42, "1": 42, "3": 42}, + Uint8: map[string]uint8{"0": 42, "1": 42, "3": 42}, + Uint16: map[string]uint16{"0": 42, "1": 42, "3": 42}, + Uint32: map[string]uint32{"0": 42, "1": 42, "3": 42}, + Uint64: map[string]uint64{"0": 42, "1": 42, "3": 42}, + Float32: map[string]float32{"0": 42.0, "1": 42.0, "3": 42.0}, + Float64: map[string]float64{"0": 42, "1": 42, "3": 42}, + String: map[string]string{"0": "fourtytwo", "1": "fourtytwo", "3": "fourtytwo"}, + StringPtr: map[string]*string{"0": &fourtytwo, "1": &fourtytwo, "3": &fourtytwo}, + StringPtrPtr: map[string]**string{"0": &fourtytwoPtr, "1": &fourtytwoPtr, "3": &fourtytwoPtr}, + Map: map[string]map[string]string{"0": nil, "1": {"a": fourtytwo, "b": fourtytwo}, "3": {}}, + MapPtr: map[string]*map[string]string{"0": nil, "1": {"a": fourtytwo, "b": fourtytwo}, "3": &nilMap}, + Slice: map[string][]string{"0": nil, "1": {"a", "b"}, "2": {}}, + SlicePtr: map[string]*[]string{"0": nil, "1": {"a", "b"}, "2": &nilSlice}, + Struct: map[string]maps.Ttest{"0": {}, "1": {Byte: map[string]byte{"0": 42, "1": 42, "3": 42}}}, + StructPtr: map[string]*maps.Ttest{"0": nil, "1": {}, "2": {Byte: map[string]byte{"0": 42, "1": 42, "3": 42}}}, + }, + slices.Ttest{ + Byte: []byte{42, 42, 42}, + Int16: []int16{42, 42, 42}, + Int32: []int32{42, 42, 42}, + Int64: []int64{42, 42, 42}, + Uint8: []uint8{42, 42, 42}, + Uint16: []uint16{42, 42, 42}, + Uint32: []uint32{42, 42, 42}, + Uint64: []uint64{42, 42, 42}, + Float32: []float32{42.0, 42.0, 42.0}, + Float64: []float64{42, 42, 42}, + String: []string{"fourtytwo", "fourtytwo", "fourtytwo"}, + StringPtr: []*string{&fourtytwo, &fourtytwo, &fourtytwo}, + StringPtrPtr: []**string{&fourtytwoPtr, &fourtytwoPtr, &fourtytwoPtr}, + Map: []map[string]string{nil, {"a": fourtytwo, "b": fourtytwo}, {}}, + MapPtr: []*map[string]string{nil, {"a": fourtytwo, "b": fourtytwo}, &nilMap}, + Slice: [][]string{nil, {"a", "b"}, {}}, + SlicePtr: []*[]string{nil, {"a", "b"}, &nilSlice}, + Struct: []slices.Ttest{{}, {Byte: []byte{42, 42, 42}}}, + StructPtr: []*slices.Ttest{nil, {}, {Byte: []byte{42, 42, 42}}}, + }, + pointer.Ttest{ + Builtin: &fourtytwo, + Ptr: &fourtytwoPtr, + Map: &map[string]string{"0": "fourtytwo", "1": "fourtytwo"}, + Slice: &[]string{"fourtytwo", "fourtytwo", "fourtytwo"}, + MapPtr: &mapPtr, + SlicePtr: &slicePtr, + Struct: &pointer.Ttest{ + Builtin: &fourtytwo, + Ptr: &fourtytwoPtr, + }, + StructPtr: &structPtr, + }, + } + + fuzzer := fuzz.New() + fuzzer.NilChance(0.5) + fuzzer.NumElements(0, 2) + fuzzer.Funcs(interfaceFuzzers...) + + for _, test := range tests { + b.Run(fmt.Sprintf("%T", test), func(b *testing.B) { + for i := 0; i < b.N; i++ { + switch t := test.(type) { + case maps.Ttest: + t.DeepCopy() + case slices.Ttest: + t.DeepCopy() + case pointer.Ttest: + t.DeepCopy() + default: + b.Fatalf("missing type case in switch for %T", t) + } + } + }) + } +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/pointer/doc.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/pointer/doc.go new file mode 100644 index 00000000000..fd461101b14 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/pointer/doc.go @@ -0,0 +1,31 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package + +// This is a test package. +package pointer + +type Ttest struct { + Builtin *string + Ptr **string + Map *map[string]string + Slice *[]string + MapPtr **map[string]string + SlicePtr **[]string + Struct *Ttest + StructPtr **Ttest +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/pointer/zz_generated.deepcopy.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/pointer/zz_generated.deepcopy.go new file mode 100644 index 00000000000..ceb9a52dcf7 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/pointer/zz_generated.deepcopy.go @@ -0,0 +1,114 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package pointer + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Ttest) DeepCopyInto(out *Ttest) { + *out = *in + if in.Builtin != nil { + in, out := &in.Builtin, &out.Builtin + *out = new(string) + **out = **in + } + if in.Ptr != nil { + in, out := &in.Ptr, &out.Ptr + *out = new(*string) + if **in != nil { + in, out := *in, *out + *out = new(string) + **out = **in + } + } + if in.Map != nil { + in, out := &in.Map, &out.Map + *out = new(map[string]string) + if **in != nil { + in, out := *in, *out + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + } + if in.Slice != nil { + in, out := &in.Slice, &out.Slice + *out = new([]string) + if **in != nil { + in, out := *in, *out + *out = make([]string, len(*in)) + copy(*out, *in) + } + } + if in.MapPtr != nil { + in, out := &in.MapPtr, &out.MapPtr + *out = new(*map[string]string) + if **in != nil { + in, out := *in, *out + *out = new(map[string]string) + if **in != nil { + in, out := *in, *out + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + } + } + if in.SlicePtr != nil { + in, out := &in.SlicePtr, &out.SlicePtr + *out = new(*[]string) + if **in != nil { + in, out := *in, *out + *out = new([]string) + if **in != nil { + in, out := *in, *out + *out = make([]string, len(*in)) + copy(*out, *in) + } + } + } + if in.Struct != nil { + in, out := &in.Struct, &out.Struct + *out = new(Ttest) + (*in).DeepCopyInto(*out) + } + if in.StructPtr != nil { + in, out := &in.StructPtr, &out.StructPtr + *out = new(*Ttest) + if **in != nil { + in, out := *in, *out + *out = new(Ttest) + (*in).DeepCopyInto(*out) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest. +func (in *Ttest) DeepCopy() *Ttest { + if in == nil { + return nil + } + out := new(Ttest) + in.DeepCopyInto(out) + return out +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/reflect_deepcopy.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/reflect_deepcopy.go new file mode 100644 index 00000000000..ffb3241af85 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/reflect_deepcopy.go @@ -0,0 +1,81 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package outputtests + +import ( + "fmt" + "reflect" +) + +// ReflectDeepCopy deep copies the object using reflection. +func ReflectDeepCopy(in interface{}) interface{} { + return reflectDeepCopy(reflect.ValueOf(in)).Interface() +} + +func reflectDeepCopy(src reflect.Value) reflect.Value { + switch src.Kind() { + case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: + if src.IsNil() { + return src + } + } + + switch src.Kind() { + case reflect.Chan, reflect.Func, reflect.UnsafePointer, reflect.Uintptr: + panic(fmt.Sprintf("cannot deep copy kind: %s", src.Kind())) + case reflect.Array: + dst := reflect.New(src.Type()) + for i := 0; i < src.Len(); i++ { + dst.Elem().Index(i).Set(reflectDeepCopy(src.Index(i))) + } + return dst.Elem() + case reflect.Interface: + return reflectDeepCopy(src.Elem()) + case reflect.Map: + dst := reflect.MakeMap(src.Type()) + for _, k := range src.MapKeys() { + dst.SetMapIndex(k, reflectDeepCopy(src.MapIndex(k))) + } + return dst + case reflect.Ptr: + dst := reflect.New(src.Type().Elem()) + dst.Elem().Set(reflectDeepCopy(src.Elem())) + return dst + case reflect.Slice: + dst := reflect.MakeSlice(src.Type(), 0, src.Len()) + for i := 0; i < src.Len(); i++ { + dst = reflect.Append(dst, reflectDeepCopy(src.Index(i))) + } + return dst + case reflect.Struct: + dst := reflect.New(src.Type()) + for i := 0; i < src.NumField(); i++ { + if !dst.Elem().Field(i).CanSet() { + // Can't set private fields. At this point, the + // best we can do is a shallow copy. For + // example, time.Time is a value type with + // private members that can be shallow copied. + return src + } + dst.Elem().Field(i).Set(reflectDeepCopy(src.Field(i))) + } + return dst.Elem() + default: + // Value types like numbers, booleans, and strings. + return src + } +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/slices/doc.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/slices/doc.go new file mode 100644 index 00000000000..183d73628cd --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/slices/doc.go @@ -0,0 +1,43 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package + +// This is a test package. +package slices + +type Ttest struct { + Byte []byte + // Int8 []int8 //TODO: int8 becomes byte in SnippetWriter + Int16 []int16 + Int32 []int32 + Int64 []int64 + Uint8 []uint8 + Uint16 []uint16 + Uint32 []uint32 + Uint64 []uint64 + Float32 []float32 + Float64 []float64 + String []string + StringPtr []*string + StringPtrPtr []**string + Map []map[string]string + MapPtr []*map[string]string + Slice [][]string + SlicePtr []*[]string + Struct []Ttest + StructPtr []*Ttest +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/slices/zz_generated.deepcopy.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/slices/zz_generated.deepcopy.go new file mode 100644 index 00000000000..04d4276a9d5 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/slices/zz_generated.deepcopy.go @@ -0,0 +1,193 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package slices + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Ttest) DeepCopyInto(out *Ttest) { + *out = *in + if in.Byte != nil { + in, out := &in.Byte, &out.Byte + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.Int16 != nil { + in, out := &in.Int16, &out.Int16 + *out = make([]int16, len(*in)) + copy(*out, *in) + } + if in.Int32 != nil { + in, out := &in.Int32, &out.Int32 + *out = make([]int32, len(*in)) + copy(*out, *in) + } + if in.Int64 != nil { + in, out := &in.Int64, &out.Int64 + *out = make([]int64, len(*in)) + copy(*out, *in) + } + if in.Uint8 != nil { + in, out := &in.Uint8, &out.Uint8 + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.Uint16 != nil { + in, out := &in.Uint16, &out.Uint16 + *out = make([]uint16, len(*in)) + copy(*out, *in) + } + if in.Uint32 != nil { + in, out := &in.Uint32, &out.Uint32 + *out = make([]uint32, len(*in)) + copy(*out, *in) + } + if in.Uint64 != nil { + in, out := &in.Uint64, &out.Uint64 + *out = make([]uint64, len(*in)) + copy(*out, *in) + } + if in.Float32 != nil { + in, out := &in.Float32, &out.Float32 + *out = make([]float32, len(*in)) + copy(*out, *in) + } + if in.Float64 != nil { + in, out := &in.Float64, &out.Float64 + *out = make([]float64, len(*in)) + copy(*out, *in) + } + if in.String != nil { + in, out := &in.String, &out.String + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.StringPtr != nil { + in, out := &in.StringPtr, &out.StringPtr + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } + if in.StringPtrPtr != nil { + in, out := &in.StringPtrPtr, &out.StringPtrPtr + *out = make([]**string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(*string) + if **in != nil { + in, out := *in, *out + *out = new(string) + **out = **in + } + } + } + } + if in.Map != nil { + in, out := &in.Map, &out.Map + *out = make([]map[string]string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + } + } + if in.MapPtr != nil { + in, out := &in.MapPtr, &out.MapPtr + *out = make([]*map[string]string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(map[string]string) + if **in != nil { + in, out := *in, *out + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + } + } + } + if in.Slice != nil { + in, out := &in.Slice, &out.Slice + *out = make([][]string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = make([]string, len(*in)) + copy(*out, *in) + } + } + } + if in.SlicePtr != nil { + in, out := &in.SlicePtr, &out.SlicePtr + *out = make([]*[]string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new([]string) + if **in != nil { + in, out := *in, *out + *out = make([]string, len(*in)) + copy(*out, *in) + } + } + } + } + if in.Struct != nil { + in, out := &in.Struct, &out.Struct + *out = make([]Ttest, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.StructPtr != nil { + in, out := &in.StructPtr, &out.StructPtr + *out = make([]*Ttest, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Ttest) + (*in).DeepCopyInto(*out) + } + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest. +func (in *Ttest) DeepCopy() *Ttest { + if in == nil { + return nil + } + out := new(Ttest) + in.DeepCopyInto(out) + return out +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/structs/doc.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/structs/doc.go new file mode 100644 index 00000000000..7e40800b239 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/structs/doc.go @@ -0,0 +1,40 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package + +// This is a test package. +package structs + +type Inner struct { + Byte byte + // Int8 int8 //TODO: int8 becomes byte in SnippetWriter + Int16 int16 + Int32 int32 + Int64 int64 + Uint8 uint8 + Uint16 uint16 + Uint32 uint32 + Uint64 uint64 + Float32 float32 + Float64 float64 + String string +} + +type Ttest struct { + Inner1 Inner + Inner2 Inner +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/structs/zz_generated.deepcopy.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/structs/zz_generated.deepcopy.go new file mode 100644 index 00000000000..992f9b9c2d1 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/structs/zz_generated.deepcopy.go @@ -0,0 +1,56 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package structs + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Inner) DeepCopyInto(out *Inner) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Inner. +func (in *Inner) DeepCopy() *Inner { + if in == nil { + return nil + } + out := new(Inner) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Ttest) DeepCopyInto(out *Ttest) { + *out = *in + out.Inner1 = in.Inner1 + out.Inner2 = in.Inner2 + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest. +func (in *Ttest) DeepCopy() *Ttest { + if in == nil { + return nil + } + out := new(Ttest) + in.DeepCopyInto(out) + return out +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/value_fuzzer.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/value_fuzzer.go new file mode 100644 index 00000000000..6104aa3cb12 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/value_fuzzer.go @@ -0,0 +1,86 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package outputtests + +import ( + "reflect" +) + +// ValueFuzz recursively changes all basic type values in an object. Any kind of references will not +// be touched, i.e. the addresses of slices, maps, pointers will stay unchanged. +func ValueFuzz(obj interface{}) { + valueFuzz(reflect.ValueOf(obj)) +} + +func valueFuzz(obj reflect.Value) { + switch obj.Kind() { + case reflect.Array: + for i := 0; i < obj.Len(); i++ { + valueFuzz(obj.Index(i)) + } + case reflect.Slice: + if obj.IsNil() { + // TODO: set non-nil value + } else { + for i := 0; i < obj.Len(); i++ { + valueFuzz(obj.Index(i)) + } + } + case reflect.Interface, reflect.Ptr: + if obj.IsNil() { + // TODO: set non-nil value + } else { + valueFuzz(obj.Elem()) + } + case reflect.Struct: + for i, n := 0, obj.NumField(); i < n; i++ { + valueFuzz(obj.Field(i)) + } + case reflect.Map: + if obj.IsNil() { + // TODO: set non-nil value + } else { + for _, k := range obj.MapKeys() { + // map values are not addressable. We need a copy. + v := obj.MapIndex(k) + copy := reflect.New(v.Type()) + copy.Elem().Set(v) + valueFuzz(copy.Elem()) + obj.SetMapIndex(k, copy.Elem()) + } + // TODO: set some new value + } + case reflect.Func: // ignore, we don't have function types in our API + default: + if !obj.CanSet() { + return + } + switch obj.Kind() { + case reflect.String: + obj.SetString(obj.String() + "x") + case reflect.Bool: + obj.SetBool(!obj.Bool()) + case reflect.Float32, reflect.Float64: + obj.SetFloat(obj.Float()*2.0 + 1.0) + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + obj.SetInt(obj.Int() + 1) + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + obj.SetUint(obj.Uint() + 1) + default: + } + } +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/a.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/a.go new file mode 100644 index 00000000000..fbebe864249 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/a.go @@ -0,0 +1,171 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package wholepkg + +import "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/otherpkg" + +// Trivial +type StructEmpty struct{} + +// Only primitives +type StructPrimitives struct { + BoolField bool + IntField int + StringField string + FloatField float64 +} +type StructPrimitivesAlias StructPrimitives +type StructEmbedStructPrimitives struct { + StructPrimitives +} +type StructEmbedInt struct { + int //nolint:unused +} +type StructStructPrimitives struct { + StructField StructPrimitives +} + +// Manual DeepCopy method +type ManualStruct struct { + StringField string +} + +func (m ManualStruct) DeepCopy() ManualStruct { + return m +} + +type ManualStructAlias ManualStruct + +type StructEmbedManualStruct struct { + ManualStruct +} + +// Only pointers to primitives +type StructPrimitivePointers struct { + BoolPtrField *bool + IntPtrField *int + StringPtrField *string + FloatPtrField *float64 +} +type StructPrimitivePointersAlias StructPrimitivePointers +type StructEmbedStructPrimitivePointers struct { + StructPrimitivePointers +} +type StructEmbedPointer struct { + *int +} +type StructStructPrimitivePointers struct { + StructField StructPrimitivePointers +} + +// Manual DeepCopy method +type ManualSlice []string + +func (m ManualSlice) DeepCopy() ManualSlice { + r := make(ManualSlice, len(m)) + copy(r, m) + return r +} + +// Slices +type StructSlices struct { + SliceBoolField []bool + SliceByteField []byte + SliceIntField []int + SliceStringField []string + SliceFloatField []float64 + SliceStructPrimitivesField []StructPrimitives + SliceStructPrimitivesAliasField []StructPrimitivesAlias + SliceStructPrimitivePointersField []StructPrimitivePointers + SliceStructPrimitivePointersAliasField []StructPrimitivePointersAlias + SliceSliceIntField [][]int + SliceManualStructField []ManualStruct + ManualSliceField ManualSlice +} +type StructSlicesAlias StructSlices +type StructEmbedStructSlices struct { + StructSlices +} +type StructStructSlices struct { + StructField StructSlices +} + +// Everything +type StructEverything struct { + BoolField bool + IntField int + StringField string + FloatField float64 + StructField StructPrimitives + EmptyStructField StructEmpty + ManualStructField ManualStruct + ManualStructAliasField ManualStructAlias + BoolPtrField *bool + IntPtrField *int + StringPtrField *string + FloatPtrField *float64 + PrimitivePointersField StructPrimitivePointers + ManualStructPtrField *ManualStruct + ManualStructAliasPtrField *ManualStructAlias + SliceBoolField []bool + SliceByteField []byte + SliceIntField []int + SliceStringField []string + SliceFloatField []float64 + SlicesField StructSlices + SliceManualStructField []ManualStruct + ManualSliceField ManualSlice +} + +// An Object +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/otherpkg.Object +type StructExplicitObject struct { + x int //nolint:unused +} + +// An Object which is used a non-pointer +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/otherpkg.Object +// +k8s:deepcopy-gen:nonpointer-interfaces=true +type StructNonPointerExplicitObject struct { + x int //nolint:unused +} + +// +k8s:deepcopy-gen=false +type StructTypeMeta struct { +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/otherpkg.Object +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/otherpkg.List +type StructObjectAndList struct { +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/otherpkg.Object +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/otherpkg.Object +type StructObjectAndObject struct { +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/wholepkg.Selector +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/otherpkg.Object +type StructExplicitSelectorExplicitObject struct { + StructTypeMeta +} + +type StructInterfaces struct { + ObjectField otherpkg.Object + NilObjectField otherpkg.Object + SelectorField Selector +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/b.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/b.go new file mode 100644 index 00000000000..3eb8c01fc85 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/b.go @@ -0,0 +1,20 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package wholepkg + +// Another type in another file. +type StructB struct{} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/deepcopy_test.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/deepcopy_test.go new file mode 100644 index 00000000000..b5089d6d408 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/deepcopy_test.go @@ -0,0 +1,145 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package wholepkg + +import ( + "reflect" + "testing" + + fuzz "github.com/google/gofuzz" +) + +func TestDeepCopyPrimitives(t *testing.T) { + x := StructPrimitives{} + y := StructPrimitives{} + + if !reflect.DeepEqual(&x, &y) { + t.Errorf("objects should be equal to start, but are not") + } + + fuzzer := fuzz.New() + fuzzer.Fuzz(&x) + fuzzer.Fuzz(&y) + + if reflect.DeepEqual(&x, &y) { + t.Errorf("objects should not be equal, but are") + } + + x.DeepCopyInto(&y) + if !reflect.DeepEqual(&x, &y) { + t.Errorf("objects should be equal, but are not") + } +} + +func TestDeepCopyInterfaceFields(t *testing.T) { + x := StructInterfaces{} + y := StructInterfaces{} + + if !reflect.DeepEqual(&x, &y) { + t.Errorf("objects should be equal to start, but are not") + } + + fuzzer := fuzz.New() + + obj := StructExplicitObject{} + fuzzer.Fuzz(&obj) + x.ObjectField = &obj + + sel := StructExplicitSelectorExplicitObject{} + fuzzer.Fuzz(&sel) + x.SelectorField = &sel + + if reflect.DeepEqual(&x, &y) { + t.Errorf("objects should not be equal, but are") + } + + x.DeepCopyInto(&y) + if !reflect.DeepEqual(&x, &y) { + t.Errorf("objects should be equal, but are not") + } +} + +func TestNilCopy(t *testing.T) { + var x *StructB + y := x.DeepCopy() + if y != nil { + t.Errorf("Expected nil as deepcopy of nil, got %+v", y) + } +} + +func assertMethod(t *testing.T, typ reflect.Type, name string) { + if _, found := typ.MethodByName(name); !found { + t.Errorf("StructExplicitObject must have %v method", name) + } +} + +func assertNotMethod(t *testing.T, typ reflect.Type, name string) { + if _, found := typ.MethodByName(name); found { + t.Errorf("%v must not have %v method", typ, name) + } +} + +func TestInterfaceTypes(t *testing.T) { + explicitObject := reflect.TypeOf(&StructExplicitObject{}) + assertMethod(t, explicitObject, "DeepCopyObject") + + typeMeta := reflect.TypeOf(&StructTypeMeta{}) + assertNotMethod(t, typeMeta, "DeepCopy") + + objectAndList := reflect.TypeOf(&StructObjectAndList{}) + assertMethod(t, objectAndList, "DeepCopyObject") + assertMethod(t, objectAndList, "DeepCopyList") + + objectAndObject := reflect.TypeOf(&StructObjectAndObject{}) + assertMethod(t, objectAndObject, "DeepCopyObject") + + explicitSelectorExplicitObject := reflect.TypeOf(&StructExplicitSelectorExplicitObject{}) + assertMethod(t, explicitSelectorExplicitObject, "DeepCopySelector") + assertMethod(t, explicitSelectorExplicitObject, "DeepCopyObject") +} + +func TestInterfaceDeepCopy(t *testing.T) { + x := StructExplicitObject{} + + fuzzer := fuzz.New() + fuzzer.Fuzz(&x) + + yObj := x.DeepCopyObject() + y, ok := yObj.(*StructExplicitObject) + if !ok { + t.Fatalf("epxected StructExplicitObject from StructExplicitObject.DeepCopyObject, got: %t", yObj) + } + if !reflect.DeepEqual(y, &x) { + t.Error("objects should be equal, but are not") + } +} + +func TestInterfaceNonPointerDeepCopy(t *testing.T) { + x := StructNonPointerExplicitObject{} + + fuzzer := fuzz.New() + fuzzer.Fuzz(&x) + + yObj := x.DeepCopyObject() + y, ok := yObj.(StructNonPointerExplicitObject) + if !ok { + t.Fatalf("epxected StructNonPointerExplicitObject from StructNonPointerExplicitObject.DeepCopyObject, got: %t", yObj) + } + if !reflect.DeepEqual(y, x) { + t.Error("objects should be equal, but are not") + } +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/doc.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/doc.go new file mode 100644 index 00000000000..10399986f8b --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +k8s:deepcopy-gen=package + +// This is a test package. +package wholepkg diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/interfaces.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/interfaces.go new file mode 100644 index 00000000000..e5b3c7de40b --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/interfaces.go @@ -0,0 +1,21 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package wholepkg + +type Selector interface { + DeepCopySelector() Selector +} diff --git a/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/zz_generated.deepcopy.go b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/zz_generated.deepcopy.go new file mode 100644 index 00000000000..0c7b4699e2b --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/zz_generated.deepcopy.go @@ -0,0 +1,761 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package wholepkg + +import ( + otherpkg "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/otherpkg" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in ManualSlice) DeepCopyInto(out *ManualSlice) { + { + in := &in + *out = in.DeepCopy() + return + } +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ManualStruct) DeepCopyInto(out *ManualStruct) { + *out = in.DeepCopy() + return +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ManualStructAlias) DeepCopyInto(out *ManualStructAlias) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManualStructAlias. +func (in *ManualStructAlias) DeepCopy() *ManualStructAlias { + if in == nil { + return nil + } + out := new(ManualStructAlias) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructB) DeepCopyInto(out *StructB) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructB. +func (in *StructB) DeepCopy() *StructB { + if in == nil { + return nil + } + out := new(StructB) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructEmbedInt) DeepCopyInto(out *StructEmbedInt) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructEmbedInt. +func (in *StructEmbedInt) DeepCopy() *StructEmbedInt { + if in == nil { + return nil + } + out := new(StructEmbedInt) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructEmbedManualStruct) DeepCopyInto(out *StructEmbedManualStruct) { + *out = *in + out.ManualStruct = in.ManualStruct.DeepCopy() + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructEmbedManualStruct. +func (in *StructEmbedManualStruct) DeepCopy() *StructEmbedManualStruct { + if in == nil { + return nil + } + out := new(StructEmbedManualStruct) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructEmbedPointer) DeepCopyInto(out *StructEmbedPointer) { + *out = *in + if in.int != nil { + in, out := &in.int, &out.int + *out = new(int) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructEmbedPointer. +func (in *StructEmbedPointer) DeepCopy() *StructEmbedPointer { + if in == nil { + return nil + } + out := new(StructEmbedPointer) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructEmbedStructPrimitivePointers) DeepCopyInto(out *StructEmbedStructPrimitivePointers) { + *out = *in + in.StructPrimitivePointers.DeepCopyInto(&out.StructPrimitivePointers) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructEmbedStructPrimitivePointers. +func (in *StructEmbedStructPrimitivePointers) DeepCopy() *StructEmbedStructPrimitivePointers { + if in == nil { + return nil + } + out := new(StructEmbedStructPrimitivePointers) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructEmbedStructPrimitives) DeepCopyInto(out *StructEmbedStructPrimitives) { + *out = *in + out.StructPrimitives = in.StructPrimitives + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructEmbedStructPrimitives. +func (in *StructEmbedStructPrimitives) DeepCopy() *StructEmbedStructPrimitives { + if in == nil { + return nil + } + out := new(StructEmbedStructPrimitives) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructEmbedStructSlices) DeepCopyInto(out *StructEmbedStructSlices) { + *out = *in + in.StructSlices.DeepCopyInto(&out.StructSlices) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructEmbedStructSlices. +func (in *StructEmbedStructSlices) DeepCopy() *StructEmbedStructSlices { + if in == nil { + return nil + } + out := new(StructEmbedStructSlices) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructEmpty) DeepCopyInto(out *StructEmpty) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructEmpty. +func (in *StructEmpty) DeepCopy() *StructEmpty { + if in == nil { + return nil + } + out := new(StructEmpty) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructEverything) DeepCopyInto(out *StructEverything) { + *out = *in + out.StructField = in.StructField + out.EmptyStructField = in.EmptyStructField + out.ManualStructField = in.ManualStructField.DeepCopy() + out.ManualStructAliasField = in.ManualStructAliasField + if in.BoolPtrField != nil { + in, out := &in.BoolPtrField, &out.BoolPtrField + *out = new(bool) + **out = **in + } + if in.IntPtrField != nil { + in, out := &in.IntPtrField, &out.IntPtrField + *out = new(int) + **out = **in + } + if in.StringPtrField != nil { + in, out := &in.StringPtrField, &out.StringPtrField + *out = new(string) + **out = **in + } + if in.FloatPtrField != nil { + in, out := &in.FloatPtrField, &out.FloatPtrField + *out = new(float64) + **out = **in + } + in.PrimitivePointersField.DeepCopyInto(&out.PrimitivePointersField) + if in.ManualStructPtrField != nil { + in, out := &in.ManualStructPtrField, &out.ManualStructPtrField + x := (*in).DeepCopy() + *out = &x + } + if in.ManualStructAliasPtrField != nil { + in, out := &in.ManualStructAliasPtrField, &out.ManualStructAliasPtrField + *out = new(ManualStructAlias) + **out = **in + } + if in.SliceBoolField != nil { + in, out := &in.SliceBoolField, &out.SliceBoolField + *out = make([]bool, len(*in)) + copy(*out, *in) + } + if in.SliceByteField != nil { + in, out := &in.SliceByteField, &out.SliceByteField + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.SliceIntField != nil { + in, out := &in.SliceIntField, &out.SliceIntField + *out = make([]int, len(*in)) + copy(*out, *in) + } + if in.SliceStringField != nil { + in, out := &in.SliceStringField, &out.SliceStringField + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.SliceFloatField != nil { + in, out := &in.SliceFloatField, &out.SliceFloatField + *out = make([]float64, len(*in)) + copy(*out, *in) + } + in.SlicesField.DeepCopyInto(&out.SlicesField) + if in.SliceManualStructField != nil { + in, out := &in.SliceManualStructField, &out.SliceManualStructField + *out = make([]ManualStruct, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + out.ManualSliceField = in.ManualSliceField.DeepCopy() + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructEverything. +func (in *StructEverything) DeepCopy() *StructEverything { + if in == nil { + return nil + } + out := new(StructEverything) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructExplicitObject) DeepCopyInto(out *StructExplicitObject) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructExplicitObject. +func (in *StructExplicitObject) DeepCopy() *StructExplicitObject { + if in == nil { + return nil + } + out := new(StructExplicitObject) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new otherpkg.Object. +func (in *StructExplicitObject) DeepCopyObject() otherpkg.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructExplicitSelectorExplicitObject) DeepCopyInto(out *StructExplicitSelectorExplicitObject) { + *out = *in + out.StructTypeMeta = in.StructTypeMeta + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructExplicitSelectorExplicitObject. +func (in *StructExplicitSelectorExplicitObject) DeepCopy() *StructExplicitSelectorExplicitObject { + if in == nil { + return nil + } + out := new(StructExplicitSelectorExplicitObject) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new otherpkg.Object. +func (in *StructExplicitSelectorExplicitObject) DeepCopyObject() otherpkg.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopySelector is an autogenerated deepcopy function, copying the receiver, creating a new Selector. +func (in *StructExplicitSelectorExplicitObject) DeepCopySelector() Selector { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructInterfaces) DeepCopyInto(out *StructInterfaces) { + *out = *in + if in.ObjectField != nil { + out.ObjectField = in.ObjectField.DeepCopyObject() + } + if in.NilObjectField != nil { + out.NilObjectField = in.NilObjectField.DeepCopyObject() + } + if in.SelectorField != nil { + out.SelectorField = in.SelectorField.DeepCopySelector() + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructInterfaces. +func (in *StructInterfaces) DeepCopy() *StructInterfaces { + if in == nil { + return nil + } + out := new(StructInterfaces) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructNonPointerExplicitObject) DeepCopyInto(out *StructNonPointerExplicitObject) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructNonPointerExplicitObject. +func (in *StructNonPointerExplicitObject) DeepCopy() *StructNonPointerExplicitObject { + if in == nil { + return nil + } + out := new(StructNonPointerExplicitObject) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new otherpkg.Object. +func (in StructNonPointerExplicitObject) DeepCopyObject() otherpkg.Object { + return *in.DeepCopy() +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructObjectAndList) DeepCopyInto(out *StructObjectAndList) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructObjectAndList. +func (in *StructObjectAndList) DeepCopy() *StructObjectAndList { + if in == nil { + return nil + } + out := new(StructObjectAndList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyList is an autogenerated deepcopy function, copying the receiver, creating a new otherpkg.List. +func (in *StructObjectAndList) DeepCopyList() otherpkg.List { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new otherpkg.Object. +func (in *StructObjectAndList) DeepCopyObject() otherpkg.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructObjectAndObject) DeepCopyInto(out *StructObjectAndObject) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructObjectAndObject. +func (in *StructObjectAndObject) DeepCopy() *StructObjectAndObject { + if in == nil { + return nil + } + out := new(StructObjectAndObject) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new otherpkg.Object. +func (in *StructObjectAndObject) DeepCopyObject() otherpkg.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructPrimitivePointers) DeepCopyInto(out *StructPrimitivePointers) { + *out = *in + if in.BoolPtrField != nil { + in, out := &in.BoolPtrField, &out.BoolPtrField + *out = new(bool) + **out = **in + } + if in.IntPtrField != nil { + in, out := &in.IntPtrField, &out.IntPtrField + *out = new(int) + **out = **in + } + if in.StringPtrField != nil { + in, out := &in.StringPtrField, &out.StringPtrField + *out = new(string) + **out = **in + } + if in.FloatPtrField != nil { + in, out := &in.FloatPtrField, &out.FloatPtrField + *out = new(float64) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructPrimitivePointers. +func (in *StructPrimitivePointers) DeepCopy() *StructPrimitivePointers { + if in == nil { + return nil + } + out := new(StructPrimitivePointers) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructPrimitivePointersAlias) DeepCopyInto(out *StructPrimitivePointersAlias) { + *out = *in + if in.BoolPtrField != nil { + in, out := &in.BoolPtrField, &out.BoolPtrField + *out = new(bool) + **out = **in + } + if in.IntPtrField != nil { + in, out := &in.IntPtrField, &out.IntPtrField + *out = new(int) + **out = **in + } + if in.StringPtrField != nil { + in, out := &in.StringPtrField, &out.StringPtrField + *out = new(string) + **out = **in + } + if in.FloatPtrField != nil { + in, out := &in.FloatPtrField, &out.FloatPtrField + *out = new(float64) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructPrimitivePointersAlias. +func (in *StructPrimitivePointersAlias) DeepCopy() *StructPrimitivePointersAlias { + if in == nil { + return nil + } + out := new(StructPrimitivePointersAlias) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructPrimitives) DeepCopyInto(out *StructPrimitives) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructPrimitives. +func (in *StructPrimitives) DeepCopy() *StructPrimitives { + if in == nil { + return nil + } + out := new(StructPrimitives) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructPrimitivesAlias) DeepCopyInto(out *StructPrimitivesAlias) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructPrimitivesAlias. +func (in *StructPrimitivesAlias) DeepCopy() *StructPrimitivesAlias { + if in == nil { + return nil + } + out := new(StructPrimitivesAlias) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructSlices) DeepCopyInto(out *StructSlices) { + *out = *in + if in.SliceBoolField != nil { + in, out := &in.SliceBoolField, &out.SliceBoolField + *out = make([]bool, len(*in)) + copy(*out, *in) + } + if in.SliceByteField != nil { + in, out := &in.SliceByteField, &out.SliceByteField + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.SliceIntField != nil { + in, out := &in.SliceIntField, &out.SliceIntField + *out = make([]int, len(*in)) + copy(*out, *in) + } + if in.SliceStringField != nil { + in, out := &in.SliceStringField, &out.SliceStringField + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.SliceFloatField != nil { + in, out := &in.SliceFloatField, &out.SliceFloatField + *out = make([]float64, len(*in)) + copy(*out, *in) + } + if in.SliceStructPrimitivesField != nil { + in, out := &in.SliceStructPrimitivesField, &out.SliceStructPrimitivesField + *out = make([]StructPrimitives, len(*in)) + copy(*out, *in) + } + if in.SliceStructPrimitivesAliasField != nil { + in, out := &in.SliceStructPrimitivesAliasField, &out.SliceStructPrimitivesAliasField + *out = make([]StructPrimitivesAlias, len(*in)) + copy(*out, *in) + } + if in.SliceStructPrimitivePointersField != nil { + in, out := &in.SliceStructPrimitivePointersField, &out.SliceStructPrimitivePointersField + *out = make([]StructPrimitivePointers, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.SliceStructPrimitivePointersAliasField != nil { + in, out := &in.SliceStructPrimitivePointersAliasField, &out.SliceStructPrimitivePointersAliasField + *out = make([]StructPrimitivePointersAlias, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.SliceSliceIntField != nil { + in, out := &in.SliceSliceIntField, &out.SliceSliceIntField + *out = make([][]int, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = make([]int, len(*in)) + copy(*out, *in) + } + } + } + if in.SliceManualStructField != nil { + in, out := &in.SliceManualStructField, &out.SliceManualStructField + *out = make([]ManualStruct, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + out.ManualSliceField = in.ManualSliceField.DeepCopy() + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructSlices. +func (in *StructSlices) DeepCopy() *StructSlices { + if in == nil { + return nil + } + out := new(StructSlices) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructSlicesAlias) DeepCopyInto(out *StructSlicesAlias) { + *out = *in + if in.SliceBoolField != nil { + in, out := &in.SliceBoolField, &out.SliceBoolField + *out = make([]bool, len(*in)) + copy(*out, *in) + } + if in.SliceByteField != nil { + in, out := &in.SliceByteField, &out.SliceByteField + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.SliceIntField != nil { + in, out := &in.SliceIntField, &out.SliceIntField + *out = make([]int, len(*in)) + copy(*out, *in) + } + if in.SliceStringField != nil { + in, out := &in.SliceStringField, &out.SliceStringField + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.SliceFloatField != nil { + in, out := &in.SliceFloatField, &out.SliceFloatField + *out = make([]float64, len(*in)) + copy(*out, *in) + } + if in.SliceStructPrimitivesField != nil { + in, out := &in.SliceStructPrimitivesField, &out.SliceStructPrimitivesField + *out = make([]StructPrimitives, len(*in)) + copy(*out, *in) + } + if in.SliceStructPrimitivesAliasField != nil { + in, out := &in.SliceStructPrimitivesAliasField, &out.SliceStructPrimitivesAliasField + *out = make([]StructPrimitivesAlias, len(*in)) + copy(*out, *in) + } + if in.SliceStructPrimitivePointersField != nil { + in, out := &in.SliceStructPrimitivePointersField, &out.SliceStructPrimitivePointersField + *out = make([]StructPrimitivePointers, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.SliceStructPrimitivePointersAliasField != nil { + in, out := &in.SliceStructPrimitivePointersAliasField, &out.SliceStructPrimitivePointersAliasField + *out = make([]StructPrimitivePointersAlias, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.SliceSliceIntField != nil { + in, out := &in.SliceSliceIntField, &out.SliceSliceIntField + *out = make([][]int, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = make([]int, len(*in)) + copy(*out, *in) + } + } + } + if in.SliceManualStructField != nil { + in, out := &in.SliceManualStructField, &out.SliceManualStructField + *out = make([]ManualStruct, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + out.ManualSliceField = in.ManualSliceField.DeepCopy() + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructSlicesAlias. +func (in *StructSlicesAlias) DeepCopy() *StructSlicesAlias { + if in == nil { + return nil + } + out := new(StructSlicesAlias) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructStructPrimitivePointers) DeepCopyInto(out *StructStructPrimitivePointers) { + *out = *in + in.StructField.DeepCopyInto(&out.StructField) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructStructPrimitivePointers. +func (in *StructStructPrimitivePointers) DeepCopy() *StructStructPrimitivePointers { + if in == nil { + return nil + } + out := new(StructStructPrimitivePointers) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructStructPrimitives) DeepCopyInto(out *StructStructPrimitives) { + *out = *in + out.StructField = in.StructField + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructStructPrimitives. +func (in *StructStructPrimitives) DeepCopy() *StructStructPrimitives { + if in == nil { + return nil + } + out := new(StructStructPrimitives) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructStructSlices) DeepCopyInto(out *StructStructSlices) { + *out = *in + in.StructField.DeepCopyInto(&out.StructField) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructStructSlices. +func (in *StructStructSlices) DeepCopy() *StructStructSlices { + if in == nil { + return nil + } + out := new(StructStructSlices) + in.DeepCopyInto(out) + return out +}