github.com/galaxyobe/gen@v0.0.0-20220910125335-392fa8f0990f/cmd/deepcopy-gen/generators/deepcopy.go (about)

     1  /*
     2  Copyright 2015 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package generators
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  	"path/filepath"
    23  	"sort"
    24  	"strings"
    25  
    26  	"github.com/spf13/pflag"
    27  	"k8s.io/gengo/args"
    28  	"k8s.io/gengo/examples/set-gen/sets"
    29  	"k8s.io/gengo/generator"
    30  	"k8s.io/gengo/namer"
    31  	"k8s.io/gengo/types"
    32  
    33  	"k8s.io/klog/v2"
    34  )
    35  
    36  // CustomArgs is used tby the go2idl framework to pass custom_args specific to this
    37  // generator.
    38  type CustomArgs struct {
    39  	BoundingDirs []string // Only deal with types rooted under these dirs.
    40  	// If specified, trim the path from PackagePath before writing files.
    41  	TrimPackagePath string
    42  }
    43  
    44  func (a *CustomArgs) AddFlags(fs *pflag.FlagSet) {
    45  	fs.StringSliceVar(&a.BoundingDirs, "bounding-dirs", a.BoundingDirs,
    46  		"Comma-separated list of import paths which bound the types for which deep-copies will be generated.")
    47  	fs.StringVar(&a.TrimPackagePath, "trim-package-path", a.TrimPackagePath,
    48  		"If set, trim the specified path from PackagePath when generating files.")
    49  }
    50  
    51  // This is the comment tag that carries parameters for deep-copy generation.
    52  const (
    53  	tagEnabledName              = "gen:deepcopy"
    54  	interfacesTagName           = tagEnabledName + ":interfaces"
    55  	interfacesNonPointerTagName = tagEnabledName + ":nonpointer-interfaces" // attach the DeepCopy<Interface> methods to the
    56  )
    57  
    58  // Known values for the comment tag.
    59  const tagValuePackage = "package"
    60  
    61  // enabledTagValue holds parameters from a tagName tag.
    62  type enabledTagValue struct {
    63  	value    string
    64  	register bool
    65  }
    66  
    67  func extractEnabledTypeTag(t *types.Type) *enabledTagValue {
    68  	comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...)
    69  	return extractEnabledTag(comments)
    70  }
    71  
    72  func extractEnabledTag(comments []string) *enabledTagValue {
    73  	tagVals := types.ExtractCommentTags("+", comments)[tagEnabledName]
    74  	if tagVals == nil {
    75  		// No match for the tag.
    76  		return nil
    77  	}
    78  	// If there are multiple values, abort.
    79  	if len(tagVals) > 1 {
    80  		klog.Fatalf("Found %d %s tags: %q", len(tagVals), tagEnabledName, tagVals)
    81  	}
    82  
    83  	// If we got here we are returning something.
    84  	tag := &enabledTagValue{}
    85  
    86  	// Get the primary value.
    87  	parts := strings.Split(tagVals[0], ",")
    88  	if len(parts) >= 1 {
    89  		tag.value = parts[0]
    90  	}
    91  
    92  	// Parse extra arguments.
    93  	parts = parts[1:]
    94  	for i := range parts {
    95  		kv := strings.SplitN(parts[i], "=", 2)
    96  		k := kv[0]
    97  		v := ""
    98  		if len(kv) == 2 {
    99  			v = kv[1]
   100  		}
   101  		switch k {
   102  		case "register":
   103  			if v != "false" {
   104  				tag.register = true
   105  			}
   106  		default:
   107  			klog.Fatalf("Unsupported %s param: %q", tagEnabledName, parts[i])
   108  		}
   109  	}
   110  	return tag
   111  }
   112  
   113  // TODO: This is created only to reduce number of changes in a single PR.
   114  // Remove it and use PublicNamer instead.
   115  func deepCopyNamer() *namer.NameStrategy {
   116  	return &namer.NameStrategy{
   117  		Join: func(pre string, in []string, post string) string {
   118  			return strings.Join(in, "_")
   119  		},
   120  		PrependPackageNames: 1,
   121  	}
   122  }
   123  
   124  // NameSystems returns the name system used by the generators in this package.
   125  func NameSystems() namer.NameSystems {
   126  	return namer.NameSystems{
   127  		"public": deepCopyNamer(),
   128  		"raw":    namer.NewRawNamer("", nil),
   129  	}
   130  }
   131  
   132  // DefaultNameSystem returns the default name system for ordering the types to be
   133  // processed by the generators in this package.
   134  func DefaultNameSystem() string {
   135  	return "public"
   136  }
   137  
   138  func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
   139  	boilerplate, err := arguments.LoadGoBoilerplate()
   140  	if err != nil {
   141  		klog.Fatalf("Failed loading boilerplate: %v", err)
   142  	}
   143  
   144  	inputs := sets.NewString(context.Inputs...)
   145  	packages := generator.Packages{}
   146  	header := append([]byte(fmt.Sprintf("//go:build !%s\n// +build !%s\n\n", arguments.GeneratedBuildTag, arguments.GeneratedBuildTag)), boilerplate...)
   147  
   148  	boundingDirs := []string{}
   149  	if customArgs, ok := arguments.CustomArgs.(*CustomArgs); ok {
   150  		if customArgs.BoundingDirs == nil {
   151  			customArgs.BoundingDirs = context.Inputs
   152  		}
   153  		for i := range customArgs.BoundingDirs {
   154  			// Strip any trailing slashes - they are not exactly "correct" but
   155  			// this is friendlier.
   156  			boundingDirs = append(boundingDirs, strings.TrimRight(customArgs.BoundingDirs[i], "/"))
   157  		}
   158  	}
   159  
   160  	for i := range inputs {
   161  		klog.V(5).Infof("Considering pkg %q", i)
   162  		pkg := context.Universe[i]
   163  		if pkg == nil {
   164  			// If the input had no Go files, for example.
   165  			continue
   166  		}
   167  
   168  		ptag := extractEnabledTag(pkg.Comments)
   169  		ptagValue := ""
   170  		ptagRegister := false
   171  		if ptag != nil {
   172  			ptagValue = ptag.value
   173  			if ptagValue != tagValuePackage {
   174  				klog.Fatalf("Package %v: unsupported %s value: %q", i, tagEnabledName, ptagValue)
   175  			}
   176  			ptagRegister = ptag.register
   177  			klog.V(5).Infof("  tag.value: %q, tag.register: %t", ptagValue, ptagRegister)
   178  		} else {
   179  			klog.V(5).Infof("  no tag")
   180  		}
   181  
   182  		// If the pkg-scoped tag says to generate, we can skip scanning types.
   183  		pkgNeedsGeneration := (ptagValue == tagValuePackage)
   184  		if !pkgNeedsGeneration {
   185  			// If the pkg-scoped tag did not exist, scan all types for one that
   186  			// explicitly wants generation.
   187  			for _, t := range pkg.Types {
   188  				klog.V(5).Infof("  considering type %q", t.Name.String())
   189  				ttag := extractEnabledTypeTag(t)
   190  				if ttag != nil && ttag.value == "true" {
   191  					klog.V(5).Infof("    tag=true")
   192  					if !copyableType(t) {
   193  						klog.Fatalf("Type %v requests deepcopy generation but is not copyable", t)
   194  					}
   195  					pkgNeedsGeneration = true
   196  					break
   197  				}
   198  			}
   199  		}
   200  
   201  		if pkgNeedsGeneration {
   202  			klog.V(3).Infof("Package %q needs generation", i)
   203  			path := pkg.Path
   204  			// if the source path is within a /vendor/ directory (for example,
   205  			// k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/apis/meta/v1), allow
   206  			// generation to output to the proper relative path (under vendor).
   207  			// Otherwise, the generator will create the file in the wrong location
   208  			// in the output directory.
   209  			// TODO: build a more fundamental concept in gengo for dealing with modifications
   210  			// to vendored packages.
   211  			if strings.HasPrefix(pkg.SourcePath, arguments.OutputBase) {
   212  				expandedPath := strings.TrimPrefix(pkg.SourcePath, arguments.OutputBase)
   213  				if strings.Contains(expandedPath, "/vendor/") {
   214  					path = expandedPath
   215  				}
   216  			}
   217  			if customArgs, ok := arguments.CustomArgs.(*CustomArgs); ok {
   218  				if customArgs.TrimPackagePath != "" {
   219  					path = strings.ReplaceAll(path, customArgs.TrimPackagePath, "")
   220  					separator := string(filepath.Separator)
   221  					if path != "" && strings.HasPrefix(path, separator) {
   222  						path = path[1:]
   223  					}
   224  				}
   225  			}
   226  			packages = append(packages,
   227  				&generator.DefaultPackage{
   228  					PackageName: pkg.Name,
   229  					PackagePath: path,
   230  					HeaderText:  header,
   231  					GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
   232  						return []generator.Generator{
   233  							NewGenDeepCopy(arguments.OutputFileBaseName, pkg.Path, boundingDirs, (ptagValue == tagValuePackage), ptagRegister),
   234  						}
   235  					},
   236  					FilterFunc: func(c *generator.Context, t *types.Type) bool {
   237  						return t.Name.Package == pkg.Path
   238  					},
   239  				})
   240  		}
   241  	}
   242  	return packages
   243  }
   244  
   245  // genDeepCopy produces a file with autogenerated deep-copy functions.
   246  type genDeepCopy struct {
   247  	generator.DefaultGen
   248  	targetPackage string
   249  	boundingDirs  []string
   250  	allTypes      bool
   251  	registerTypes bool
   252  	imports       namer.ImportTracker
   253  	typesForInit  []*types.Type
   254  }
   255  
   256  func NewGenDeepCopy(sanitizedName, targetPackage string, boundingDirs []string, allTypes, registerTypes bool) generator.Generator {
   257  	return &genDeepCopy{
   258  		DefaultGen: generator.DefaultGen{
   259  			OptionalName: sanitizedName,
   260  		},
   261  		targetPackage: targetPackage,
   262  		boundingDirs:  boundingDirs,
   263  		allTypes:      allTypes,
   264  		registerTypes: registerTypes,
   265  		imports:       generator.NewImportTracker(),
   266  		typesForInit:  make([]*types.Type, 0),
   267  	}
   268  }
   269  
   270  func (g *genDeepCopy) Namers(c *generator.Context) namer.NameSystems {
   271  	// Have the raw namer for this file track what it imports.
   272  	return namer.NameSystems{
   273  		"raw": namer.NewRawNamer(g.targetPackage, g.imports),
   274  	}
   275  }
   276  
   277  func (g *genDeepCopy) Filter(c *generator.Context, t *types.Type) bool {
   278  	// Filter out types not being processed or not copyable within the package.
   279  	enabled := g.allTypes
   280  	if !enabled {
   281  		ttag := extractEnabledTypeTag(t)
   282  		if ttag != nil && ttag.value == "true" {
   283  			enabled = true
   284  		}
   285  	}
   286  	if !enabled {
   287  		return false
   288  	}
   289  	if !copyableType(t) {
   290  		klog.V(2).Infof("Type %v is not copyable", t)
   291  		return false
   292  	}
   293  	klog.V(4).Infof("Type %v is copyable", t)
   294  	g.typesForInit = append(g.typesForInit, t)
   295  	return true
   296  }
   297  
   298  func (g *genDeepCopy) copyableAndInBounds(t *types.Type) bool {
   299  	if !copyableType(t) {
   300  		return false
   301  	}
   302  	// Only packages within the restricted range can be processed.
   303  	if !isRootedUnder(t.Name.Package, g.boundingDirs) {
   304  		return false
   305  	}
   306  	return true
   307  }
   308  
   309  // deepCopyMethod returns the signature of a DeepCopy() method, nil or an error
   310  // if the type does not match. This allows more efficient deep copy
   311  // implementations to be defined by the type's author.  The correct signature
   312  // for a type T is:
   313  //
   314  //	func (t T) DeepCopy() T
   315  //
   316  // or:
   317  //
   318  //	func (t *T) DeepCopy() *T
   319  func deepCopyMethod(t *types.Type) (*types.Signature, error) {
   320  	f, found := t.Methods["DeepCopy"]
   321  	if !found {
   322  		return nil, nil
   323  	}
   324  	if len(f.Signature.Parameters) != 0 {
   325  		return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected no parameters", t)
   326  	}
   327  	if len(f.Signature.Results) != 1 {
   328  		return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected exactly one result", t)
   329  	}
   330  
   331  	ptrResult := f.Signature.Results[0].Kind == types.Pointer && f.Signature.Results[0].Elem.Name == t.Name
   332  	nonPtrResult := f.Signature.Results[0].Name == t.Name
   333  
   334  	if !ptrResult && !nonPtrResult {
   335  		return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected to return %s or *%s", t, t.Name.Name, t.Name.Name)
   336  	}
   337  
   338  	ptrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Kind == types.Pointer && f.Signature.Receiver.Elem.Name == t.Name
   339  	nonPtrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Name == t.Name
   340  
   341  	if ptrRcvr && !ptrResult {
   342  		return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected a *%s result for a *%s receiver", t, t.Name.Name, t.Name.Name)
   343  	}
   344  	if nonPtrRcvr && !nonPtrResult {
   345  		return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected a %s result for a %s receiver", t, t.Name.Name, t.Name.Name)
   346  	}
   347  
   348  	return f.Signature, nil
   349  }
   350  
   351  // deepCopyMethodOrDie returns the signatrue of a DeepCopy method, nil or calls klog.Fatalf
   352  // if the type does not match.
   353  func deepCopyMethodOrDie(t *types.Type) *types.Signature {
   354  	ret, err := deepCopyMethod(t)
   355  	if err != nil {
   356  		klog.Fatal(err)
   357  	}
   358  	return ret
   359  }
   360  
   361  // deepCopyIntoMethod returns the signature of a DeepCopyInto() method, nil or an error
   362  // if the type is wrong. DeepCopyInto allows more efficient deep copy
   363  // implementations to be defined by the type's author.  The correct signature
   364  // for a type T is:
   365  //
   366  //	func (t T) DeepCopyInto(t *T)
   367  //
   368  // or:
   369  //
   370  //	func (t *T) DeepCopyInto(t *T)
   371  func deepCopyIntoMethod(t *types.Type) (*types.Signature, error) {
   372  	f, found := t.Methods["DeepCopyInto"]
   373  	if !found {
   374  		return nil, nil
   375  	}
   376  	if len(f.Signature.Parameters) != 1 {
   377  		return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected exactly one parameter", t)
   378  	}
   379  	if len(f.Signature.Results) != 0 {
   380  		return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected no result type", t)
   381  	}
   382  
   383  	ptrParam := f.Signature.Parameters[0].Kind == types.Pointer && f.Signature.Parameters[0].Elem.Name == t.Name
   384  
   385  	if !ptrParam {
   386  		return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected parameter of type *%s", t, t.Name.Name)
   387  	}
   388  
   389  	ptrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Kind == types.Pointer && f.Signature.Receiver.Elem.Name == t.Name
   390  	nonPtrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Name == t.Name
   391  
   392  	if !ptrRcvr && !nonPtrRcvr {
   393  		// this should never happen
   394  		return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected a receiver of type %s or *%s", t, t.Name.Name, t.Name.Name)
   395  	}
   396  
   397  	return f.Signature, nil
   398  }
   399  
   400  // deepCopyIntoMethodOrDie returns the signature of a DeepCopyInto() method, nil or calls klog.Fatalf
   401  // if the type is wrong.
   402  func deepCopyIntoMethodOrDie(t *types.Type) *types.Signature {
   403  	ret, err := deepCopyIntoMethod(t)
   404  	if err != nil {
   405  		klog.Fatal(err)
   406  	}
   407  	return ret
   408  }
   409  
   410  func isRootedUnder(pkg string, roots []string) bool {
   411  	// Add trailing / to avoid false matches, e.g. foo/bar vs foo/barn.  This
   412  	// assumes that bounding dirs do not have trailing slashes.
   413  	pkg = pkg + "/"
   414  	for _, root := range roots {
   415  		if strings.HasPrefix(pkg, root+"/") {
   416  			return true
   417  		}
   418  	}
   419  	return false
   420  }
   421  
   422  func copyableType(t *types.Type) bool {
   423  	// If the type opts out of copy-generation, stop.
   424  	ttag := extractEnabledTypeTag(t)
   425  	if ttag != nil && ttag.value == "false" {
   426  		return false
   427  	}
   428  
   429  	// Filter out private types.
   430  	if namer.IsPrivateGoName(t.Name.Name) {
   431  		return false
   432  	}
   433  
   434  	if t.Kind == types.Alias {
   435  		// if the underlying built-in is not deepcopy-able, deepcopy is opt-in through definition of custom methods.
   436  		// Note that aliases of builtins, maps, slices can have deepcopy methods.
   437  		if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
   438  			return true
   439  		} else {
   440  			return t.Underlying.Kind != types.Builtin || copyableType(t.Underlying)
   441  		}
   442  	}
   443  
   444  	if t.Kind != types.Struct {
   445  		return false
   446  	}
   447  
   448  	return true
   449  }
   450  
   451  func underlyingType(t *types.Type) *types.Type {
   452  	for t.Kind == types.Alias {
   453  		t = t.Underlying
   454  	}
   455  	return t
   456  }
   457  
   458  func (g *genDeepCopy) isOtherPackage(pkg string) bool {
   459  	if pkg == g.targetPackage {
   460  		return false
   461  	}
   462  	if strings.HasSuffix(pkg, "\""+g.targetPackage+"\"") {
   463  		return false
   464  	}
   465  	return true
   466  }
   467  
   468  func (g *genDeepCopy) Imports(c *generator.Context) (imports []string) {
   469  	importLines := []string{}
   470  	for _, singleImport := range g.imports.ImportLines() {
   471  		if g.isOtherPackage(singleImport) {
   472  			importLines = append(importLines, singleImport)
   473  		}
   474  	}
   475  	return importLines
   476  }
   477  
   478  func argsFromType(ts ...*types.Type) generator.Args {
   479  	a := generator.Args{
   480  		"type": ts[0],
   481  	}
   482  	for i, t := range ts {
   483  		a[fmt.Sprintf("type%d", i+1)] = t
   484  	}
   485  	return a
   486  }
   487  
   488  func (g *genDeepCopy) Init(c *generator.Context, w io.Writer) error {
   489  	return nil
   490  }
   491  
   492  func (g *genDeepCopy) needsGeneration(t *types.Type) bool {
   493  	tag := extractEnabledTypeTag(t)
   494  	tv := ""
   495  	if tag != nil {
   496  		tv = tag.value
   497  		if tv != "true" && tv != "false" {
   498  			klog.Fatalf("Type %v: unsupported %s value: %q", t, tagEnabledName, tag.value)
   499  		}
   500  	}
   501  	if g.allTypes && tv == "false" {
   502  		// The whole package is being generated, but this type has opted out.
   503  		klog.V(5).Infof("Not generating for type %v because type opted out", t)
   504  		return false
   505  	}
   506  	if !g.allTypes && tv != "true" {
   507  		// The whole package is NOT being generated, and this type has NOT opted in.
   508  		klog.V(5).Infof("Not generating for type %v because type did not opt in", t)
   509  		return false
   510  	}
   511  	return true
   512  }
   513  
   514  func extractInterfacesTag(t *types.Type) []string {
   515  	var result []string
   516  	comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...)
   517  	values := types.ExtractCommentTags("+", comments)[interfacesTagName]
   518  	for _, v := range values {
   519  		if len(v) == 0 {
   520  			continue
   521  		}
   522  		intfs := strings.Split(v, ",")
   523  		for _, intf := range intfs {
   524  			if intf == "" {
   525  				continue
   526  			}
   527  			result = append(result, intf)
   528  		}
   529  	}
   530  	return result
   531  }
   532  
   533  func extractNonPointerInterfaces(t *types.Type) (bool, error) {
   534  	comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...)
   535  	values := types.ExtractCommentTags("+", comments)[interfacesNonPointerTagName]
   536  	if len(values) == 0 {
   537  		return false, nil
   538  	}
   539  	result := values[0] == "true"
   540  	for _, v := range values {
   541  		if v == "true" != result {
   542  			return false, fmt.Errorf("contradicting %v value %q found to previous value %v", interfacesNonPointerTagName, v, result)
   543  		}
   544  	}
   545  	return result, nil
   546  }
   547  
   548  func (g *genDeepCopy) deepCopyableInterfacesInner(c *generator.Context, t *types.Type) ([]*types.Type, error) {
   549  	if t.Kind != types.Struct {
   550  		return nil, nil
   551  	}
   552  
   553  	intfs := extractInterfacesTag(t)
   554  
   555  	var ts []*types.Type
   556  	for _, intf := range intfs {
   557  		t := types.ParseFullyQualifiedName(intf)
   558  		err := c.AddDir(t.Package)
   559  		if err != nil {
   560  			return nil, err
   561  		}
   562  		intfT := c.Universe.Type(t)
   563  		if intfT == nil {
   564  			return nil, fmt.Errorf("unknown type %q in %s tag of type %s", intf, interfacesTagName, intfT)
   565  		}
   566  		if intfT.Kind != types.Interface {
   567  			return nil, fmt.Errorf("type %q in %s tag of type %s is not an interface, but: %q", intf, interfacesTagName, t, intfT.Kind)
   568  		}
   569  		g.imports.AddType(intfT)
   570  		ts = append(ts, intfT)
   571  	}
   572  
   573  	return ts, nil
   574  }
   575  
   576  // deepCopyableInterfaces returns the interface types to implement and whether they apply to a non-pointer receiver.
   577  func (g *genDeepCopy) deepCopyableInterfaces(c *generator.Context, t *types.Type) ([]*types.Type, bool, error) {
   578  	ts, err := g.deepCopyableInterfacesInner(c, t)
   579  	if err != nil {
   580  		return nil, false, err
   581  	}
   582  
   583  	set := map[string]*types.Type{}
   584  	for _, t := range ts {
   585  		set[t.String()] = t
   586  	}
   587  
   588  	result := []*types.Type{}
   589  	for _, t := range set {
   590  		result = append(result, t)
   591  	}
   592  
   593  	TypeSlice(result).Sort() // we need a stable sorting because it determines the order in generation
   594  
   595  	nonPointerReceiver, err := extractNonPointerInterfaces(t)
   596  	if err != nil {
   597  		return nil, false, err
   598  	}
   599  
   600  	return result, nonPointerReceiver, nil
   601  }
   602  
   603  type TypeSlice []*types.Type
   604  
   605  func (s TypeSlice) Len() int           { return len(s) }
   606  func (s TypeSlice) Less(i, j int) bool { return s[i].String() < s[j].String() }
   607  func (s TypeSlice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
   608  func (s TypeSlice) Sort()              { sort.Sort(s) }
   609  
   610  func (g *genDeepCopy) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
   611  	if !g.needsGeneration(t) {
   612  		return nil
   613  	}
   614  	klog.V(5).Infof("Generating deepcopy function for type %v", t)
   615  
   616  	sw := generator.NewSnippetWriter(w, c, "$", "$")
   617  	args := argsFromType(t)
   618  
   619  	if deepCopyIntoMethodOrDie(t) == nil {
   620  		sw.Do("// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\n", args)
   621  		if isReference(t) {
   622  			sw.Do("func (in $.type|raw$) DeepCopyInto(out *$.type|raw$) {\n", args)
   623  			sw.Do("{in:=&in\n", nil)
   624  		} else {
   625  			sw.Do("func (in *$.type|raw$) DeepCopyInto(out *$.type|raw$) {\n", args)
   626  		}
   627  		if deepCopyMethodOrDie(t) != nil {
   628  			if t.Methods["DeepCopy"].Signature.Receiver.Kind == types.Pointer {
   629  				sw.Do("clone := in.DeepCopy()\n", nil)
   630  				sw.Do("*out = *clone\n", nil)
   631  			} else {
   632  				sw.Do("*out = in.DeepCopy()\n", nil)
   633  			}
   634  			sw.Do("return\n", nil)
   635  		} else {
   636  			g.generateFor(t, sw)
   637  			sw.Do("return\n", nil)
   638  		}
   639  		if isReference(t) {
   640  			sw.Do("}\n", nil)
   641  		}
   642  		sw.Do("}\n\n", nil)
   643  	}
   644  
   645  	if deepCopyMethodOrDie(t) == nil {
   646  		sw.Do("// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new $.type|raw$.\n", args)
   647  		if isReference(t) {
   648  			sw.Do("func (in $.type|raw$) DeepCopy() $.type|raw$ {\n", args)
   649  		} else {
   650  			sw.Do("func (in *$.type|raw$) DeepCopy() *$.type|raw$ {\n", args)
   651  		}
   652  		sw.Do("if in == nil { return nil }\n", nil)
   653  		sw.Do("out := new($.type|raw$)\n", args)
   654  		sw.Do("in.DeepCopyInto(out)\n", nil)
   655  		if isReference(t) {
   656  			sw.Do("return *out\n", nil)
   657  		} else {
   658  			sw.Do("return out\n", nil)
   659  		}
   660  		sw.Do("}\n\n", nil)
   661  	}
   662  
   663  	intfs, nonPointerReceiver, err := g.deepCopyableInterfaces(c, t)
   664  	if err != nil {
   665  		return err
   666  	}
   667  	for _, intf := range intfs {
   668  		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))
   669  		if nonPointerReceiver {
   670  			sw.Do(fmt.Sprintf("func (in $.type|raw$) DeepCopy%s() $.type2|raw$ {\n", intf.Name.Name), argsFromType(t, intf))
   671  			sw.Do("return *in.DeepCopy()", nil)
   672  			sw.Do("}\n\n", nil)
   673  		} else {
   674  			sw.Do(fmt.Sprintf("func (in *$.type|raw$) DeepCopy%s() $.type2|raw$ {\n", intf.Name.Name), argsFromType(t, intf))
   675  			sw.Do("if c := in.DeepCopy(); c != nil {\n", nil)
   676  			sw.Do("return c\n", nil)
   677  			sw.Do("}\n", nil)
   678  			sw.Do("return nil\n", nil)
   679  			sw.Do("}\n\n", nil)
   680  		}
   681  	}
   682  
   683  	return sw.Error()
   684  }
   685  
   686  // isReference return true for pointer, maps, slices and aliases of those.
   687  func isReference(t *types.Type) bool {
   688  	if t.Kind == types.Pointer || t.Kind == types.Map || t.Kind == types.Slice {
   689  		return true
   690  	}
   691  	return t.Kind == types.Alias && isReference(underlyingType(t))
   692  }
   693  
   694  // we use the system of shadowing 'in' and 'out' so that the same code is valid
   695  // at any nesting level. This makes the autogenerator easy to understand, and
   696  // the compiler shouldn't care.
   697  func (g *genDeepCopy) generateFor(t *types.Type, sw *generator.SnippetWriter) {
   698  	// derive inner types if t is an alias. We call the do* methods below with the alias type.
   699  	// basic rule: generate according to inner type, but construct objects with the alias type.
   700  	ut := underlyingType(t)
   701  
   702  	var f func(*types.Type, *generator.SnippetWriter)
   703  	switch ut.Kind {
   704  	case types.Builtin:
   705  		f = g.doBuiltin
   706  	case types.Map:
   707  		f = g.doMap
   708  	case types.Slice:
   709  		f = g.doSlice
   710  	case types.Struct:
   711  		f = g.doStruct
   712  	case types.Pointer:
   713  		f = g.doPointer
   714  	case types.Interface:
   715  		// interfaces are handled in-line in the other cases
   716  		klog.Fatalf("Hit an interface type %v. This should never happen.", t)
   717  	case types.Alias:
   718  		// can never happen because we branch on the underlying type which is never an alias
   719  		klog.Fatalf("Hit an alias type %v. This should never happen.", t)
   720  	default:
   721  		klog.Fatalf("Hit an unsupported type %v.", t)
   722  	}
   723  	f(t, sw)
   724  }
   725  
   726  // doBuiltin generates code for a builtin or an alias to a builtin. The generated code is
   727  // is the same for both cases, i.e. it's the code for the underlying type.
   728  func (g *genDeepCopy) doBuiltin(t *types.Type, sw *generator.SnippetWriter) {
   729  	if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
   730  		sw.Do("*out = in.DeepCopy()\n", nil)
   731  		return
   732  	}
   733  
   734  	sw.Do("*out = *in\n", nil)
   735  }
   736  
   737  // doMap generates code for a map or an alias to a map. The generated code is
   738  // is the same for both cases, i.e. it's the code for the underlying type.
   739  func (g *genDeepCopy) doMap(t *types.Type, sw *generator.SnippetWriter) {
   740  	ut := underlyingType(t)
   741  	uet := underlyingType(ut.Elem)
   742  
   743  	if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
   744  		sw.Do("*out = in.DeepCopy()\n", nil)
   745  		return
   746  	}
   747  
   748  	if !ut.Key.IsAssignable() {
   749  		klog.Fatalf("Hit an unsupported type %v for: %v", uet, t)
   750  	}
   751  
   752  	sw.Do("*out = make($.|raw$, len(*in))\n", t)
   753  	sw.Do("for key, val := range *in {\n", nil)
   754  	dc, dci := deepCopyMethodOrDie(ut.Elem), deepCopyIntoMethodOrDie(ut.Elem)
   755  	switch {
   756  	case dc != nil || dci != nil:
   757  		// Note: a DeepCopy exists because it is added if DeepCopyInto is manually defined
   758  		leftPointer := ut.Elem.Kind == types.Pointer
   759  		rightPointer := !isReference(ut.Elem)
   760  		if dc != nil {
   761  			rightPointer = dc.Results[0].Kind == types.Pointer
   762  		}
   763  		if leftPointer == rightPointer {
   764  			sw.Do("(*out)[key] = val.DeepCopy()\n", nil)
   765  		} else if leftPointer {
   766  			sw.Do("x := val.DeepCopy()\n", nil)
   767  			sw.Do("(*out)[key] = &x\n", nil)
   768  		} else {
   769  			sw.Do("(*out)[key] = *val.DeepCopy()\n", nil)
   770  		}
   771  	case ut.Elem.IsAnonymousStruct(): // not uet here because it needs type cast
   772  		sw.Do("(*out)[key] = val\n", nil)
   773  	case uet.IsAssignable():
   774  		sw.Do("(*out)[key] = val\n", nil)
   775  	case uet.Kind == types.Interface:
   776  		// Note: do not generate code that won't compile as `DeepCopyinterface{}()` is not a valid function
   777  		if uet.Name.Name == "interface{}" {
   778  			klog.Fatalf("DeepCopy of %q is unsupported. Instead, use named interfaces with DeepCopy<named-interface> as one of the methods.", uet.Name.Name)
   779  		}
   780  		sw.Do("if val == nil {(*out)[key]=nil} else {\n", nil)
   781  		// Note: if t.Elem has been an alias "J" of an interface "I" in Go, we will see it
   782  		// as kind Interface of name "J" here, i.e. generate val.DeepCopyJ(). The golang
   783  		// parser does not give us the underlying interface name. So we cannot do any better.
   784  		sw.Do(fmt.Sprintf("(*out)[key] = val.DeepCopy%s()\n", uet.Name.Name), nil)
   785  		sw.Do("}\n", nil)
   786  	case uet.Kind == types.Slice || uet.Kind == types.Map || uet.Kind == types.Pointer:
   787  		sw.Do("var outVal $.|raw$\n", uet)
   788  		sw.Do("if val == nil { (*out)[key] = nil } else {\n", nil)
   789  		sw.Do("in, out := &val, &outVal\n", uet)
   790  		g.generateFor(ut.Elem, sw)
   791  		sw.Do("}\n", nil)
   792  		sw.Do("(*out)[key] = outVal\n", nil)
   793  	case uet.Kind == types.Struct:
   794  		sw.Do("(*out)[key] = *val.DeepCopy()\n", uet)
   795  	default:
   796  		klog.Fatalf("Hit an unsupported type %v for %v", uet, t)
   797  	}
   798  	sw.Do("}\n", nil)
   799  }
   800  
   801  // doSlice generates code for a slice or an alias to a slice. The generated code is
   802  // is the same for both cases, i.e. it's the code for the underlying type.
   803  func (g *genDeepCopy) doSlice(t *types.Type, sw *generator.SnippetWriter) {
   804  	ut := underlyingType(t)
   805  	uet := underlyingType(ut.Elem)
   806  
   807  	if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
   808  		sw.Do("*out = in.DeepCopy()\n", nil)
   809  		return
   810  	}
   811  
   812  	sw.Do("*out = make($.|raw$, len(*in))\n", t)
   813  	if deepCopyMethodOrDie(ut.Elem) != nil || deepCopyIntoMethodOrDie(ut.Elem) != nil {
   814  		sw.Do("for i := range *in {\n", nil)
   815  		// Note: a DeepCopyInto exists because it is added if DeepCopy is manually defined
   816  		sw.Do("(*in)[i].DeepCopyInto(&(*out)[i])\n", nil)
   817  		sw.Do("}\n", nil)
   818  	} else if uet.Kind == types.Builtin || uet.IsAssignable() {
   819  		sw.Do("copy(*out, *in)\n", nil)
   820  	} else {
   821  		sw.Do("for i := range *in {\n", nil)
   822  		if uet.Kind == types.Slice || uet.Kind == types.Map || uet.Kind == types.Pointer || deepCopyMethodOrDie(ut.Elem) != nil || deepCopyIntoMethodOrDie(ut.Elem) != nil {
   823  			sw.Do("if (*in)[i] != nil {\n", nil)
   824  			sw.Do("in, out := &(*in)[i], &(*out)[i]\n", nil)
   825  			g.generateFor(ut.Elem, sw)
   826  			sw.Do("}\n", nil)
   827  		} else if uet.Kind == types.Interface {
   828  			// Note: do not generate code that won't compile as `DeepCopyinterface{}()` is not a valid function
   829  			if uet.Name.Name == "interface{}" {
   830  				klog.Fatalf("DeepCopy of %q is unsupported. Instead, use named interfaces with DeepCopy<named-interface> as one of the methods.", uet.Name.Name)
   831  			}
   832  			sw.Do("if (*in)[i] != nil {\n", nil)
   833  			// Note: if t.Elem has been an alias "J" of an interface "I" in Go, we will see it
   834  			// as kind Interface of name "J" here, i.e. generate val.DeepCopyJ(). The golang
   835  			// parser does not give us the underlying interface name. So we cannot do any better.
   836  			sw.Do(fmt.Sprintf("(*out)[i] = (*in)[i].DeepCopy%s()\n", uet.Name.Name), nil)
   837  			sw.Do("}\n", nil)
   838  		} else if uet.Kind == types.Struct {
   839  			sw.Do("(*in)[i].DeepCopyInto(&(*out)[i])\n", nil)
   840  		} else {
   841  			klog.Fatalf("Hit an unsupported type %v for %v", uet, t)
   842  		}
   843  		sw.Do("}\n", nil)
   844  	}
   845  }
   846  
   847  // doStruct generates code for a struct or an alias to a struct. The generated code is
   848  // is the same for both cases, i.e. it's the code for the underlying type.
   849  func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) {
   850  	ut := underlyingType(t)
   851  
   852  	if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
   853  		sw.Do("*out = in.DeepCopy()\n", nil)
   854  		return
   855  	}
   856  
   857  	// Simple copy covers a lot of cases.
   858  	sw.Do("*out = *in\n", nil)
   859  
   860  	// Now fix-up fields as needed.
   861  	for _, m := range ut.Members {
   862  		ft := m.Type
   863  		uft := underlyingType(ft)
   864  
   865  		args := generator.Args{
   866  			"type": ft,
   867  			"kind": ft.Kind,
   868  			"name": m.Name,
   869  		}
   870  		dc, dci := deepCopyMethodOrDie(ft), deepCopyIntoMethodOrDie(ft)
   871  		switch {
   872  		case dc != nil || dci != nil:
   873  			// Note: a DeepCopyInto exists because it is added if DeepCopy is manually defined
   874  			leftPointer := ft.Kind == types.Pointer
   875  			rightPointer := !isReference(ft)
   876  			if dc != nil {
   877  				rightPointer = dc.Results[0].Kind == types.Pointer
   878  			}
   879  			if leftPointer == rightPointer {
   880  				sw.Do("out.$.name$ = in.$.name$.DeepCopy()\n", args)
   881  			} else if leftPointer {
   882  				sw.Do("x := in.$.name$.DeepCopy()\n", args)
   883  				sw.Do("out.$.name$ =  = &x\n", args)
   884  			} else {
   885  				sw.Do("in.$.name$.DeepCopyInto(&out.$.name$)\n", args)
   886  			}
   887  		case uft.Kind == types.Builtin:
   888  			// the initial *out = *in was enough
   889  		case uft.Kind == types.Map, uft.Kind == types.Slice, uft.Kind == types.Pointer:
   890  			// Fixup non-nil reference-semantic types.
   891  			sw.Do("if in.$.name$ != nil {\n", args)
   892  			sw.Do("in, out := &in.$.name$, &out.$.name$\n", args)
   893  			g.generateFor(ft, sw)
   894  			sw.Do("}\n", nil)
   895  		case uft.Kind == types.Array:
   896  			sw.Do("out.$.name$ = in.$.name$\n", args)
   897  		case uft.Kind == types.Struct:
   898  			if ft.IsAssignable() {
   899  				sw.Do("out.$.name$ = in.$.name$\n", args)
   900  			} else {
   901  				sw.Do("in.$.name$.DeepCopyInto(&out.$.name$)\n", args)
   902  			}
   903  		case uft.Kind == types.Interface:
   904  			// Note: do not generate code that won't compile as `DeepCopyinterface{}()` is not a valid function
   905  			if uft.Name.Name == "interface{}" {
   906  				klog.Fatalf("DeepCopy of %q is unsupported. Instead, use named interfaces with DeepCopy<named-interface> as one of the methods.", uft.Name.Name)
   907  			}
   908  			sw.Do("if in.$.name$ != nil {\n", args)
   909  			// Note: if t.Elem has been an alias "J" of an interface "I" in Go, we will see it
   910  			// as kind Interface of name "J" here, i.e. generate val.DeepCopyJ(). The golang
   911  			// parser does not give us the underlying interface name. So we cannot do any better.
   912  			sw.Do(fmt.Sprintf("out.$.name$ = in.$.name$.DeepCopy%s()\n", uft.Name.Name), args)
   913  			sw.Do("}\n", nil)
   914  		default:
   915  			klog.Fatalf("Hit an unsupported type %v for %v, from %v", uft, ft, t)
   916  		}
   917  	}
   918  }
   919  
   920  // doPointer generates code for a pointer or an alias to a pointer. The generated code is
   921  // is the same for both cases, i.e. it's the code for the underlying type.
   922  func (g *genDeepCopy) doPointer(t *types.Type, sw *generator.SnippetWriter) {
   923  	ut := underlyingType(t)
   924  	uet := underlyingType(ut.Elem)
   925  
   926  	dc, dci := deepCopyMethodOrDie(ut.Elem), deepCopyIntoMethodOrDie(ut.Elem)
   927  	switch {
   928  	case dc != nil || dci != nil:
   929  		rightPointer := !isReference(ut.Elem)
   930  		if dc != nil {
   931  			rightPointer = dc.Results[0].Kind == types.Pointer
   932  		}
   933  		if rightPointer {
   934  			sw.Do("*out = (*in).DeepCopy()\n", nil)
   935  		} else {
   936  			sw.Do("x := (*in).DeepCopy()\n", nil)
   937  			sw.Do("*out = &x\n", nil)
   938  		}
   939  	case uet.IsAssignable():
   940  		sw.Do("*out = new($.Elem|raw$)\n", ut)
   941  		sw.Do("**out = **in", nil)
   942  	case uet.Kind == types.Map, uet.Kind == types.Slice, uet.Kind == types.Pointer:
   943  		sw.Do("*out = new($.Elem|raw$)\n", ut)
   944  		sw.Do("if **in != nil {\n", nil)
   945  		sw.Do("in, out := *in, *out\n", nil)
   946  		g.generateFor(uet, sw)
   947  		sw.Do("}\n", nil)
   948  	case uet.Kind == types.Struct:
   949  		sw.Do("*out = new($.Elem|raw$)\n", ut)
   950  		sw.Do("(*in).DeepCopyInto(*out)\n", nil)
   951  	default:
   952  		klog.Fatalf("Hit an unsupported type %v for %v", uet, t)
   953  	}
   954  }