Move gengo/examples/deepcopy -> code_generator

Merge comments in main.go and fix a bunch of pre-existing lint errors.
This commit is contained in:
Tim Hockin 2024-01-11 23:36:55 -08:00
parent 01a1865934
commit cb7f0593ae
No known key found for this signature in database
31 changed files with 4673 additions and 18 deletions

View File

@ -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"

View File

@ -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")

View File

@ -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<Interface> 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<named-interface> 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<named-interface> 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<named-interface> 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)
}
}

View File

@ -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)
}
}
}

View File

@ -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"
)

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}
}
})
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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:
}
}
}

View File

@ -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
}

View File

@ -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{}

View File

@ -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")
}
}

View File

@ -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

View File

@ -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
}

View File

@ -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
}