traverse.go 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  1. /*
  2. Copyright 2019 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package deepcopy
  14. import (
  15. "fmt"
  16. "go/ast"
  17. "go/types"
  18. "io"
  19. "path"
  20. "strings"
  21. "unicode"
  22. "unicode/utf8"
  23. "sigs.k8s.io/controller-tools/pkg/loader"
  24. "sigs.k8s.io/controller-tools/pkg/markers"
  25. )
  26. // NB(directxman12): This code is a bit of a byzantine mess.
  27. // I've tried to clean it up a bit from the original in deepcopy-gen,
  28. // but parts remain a bit convoluted. Exercise caution when changing.
  29. // It's perhaps a tad over-commented now, but better safe than sorry.
  30. // It also seriously needs auditing for sanity -- there's parts where we
  31. // copy the original deepcopy-gen's output just to be safe, but some of that
  32. // could be simplified away if we're careful.
  33. // codeWriter assists in writing out Go code lines and blocks to a writer.
  34. type codeWriter struct {
  35. out io.Writer
  36. }
  37. // Line writes a single line.
  38. func (c *codeWriter) Line(line string) {
  39. fmt.Fprintln(c.out, line)
  40. }
  41. // Linef writes a single line with formatting (as per fmt.Sprintf).
  42. func (c *codeWriter) Linef(line string, args ...interface{}) {
  43. fmt.Fprintf(c.out, line+"\n", args...)
  44. }
  45. // If writes an if statement with the given setup/condition clause, executing
  46. // the given function to write the contents of the block.
  47. func (c *codeWriter) If(setup string, block func()) {
  48. c.Linef("if %s {", setup)
  49. block()
  50. c.Line("}")
  51. }
  52. // If writes if and else statements with the given setup/condition clause, executing
  53. // the given functions to write the contents of the blocks.
  54. func (c *codeWriter) IfElse(setup string, ifBlock func(), elseBlock func()) {
  55. c.Linef("if %s {", setup)
  56. ifBlock()
  57. c.Line("} else {")
  58. elseBlock()
  59. c.Line("}")
  60. }
  61. // For writes an for statement with the given setup/condition clause, executing
  62. // the given function to write the contents of the block.
  63. func (c *codeWriter) For(setup string, block func()) {
  64. c.Linef("for %s {", setup)
  65. block()
  66. c.Line("}")
  67. }
  68. // importsList keeps track of required imports, automatically assigning aliases
  69. // to import statement.
  70. type importsList struct {
  71. byPath map[string]string
  72. byAlias map[string]string
  73. pkg *loader.Package
  74. }
  75. // NeedImport marks that the given package is needed in the list of imports,
  76. // returning the ident (import alias) that should be used to reference the package.
  77. func (l *importsList) NeedImport(importPath string) string {
  78. // we get an actual path from Package, which might include venddored
  79. // packages if running on a package in vendor.
  80. if ind := strings.LastIndex(importPath, "/vendor/"); ind != -1 {
  81. importPath = importPath[ind+8: /* len("/vendor/") */]
  82. }
  83. // check to see if we've already assigned an alias, and just return that.
  84. alias, exists := l.byPath[importPath]
  85. if exists {
  86. return alias
  87. }
  88. // otherwise, calculate an import alias by joining path parts till we get something unique
  89. restPath, nextWord := path.Split(importPath)
  90. for otherPath, exists := "", true; exists && otherPath != importPath; otherPath, exists = l.byAlias[alias] {
  91. if restPath == "" {
  92. // do something else to disambiguate if we're run out of parts and
  93. // still have duplicates, somehow
  94. alias += "x"
  95. }
  96. // can't have a first digit, per Go identifier rules, so just skip them
  97. for firstRune, runeLen := utf8.DecodeRuneInString(nextWord); unicode.IsDigit(firstRune); firstRune, runeLen = utf8.DecodeRuneInString(nextWord) {
  98. nextWord = nextWord[runeLen:]
  99. }
  100. // make a valid identifier by replacing "bad" characters with underscores
  101. nextWord = strings.Map(func(r rune) rune {
  102. if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' {
  103. return r
  104. }
  105. return '_'
  106. }, nextWord)
  107. alias = nextWord + alias
  108. if len(restPath) > 0 {
  109. restPath, nextWord = path.Split(restPath[:len(restPath)-1] /* chop off final slash */)
  110. }
  111. }
  112. l.byPath[importPath] = alias
  113. l.byAlias[alias] = importPath
  114. return alias
  115. }
  116. // ImportSpecs returns a string form of each import spec
  117. // (i.e. `alias "path/to/import"). Aliases are only present
  118. // when they don't match the package name.
  119. func (l *importsList) ImportSpecs() []string {
  120. res := make([]string, 0, len(l.byPath))
  121. for importPath, alias := range l.byPath {
  122. pkg := l.pkg.Imports()[importPath]
  123. if pkg != nil && pkg.Name == alias {
  124. // don't print if alias is the same as package name
  125. // (we've already taken care of duplicates).
  126. res = append(res, fmt.Sprintf("%q", importPath))
  127. } else {
  128. res = append(res, fmt.Sprintf("%s %q", alias, importPath))
  129. }
  130. }
  131. return res
  132. }
  133. // namingInfo holds package and syntax for referencing a field, type,
  134. // etc. It's used to allow lazily marking import usage.
  135. // You should generally retrieve the syntax using Syntax.
  136. type namingInfo struct {
  137. // typeInfo is the type being named.
  138. typeInfo types.Type
  139. nameOverride string
  140. }
  141. // Syntax calculates the code representation of the given type or name,
  142. // and marks that is used (potentially marking an import as used).
  143. func (n *namingInfo) Syntax(basePkg *loader.Package, imports *importsList) string {
  144. if n.nameOverride != "" {
  145. return n.nameOverride
  146. }
  147. // NB(directxman12): typeInfo.String gets us most of the way there,
  148. // but fails (for us) on named imports, since it uses the full package path.
  149. switch typeInfo := n.typeInfo.(type) {
  150. case *types.Named:
  151. // register that we need an import for this type,
  152. // so we can get the appropriate alias to use.
  153. typeName := typeInfo.Obj()
  154. otherPkg := typeName.Pkg()
  155. if otherPkg == basePkg.Types {
  156. // local import
  157. return typeName.Name()
  158. }
  159. alias := imports.NeedImport(loader.NonVendorPath(otherPkg.Path()))
  160. return alias + "." + typeName.Name()
  161. case *types.Basic:
  162. return typeInfo.String()
  163. case *types.Pointer:
  164. return "*" + (&namingInfo{typeInfo: typeInfo.Elem()}).Syntax(basePkg, imports)
  165. case *types.Slice:
  166. return "[]" + (&namingInfo{typeInfo: typeInfo.Elem()}).Syntax(basePkg, imports)
  167. case *types.Map:
  168. return fmt.Sprintf(
  169. "map[%s]%s",
  170. (&namingInfo{typeInfo: typeInfo.Key()}).Syntax(basePkg, imports),
  171. (&namingInfo{typeInfo: typeInfo.Elem()}).Syntax(basePkg, imports))
  172. default:
  173. basePkg.AddError(fmt.Errorf("name requested for invalid type: %s", typeInfo))
  174. return typeInfo.String()
  175. }
  176. }
  177. // copyMethodMakers makes DeepCopy (and related) methods for Go types,
  178. // writing them to its codeWriter.
  179. type copyMethodMaker struct {
  180. pkg *loader.Package
  181. *importsList
  182. *codeWriter
  183. }
  184. // GenerateMethodsFor makes DeepCopy, DeepCopyInto, and DeepCopyObject methods
  185. // for the given type, when appropriate
  186. func (c *copyMethodMaker) GenerateMethodsFor(root *loader.Package, info *markers.TypeInfo) {
  187. typeInfo := root.TypesInfo.TypeOf(info.RawSpec.Name)
  188. if typeInfo == types.Typ[types.Invalid] {
  189. root.AddError(loader.ErrFromNode(fmt.Errorf("unknown type: %s", info.Name), info.RawSpec))
  190. }
  191. // figure out if we need to use a pointer receiver -- most types get a pointer receiver,
  192. // except those that are aliases to types that are already pass-by-reference (pointers,
  193. // interfaces. maps, slices).
  194. ptrReceiver := usePtrReceiver(typeInfo)
  195. hasManualDeepCopyInto := hasDeepCopyIntoMethod(root, typeInfo)
  196. hasManualDeepCopy, deepCopyOnPtr := hasDeepCopyMethod(root, typeInfo)
  197. // only generate each method if it hasn't been implemented.
  198. if !hasManualDeepCopyInto {
  199. c.Line("// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.")
  200. if ptrReceiver {
  201. c.Linef("func (in *%s) DeepCopyInto(out *%s) {", info.Name, info.Name)
  202. } else {
  203. c.Linef("func (in %s) DeepCopyInto(out *%s) {", info.Name, info.Name)
  204. c.Line("{in := &in") // add an extra block so that we can redefine `in` without type issues
  205. }
  206. // just wrap the existing deepcopy if present
  207. if hasManualDeepCopy {
  208. if deepCopyOnPtr {
  209. c.Line("clone := in.DeepCopy()")
  210. c.Line("*out = *clone")
  211. } else {
  212. c.Line("*out = in.DeepCopy()")
  213. }
  214. } else {
  215. c.genDeepCopyIntoBlock(&namingInfo{nameOverride: info.Name}, typeInfo)
  216. }
  217. if !ptrReceiver {
  218. c.Line("}") // close our extra "in redefinition" block
  219. }
  220. c.Line("}")
  221. }
  222. if !hasManualDeepCopy {
  223. // these are both straightforward, so we just template them out.
  224. if ptrReceiver {
  225. c.Linef(ptrDeepCopy, info.Name)
  226. } else {
  227. c.Linef(bareDeepCopy, info.Name)
  228. }
  229. // maybe also generate DeepCopyObject, if asked.
  230. if genObjectInterface(info) {
  231. // we always need runtime.Object for DeepCopyObject
  232. runtimeAlias := c.NeedImport("k8s.io/apimachinery/pkg/runtime")
  233. if ptrReceiver {
  234. c.Linef(ptrDeepCopyObj, info.Name, runtimeAlias)
  235. } else {
  236. c.Linef(bareDeepCopyObj, info.Name, runtimeAlias)
  237. }
  238. }
  239. }
  240. }
  241. // genDeepCopyBody generates a DeepCopyInto block for the given type. The
  242. // block is *not* wrapped in curly braces.
  243. func (c *copyMethodMaker) genDeepCopyIntoBlock(actualName *namingInfo, typeInfo types.Type) {
  244. // we calculate *how* we should copy mostly based on the "eventual" type of
  245. // a given type (i.e. the type that results from following all aliases)
  246. last := eventualUnderlyingType(typeInfo)
  247. // we might hit a type that has a manual deepcopy method written on non-root types
  248. // (this case is handled for root types in GenerateMethodFor).
  249. // In that case (when we're not dealing with a pointer, since those need special handling
  250. // to match 1-to-1 with k8s deepcopy-gen), just use that.
  251. if _, isPtr := last.(*types.Pointer); !isPtr && hasAnyDeepCopyMethod(c.pkg, typeInfo) {
  252. c.Line("*out = in.DeepCopy()")
  253. return
  254. }
  255. switch last := last.(type) {
  256. case *types.Basic:
  257. switch last.Kind() {
  258. case types.Invalid, types.UnsafePointer:
  259. c.pkg.AddError(fmt.Errorf("invalid type: %s", last))
  260. default:
  261. // basic types themselves can be "shallow" copied, so all we need
  262. // to do is check if our *actual* type (not the underlying one) has
  263. // a custom method implemented.
  264. if hasMethod, _ := hasDeepCopyMethod(c.pkg, typeInfo); hasMethod {
  265. c.Line("*out = in.DeepCopy()")
  266. }
  267. c.Line("*out = *in")
  268. }
  269. case *types.Map:
  270. c.genMapDeepCopy(actualName, last)
  271. case *types.Slice:
  272. c.genSliceDeepCopy(actualName, last)
  273. case *types.Struct:
  274. c.genStructDeepCopy(actualName, last)
  275. case *types.Pointer:
  276. c.genPointerDeepCopy(actualName, last)
  277. case *types.Named:
  278. // handled via the above loop, should never happen
  279. c.pkg.AddError(fmt.Errorf("interface type %s encountered directly, invalid condition", last))
  280. default:
  281. c.pkg.AddError(fmt.Errorf("invalid type: %s", last))
  282. }
  283. }
  284. // genMapDeepCopy generates DeepCopy code for the given named type whose eventual
  285. // type is the given map type.
  286. func (c *copyMethodMaker) genMapDeepCopy(actualName *namingInfo, mapType *types.Map) {
  287. // maps *must* have shallow-copiable types, since we just iterate
  288. // through the keys, only trying to deepcopy the values.
  289. if !fineToShallowCopy(mapType.Key()) {
  290. c.pkg.AddError(fmt.Errorf("invalid map key type: %s", mapType.Key()))
  291. return
  292. }
  293. // make our actual type (not the underlying one)...
  294. c.Linef("*out = make(%[1]s, len(*in))", actualName.Syntax(c.pkg, c.importsList))
  295. // ...and copy each element appropriately
  296. c.For("key, val := range *in", func() {
  297. // check if we have manually written methods,
  298. // in which case we'll just try and use those
  299. hasDeepCopy, copyOnPtr := hasDeepCopyMethod(c.pkg, mapType.Elem())
  300. hasDeepCopyInto := hasDeepCopyIntoMethod(c.pkg, mapType.Elem())
  301. switch {
  302. case hasDeepCopyInto || hasDeepCopy:
  303. // use the manually-written methods
  304. _, fieldIsPtr := mapType.Elem().(*types.Pointer) // is "out" actually a pointer
  305. inIsPtr := resultWillBePointer(mapType.Elem(), hasDeepCopy, copyOnPtr) // does copying "in" produce a pointer
  306. if hasDeepCopy {
  307. // If we're calling DeepCopy, check if it's receiver needs a pointer
  308. inIsPtr = copyOnPtr
  309. }
  310. if inIsPtr == fieldIsPtr {
  311. c.Line("(*out)[key] = val.DeepCopy()")
  312. } else if fieldIsPtr {
  313. c.Line("{") // use a block because we use `x` as a temporary
  314. c.Line("x := val.DeepCopy()")
  315. c.Line("(*out)[key] = &x")
  316. c.Line("}")
  317. } else {
  318. c.Line("(*out)[key] = *val.DeepCopy()")
  319. }
  320. case fineToShallowCopy(mapType.Elem()):
  321. // just shallow copy types for which it's safe to do so
  322. c.Line("(*out)[key] = val")
  323. default:
  324. // otherwise, we've got some kind-specific actions,
  325. // based on the element's eventual type.
  326. underlyingElem := eventualUnderlyingType(mapType.Elem())
  327. // if it passes by reference, let the main switch handle it
  328. if passesByReference(underlyingElem) {
  329. c.Linef("var outVal %[1]s", (&namingInfo{typeInfo: underlyingElem}).Syntax(c.pkg, c.importsList))
  330. c.IfElse("val == nil", func() {
  331. c.Line("(*out)[key] = nil")
  332. }, func() {
  333. c.Line("in, out := &val, &outVal")
  334. c.genDeepCopyIntoBlock(&namingInfo{typeInfo: mapType.Elem()}, mapType.Elem())
  335. })
  336. c.Line("(*out)[key] = outVal")
  337. return
  338. }
  339. // otherwise...
  340. switch underlyingElem := underlyingElem.(type) {
  341. case *types.Struct:
  342. // structs will have deepcopy generated for them, so use that
  343. c.Line("(*out)[key] = *val.DeepCopy()")
  344. default:
  345. c.pkg.AddError(fmt.Errorf("invalid map value type: %s", underlyingElem))
  346. return
  347. }
  348. }
  349. })
  350. }
  351. // genSliceDeepCopy generates DeepCopy code for the given named type whose
  352. // underlying type is the given slice.
  353. func (c *copyMethodMaker) genSliceDeepCopy(actualName *namingInfo, sliceType *types.Slice) {
  354. underlyingElem := eventualUnderlyingType(sliceType.Elem())
  355. // make the actual type (not the underlying)
  356. c.Linef("*out = make(%[1]s, len(*in))", actualName.Syntax(c.pkg, c.importsList))
  357. // check if we need to do anything special, or just copy each element appropriately
  358. switch {
  359. case hasAnyDeepCopyMethod(c.pkg, sliceType.Elem()):
  360. // just use deepcopy if it's present (deepcopyinto will be filled in by our code)
  361. c.For("i := range *in", func() {
  362. c.Line("(*in)[i].DeepCopyInto(&(*out)[i])")
  363. })
  364. case fineToShallowCopy(underlyingElem):
  365. // shallow copy if ok
  366. c.Line("copy(*out, *in)")
  367. default:
  368. // copy each element appropriately
  369. c.For("i := range *in", func() {
  370. // fall back to normal code for reference types or those with custom logic
  371. if passesByReference(underlyingElem) || hasAnyDeepCopyMethod(c.pkg, sliceType.Elem()) {
  372. c.If("(*in)[i] != nil", func() {
  373. c.Line("in, out := &(*in)[i], &(*out)[i]")
  374. c.genDeepCopyIntoBlock(&namingInfo{typeInfo: sliceType.Elem()}, sliceType.Elem())
  375. })
  376. return
  377. }
  378. switch underlyingElem.(type) {
  379. case *types.Struct:
  380. // structs will always have deepcopy
  381. c.Linef("(*in)[i].DeepCopyInto(&(*out)[i])")
  382. default:
  383. c.pkg.AddError(fmt.Errorf("invalid slice element type: %s", underlyingElem))
  384. }
  385. })
  386. }
  387. }
  388. // genStructDeepCopy generates DeepCopy code for the given named type whose
  389. // underlying type is the given struct.
  390. func (c *copyMethodMaker) genStructDeepCopy(_ *namingInfo, structType *types.Struct) {
  391. c.Line("*out = *in")
  392. for i := 0; i < structType.NumFields(); i++ {
  393. field := structType.Field(i)
  394. // if we have a manual deepcopy, use that
  395. hasDeepCopy, copyOnPtr := hasDeepCopyMethod(c.pkg, field.Type())
  396. hasDeepCopyInto := hasDeepCopyIntoMethod(c.pkg, field.Type())
  397. if hasDeepCopyInto || hasDeepCopy {
  398. // NB(directxman12): yes, I know this is kind-of weird that we
  399. // have all this special-casing here, but it's nice for testing
  400. // purposes to be 1-to-1 with deepcopy-gen, which does all sorts of
  401. // stuff like this (I'm pretty sure I found some codepaths that
  402. // never execute there, because they're pretty clearly invalid
  403. // syntax).
  404. _, fieldIsPtr := field.Type().(*types.Pointer)
  405. inIsPtr := resultWillBePointer(field.Type(), hasDeepCopy, copyOnPtr)
  406. if fieldIsPtr {
  407. // we'll need a if block to check for nilness
  408. // we'll let genDeepCopyIntoBlock handle the details, we just needed the setup
  409. c.If(fmt.Sprintf("in.%s != nil", field.Name()), func() {
  410. c.Linef("in, out := &in.%[1]s, &out.%[1]s", field.Name())
  411. c.genDeepCopyIntoBlock(&namingInfo{typeInfo: field.Type()}, field.Type())
  412. })
  413. } else {
  414. // special-case for compatibility with deepcopy-gen
  415. if inIsPtr == fieldIsPtr {
  416. c.Linef("out.%[1]s = in.%[1]s.DeepCopy()", field.Name())
  417. } else {
  418. c.Linef("in.%[1]s.DeepCopyInto(&out.%[1]s)", field.Name())
  419. }
  420. }
  421. continue
  422. }
  423. // pass-by-reference fields get delegated to the main type
  424. underlyingField := eventualUnderlyingType(field.Type())
  425. if passesByReference(underlyingField) {
  426. c.If(fmt.Sprintf("in.%s != nil", field.Name()), func() {
  427. c.Linef("in, out := &in.%[1]s, &out.%[1]s", field.Name())
  428. c.genDeepCopyIntoBlock(&namingInfo{typeInfo: field.Type()}, field.Type())
  429. })
  430. continue
  431. }
  432. // otherwise...
  433. switch underlyingField := underlyingField.(type) {
  434. case *types.Basic:
  435. switch underlyingField.Kind() {
  436. case types.Invalid, types.UnsafePointer:
  437. c.pkg.AddError(loader.ErrFromNode(fmt.Errorf("invalid field type: %s", underlyingField), field))
  438. return
  439. default:
  440. // nothing to do, initial assignment copied this
  441. }
  442. case *types.Struct:
  443. if fineToShallowCopy(field.Type()) {
  444. c.Linef("out.%[1]s = in.%[1]s", field.Name())
  445. } else {
  446. c.Linef("in.%[1]s.DeepCopyInto(&out.%[1]s)", field.Name())
  447. }
  448. default:
  449. c.pkg.AddError(loader.ErrFromNode(fmt.Errorf("invalid field type: %s", underlyingField), field))
  450. return
  451. }
  452. }
  453. }
  454. // genPointerDeepCopy generates DeepCopy code for the given named type whose
  455. // underlying type is the given struct.
  456. func (c *copyMethodMaker) genPointerDeepCopy(_ *namingInfo, pointerType *types.Pointer) {
  457. underlyingElem := eventualUnderlyingType(pointerType.Elem())
  458. // if we have a manually written deepcopy, just use that
  459. hasDeepCopy, copyOnPtr := hasDeepCopyMethod(c.pkg, pointerType.Elem())
  460. hasDeepCopyInto := hasDeepCopyIntoMethod(c.pkg, pointerType.Elem())
  461. if hasDeepCopyInto || hasDeepCopy {
  462. outNeedsPtr := resultWillBePointer(pointerType.Elem(), hasDeepCopy, copyOnPtr)
  463. if hasDeepCopy {
  464. outNeedsPtr = copyOnPtr
  465. }
  466. if outNeedsPtr {
  467. c.Line("*out = (*in).DeepCopy()")
  468. } else {
  469. c.Line("x := (*in).DeepCopy()")
  470. c.Line("*out = &x")
  471. }
  472. return
  473. }
  474. // shallow-copiable types are pretty easy
  475. if fineToShallowCopy(underlyingElem) {
  476. c.Linef("*out = new(%[1]s)", (&namingInfo{typeInfo: pointerType.Elem()}).Syntax(c.pkg, c.importsList))
  477. c.Line("**out = **in")
  478. return
  479. }
  480. // pass-by-reference types get delegated to the main switch
  481. if passesByReference(underlyingElem) {
  482. c.Linef("*out = new(%s)", (&namingInfo{typeInfo: underlyingElem}).Syntax(c.pkg, c.importsList))
  483. c.If("**in != nil", func() {
  484. c.Line("in, out := *in, *out")
  485. c.genDeepCopyIntoBlock(&namingInfo{typeInfo: underlyingElem}, eventualUnderlyingType(underlyingElem))
  486. })
  487. return
  488. }
  489. // otherwise...
  490. switch underlyingElem := underlyingElem.(type) {
  491. case *types.Struct:
  492. c.Linef("*out = new(%[1]s)", (&namingInfo{typeInfo: pointerType.Elem()}).Syntax(c.pkg, c.importsList))
  493. c.Line("(*in).DeepCopyInto(*out)")
  494. default:
  495. c.pkg.AddError(fmt.Errorf("invalid pointer element type: %s", underlyingElem))
  496. return
  497. }
  498. }
  499. // usePtrReceiver checks if we need a pointer receiver on methods for the given type
  500. // Pass-by-reference types don't get pointer receivers.
  501. func usePtrReceiver(typeInfo types.Type) bool {
  502. switch typeInfo.(type) {
  503. case *types.Pointer:
  504. return false
  505. case *types.Map:
  506. return false
  507. case *types.Slice:
  508. return false
  509. case *types.Named:
  510. return usePtrReceiver(typeInfo.Underlying())
  511. default:
  512. return true
  513. }
  514. }
  515. func resultWillBePointer(typeInfo types.Type, hasDeepCopy, deepCopyOnPtr bool) bool {
  516. // if we have a manual deepcopy, we can just check what that returns
  517. if hasDeepCopy {
  518. return deepCopyOnPtr
  519. }
  520. // otherwise, we'll need to check its type
  521. switch typeInfo := typeInfo.(type) {
  522. case *types.Pointer:
  523. // NB(directxman12): we don't have to worry about the elem having a deepcopy,
  524. // since hasManualDeepCopy would've caught that.
  525. // we'll be calling on the elem, so check that
  526. return resultWillBePointer(typeInfo.Elem(), false, false)
  527. case *types.Map:
  528. return false
  529. case *types.Slice:
  530. return false
  531. case *types.Named:
  532. return resultWillBePointer(typeInfo.Underlying(), false, false)
  533. default:
  534. return true
  535. }
  536. }
  537. // shouldBeCopied checks if we're supposed to make deepcopy methods the given type.
  538. //
  539. // This is the case if it's exported *and* either:
  540. // - has a partial manual DeepCopy implementation (in which case we fill in the rest)
  541. // - aliases to a non-basic type eventually
  542. // - is a struct
  543. func shouldBeCopied(pkg *loader.Package, info *markers.TypeInfo) bool {
  544. if !ast.IsExported(info.Name) {
  545. return false
  546. }
  547. typeInfo := pkg.TypesInfo.TypeOf(info.RawSpec.Name)
  548. if typeInfo == types.Typ[types.Invalid] {
  549. pkg.AddError(loader.ErrFromNode(fmt.Errorf("unknown type: %s", info.Name), info.RawSpec))
  550. return false
  551. }
  552. // according to gengo, everything named is an alias, except for an alias to a pointer,
  553. // which is just a pointer, afaict. Just roll with it.
  554. if asPtr, isPtr := typeInfo.(*types.Named).Underlying().(*types.Pointer); isPtr {
  555. typeInfo = asPtr
  556. }
  557. lastType := typeInfo
  558. if _, isNamed := typeInfo.(*types.Named); isNamed {
  559. // if it has a manual deepcopy or deepcopyinto, we're fine
  560. if hasAnyDeepCopyMethod(pkg, typeInfo) {
  561. return true
  562. }
  563. for underlyingType := typeInfo.Underlying(); underlyingType != lastType; lastType, underlyingType = underlyingType, underlyingType.Underlying() {
  564. // if it has a manual deepcopy or deepcopyinto, we're fine
  565. if hasAnyDeepCopyMethod(pkg, underlyingType) {
  566. return true
  567. }
  568. // aliases to other things besides basics need copy methods
  569. // (basics can be straight-up shallow-copied)
  570. if _, isBasic := underlyingType.(*types.Basic); !isBasic {
  571. return true
  572. }
  573. }
  574. }
  575. // structs are the only thing that's not a basic that's copiable by default
  576. _, isStruct := lastType.(*types.Struct)
  577. return isStruct
  578. }
  579. // hasDeepCopyMethod checks if this type has a manual DeepCopy method and if
  580. // the method has a pointer receiver.
  581. func hasDeepCopyMethod(pkg *loader.Package, typeInfo types.Type) (bool, bool) {
  582. deepCopyMethod, ind, _ := types.LookupFieldOrMethod(typeInfo, true /* check pointers too */, pkg.Types, "DeepCopy")
  583. if len(ind) != 1 {
  584. // ignore embedded methods
  585. return false, false
  586. }
  587. if deepCopyMethod == nil {
  588. return false, false
  589. }
  590. methodSig := deepCopyMethod.Type().(*types.Signature)
  591. if methodSig.Params() != nil && methodSig.Params().Len() != 0 {
  592. return false, false
  593. }
  594. if methodSig.Results() == nil || methodSig.Results().Len() != 1 {
  595. return false, false
  596. }
  597. recvAsPtr, recvIsPtr := methodSig.Recv().Type().(*types.Pointer)
  598. if recvIsPtr {
  599. // NB(directxman12): the pointer type returned here isn't comparable even though they
  600. // have the same underlying type, for some reason (probably that
  601. // LookupFieldOrMethod calls types.NewPointer for us), so check the
  602. // underlying values.
  603. resultPtr, resultIsPtr := methodSig.Results().At(0).Type().(*types.Pointer)
  604. if !resultIsPtr {
  605. // pointer vs non-pointer are different types
  606. return false, false
  607. }
  608. if recvAsPtr.Elem() != resultPtr.Elem() {
  609. return false, false
  610. }
  611. } else if methodSig.Results().At(0).Type() != methodSig.Recv().Type() {
  612. return false, false
  613. }
  614. return true, recvIsPtr
  615. }
  616. // hasDeepCopyIntoMethod checks if this type has a manual DeepCopyInto method.
  617. func hasDeepCopyIntoMethod(pkg *loader.Package, typeInfo types.Type) bool {
  618. deepCopyMethod, ind, _ := types.LookupFieldOrMethod(typeInfo, true /* check pointers too */, pkg.Types, "DeepCopyInto")
  619. if len(ind) != 1 {
  620. // ignore embedded methods
  621. return false
  622. }
  623. if deepCopyMethod == nil {
  624. return false
  625. }
  626. methodSig := deepCopyMethod.Type().(*types.Signature)
  627. if methodSig.Params() == nil || methodSig.Params().Len() != 1 {
  628. return false
  629. }
  630. paramPtr, isPtr := methodSig.Params().At(0).Type().(*types.Pointer)
  631. if !isPtr {
  632. return false
  633. }
  634. if methodSig.Results() != nil && methodSig.Results().Len() != 0 {
  635. return false
  636. }
  637. if recvPtr, recvIsPtr := methodSig.Recv().Type().(*types.Pointer); recvIsPtr {
  638. // NB(directxman12): the pointer type returned here isn't comparable even though they
  639. // have the same underlying type, for some reason (probably that
  640. // LookupFieldOrMethod calls types.NewPointer for us), so check the
  641. // underlying values.
  642. return paramPtr.Elem() == recvPtr.Elem()
  643. }
  644. return methodSig.Recv().Type() == paramPtr.Elem()
  645. }
  646. // hasAnyDeepCopyMethod checks if the given method has DeepCopy or DeepCopyInto
  647. // (either of which implies the other will exist eventually).
  648. func hasAnyDeepCopyMethod(pkg *loader.Package, typeInfo types.Type) bool {
  649. hasDeepCopy, _ := hasDeepCopyMethod(pkg, typeInfo)
  650. return hasDeepCopy || hasDeepCopyIntoMethod(pkg, typeInfo)
  651. }
  652. // eventualUnderlyingType gets the "final" type in a sequence of named aliases.
  653. // It's effectively a shortcut for calling Underlying in a loop.
  654. func eventualUnderlyingType(typeInfo types.Type) types.Type {
  655. last := typeInfo
  656. for underlying := typeInfo.Underlying(); underlying != last; last, underlying = underlying, underlying.Underlying() {
  657. // get the actual underlying type
  658. }
  659. return last
  660. }
  661. // fineToShallowCopy checks if a shallow-copying a type is equivalent to deepcopy-ing it.
  662. func fineToShallowCopy(typeInfo types.Type) bool {
  663. switch typeInfo := typeInfo.(type) {
  664. case *types.Basic:
  665. // basic types (int, string, etc) are always fine to shallow-copy,
  666. // except for Invalid and UnsafePointer, which can't be copied at all.
  667. switch typeInfo.Kind() {
  668. case types.Invalid, types.UnsafePointer:
  669. return false
  670. default:
  671. return true
  672. }
  673. case *types.Named:
  674. // aliases are fine to shallow-copy as long as they resolve to a shallow-copyable type
  675. return fineToShallowCopy(typeInfo.Underlying())
  676. case *types.Struct:
  677. // structs are fine to shallow-copy if they have all shallow-copyable fields
  678. for i := 0; i < typeInfo.NumFields(); i++ {
  679. field := typeInfo.Field(i)
  680. if !fineToShallowCopy(field.Type()) {
  681. return false
  682. }
  683. }
  684. return true
  685. default:
  686. return false
  687. }
  688. }
  689. // passesByReference checks if the given type passesByReference
  690. // (except for interfaces, which are handled separately).
  691. func passesByReference(typeInfo types.Type) bool {
  692. switch typeInfo.(type) {
  693. case *types.Slice:
  694. return true
  695. case *types.Map:
  696. return true
  697. case *types.Pointer:
  698. return true
  699. default:
  700. return false
  701. }
  702. }
  703. var (
  704. // ptrDeepCopy is a DeepCopy for a type with an existing DeepCopyInto and a pointer receiver.
  705. ptrDeepCopy = `
  706. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new %[1]s.
  707. func (in *%[1]s) DeepCopy() *%[1]s {
  708. if in == nil { return nil }
  709. out := new(%[1]s)
  710. in.DeepCopyInto(out)
  711. return out
  712. }
  713. `
  714. // ptrDeepCopy is a DeepCopy for a type with an existing DeepCopyInto and a non-pointer receiver.
  715. bareDeepCopy = `
  716. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new %[1]s.
  717. func (in %[1]s) DeepCopy() %[1]s {
  718. if in == nil { return nil }
  719. out := new(%[1]s)
  720. in.DeepCopyInto(out)
  721. return *out
  722. }
  723. `
  724. // ptrDeepCopy is a DeepCopyObject for a type with an existing DeepCopyInto and a pointer receiver.
  725. ptrDeepCopyObj = `
  726. // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
  727. func (in *%[1]s) DeepCopyObject() %[2]s.Object {
  728. if c := in.DeepCopy(); c != nil {
  729. return c
  730. }
  731. return nil
  732. }
  733. `
  734. // ptrDeepCopy is a DeepCopyObject for a type with an existing DeepCopyInto and a non-pointer receiver.
  735. bareDeepCopyObj = `
  736. // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
  737. func (in %[1]s) DeepCopyObject() %[2]s.Object {
  738. return in.DeepCopy()
  739. }
  740. `
  741. )