traverse.go 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  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("inVal := (*in)[key]")
  334. c.Line("in, out := &inVal, &outVal")
  335. c.genDeepCopyIntoBlock(&namingInfo{typeInfo: mapType.Elem()}, mapType.Elem())
  336. })
  337. c.Line("(*out)[key] = outVal")
  338. return
  339. }
  340. // otherwise...
  341. switch underlyingElem := underlyingElem.(type) {
  342. case *types.Struct:
  343. // structs will have deepcopy generated for them, so use that
  344. c.Line("(*out)[key] = *val.DeepCopy()")
  345. default:
  346. c.pkg.AddError(fmt.Errorf("invalid map value type: %s", underlyingElem))
  347. return
  348. }
  349. }
  350. })
  351. }
  352. // genSliceDeepCopy generates DeepCopy code for the given named type whose
  353. // underlying type is the given slice.
  354. func (c *copyMethodMaker) genSliceDeepCopy(actualName *namingInfo, sliceType *types.Slice) {
  355. underlyingElem := eventualUnderlyingType(sliceType.Elem())
  356. // make the actual type (not the underlying)
  357. c.Linef("*out = make(%[1]s, len(*in))", actualName.Syntax(c.pkg, c.importsList))
  358. // check if we need to do anything special, or just copy each element appropriately
  359. switch {
  360. case hasAnyDeepCopyMethod(c.pkg, sliceType.Elem()):
  361. // just use deepcopy if it's present (deepcopyinto will be filled in by our code)
  362. c.For("i := range *in", func() {
  363. c.Line("(*in)[i].DeepCopyInto(&(*out)[i])")
  364. })
  365. case fineToShallowCopy(underlyingElem):
  366. // shallow copy if ok
  367. c.Line("copy(*out, *in)")
  368. default:
  369. // copy each element appropriately
  370. c.For("i := range *in", func() {
  371. // fall back to normal code for reference types or those with custom logic
  372. if passesByReference(underlyingElem) || hasAnyDeepCopyMethod(c.pkg, sliceType.Elem()) {
  373. c.If("(*in)[i] != nil", func() {
  374. c.Line("in, out := &(*in)[i], &(*out)[i]")
  375. c.genDeepCopyIntoBlock(&namingInfo{typeInfo: sliceType.Elem()}, sliceType.Elem())
  376. })
  377. return
  378. }
  379. switch underlyingElem.(type) {
  380. case *types.Struct:
  381. // structs will always have deepcopy
  382. c.Linef("(*in)[i].DeepCopyInto(&(*out)[i])")
  383. default:
  384. c.pkg.AddError(fmt.Errorf("invalid slice element type: %s", underlyingElem))
  385. }
  386. })
  387. }
  388. }
  389. // genStructDeepCopy generates DeepCopy code for the given named type whose
  390. // underlying type is the given struct.
  391. func (c *copyMethodMaker) genStructDeepCopy(_ *namingInfo, structType *types.Struct) {
  392. c.Line("*out = *in")
  393. for i := 0; i < structType.NumFields(); i++ {
  394. field := structType.Field(i)
  395. // if we have a manual deepcopy, use that
  396. hasDeepCopy, copyOnPtr := hasDeepCopyMethod(c.pkg, field.Type())
  397. hasDeepCopyInto := hasDeepCopyIntoMethod(c.pkg, field.Type())
  398. if hasDeepCopyInto || hasDeepCopy {
  399. // NB(directxman12): yes, I know this is kind-of weird that we
  400. // have all this special-casing here, but it's nice for testing
  401. // purposes to be 1-to-1 with deepcopy-gen, which does all sorts of
  402. // stuff like this (I'm pretty sure I found some codepaths that
  403. // never execute there, because they're pretty clearly invalid
  404. // syntax).
  405. _, fieldIsPtr := field.Type().(*types.Pointer)
  406. inIsPtr := resultWillBePointer(field.Type(), hasDeepCopy, copyOnPtr)
  407. if fieldIsPtr {
  408. // we'll need a if block to check for nilness
  409. // we'll let genDeepCopyIntoBlock handle the details, we just needed the setup
  410. c.If(fmt.Sprintf("in.%s != nil", field.Name()), func() {
  411. c.Linef("in, out := &in.%[1]s, &out.%[1]s", field.Name())
  412. c.genDeepCopyIntoBlock(&namingInfo{typeInfo: field.Type()}, field.Type())
  413. })
  414. } else {
  415. // special-case for compatibility with deepcopy-gen
  416. if inIsPtr == fieldIsPtr {
  417. c.Linef("out.%[1]s = in.%[1]s.DeepCopy()", field.Name())
  418. } else {
  419. c.Linef("in.%[1]s.DeepCopyInto(&out.%[1]s)", field.Name())
  420. }
  421. }
  422. continue
  423. }
  424. // pass-by-reference fields get delegated to the main type
  425. underlyingField := eventualUnderlyingType(field.Type())
  426. if passesByReference(underlyingField) {
  427. c.If(fmt.Sprintf("in.%s != nil", field.Name()), func() {
  428. c.Linef("in, out := &in.%[1]s, &out.%[1]s", field.Name())
  429. c.genDeepCopyIntoBlock(&namingInfo{typeInfo: field.Type()}, field.Type())
  430. })
  431. continue
  432. }
  433. // otherwise...
  434. switch underlyingField := underlyingField.(type) {
  435. case *types.Basic:
  436. switch underlyingField.Kind() {
  437. case types.Invalid, types.UnsafePointer:
  438. c.pkg.AddError(loader.ErrFromNode(fmt.Errorf("invalid field type: %s", underlyingField), field))
  439. return
  440. default:
  441. // nothing to do, initial assignment copied this
  442. }
  443. case *types.Struct:
  444. if fineToShallowCopy(field.Type()) {
  445. c.Linef("out.%[1]s = in.%[1]s", field.Name())
  446. } else {
  447. c.Linef("in.%[1]s.DeepCopyInto(&out.%[1]s)", field.Name())
  448. }
  449. default:
  450. c.pkg.AddError(loader.ErrFromNode(fmt.Errorf("invalid field type: %s", underlyingField), field))
  451. return
  452. }
  453. }
  454. }
  455. // genPointerDeepCopy generates DeepCopy code for the given named type whose
  456. // underlying type is the given struct.
  457. func (c *copyMethodMaker) genPointerDeepCopy(_ *namingInfo, pointerType *types.Pointer) {
  458. underlyingElem := eventualUnderlyingType(pointerType.Elem())
  459. // if we have a manually written deepcopy, just use that
  460. hasDeepCopy, copyOnPtr := hasDeepCopyMethod(c.pkg, pointerType.Elem())
  461. hasDeepCopyInto := hasDeepCopyIntoMethod(c.pkg, pointerType.Elem())
  462. if hasDeepCopyInto || hasDeepCopy {
  463. outNeedsPtr := resultWillBePointer(pointerType.Elem(), hasDeepCopy, copyOnPtr)
  464. if hasDeepCopy {
  465. outNeedsPtr = copyOnPtr
  466. }
  467. if outNeedsPtr {
  468. c.Line("*out = (*in).DeepCopy()")
  469. } else {
  470. c.Line("x := (*in).DeepCopy()")
  471. c.Line("*out = &x")
  472. }
  473. return
  474. }
  475. // shallow-copiable types are pretty easy
  476. if fineToShallowCopy(underlyingElem) {
  477. c.Linef("*out = new(%[1]s)", (&namingInfo{typeInfo: pointerType.Elem()}).Syntax(c.pkg, c.importsList))
  478. c.Line("**out = **in")
  479. return
  480. }
  481. // pass-by-reference types get delegated to the main switch
  482. if passesByReference(underlyingElem) {
  483. c.Linef("*out = new(%s)", (&namingInfo{typeInfo: underlyingElem}).Syntax(c.pkg, c.importsList))
  484. c.If("**in != nil", func() {
  485. c.Line("in, out := *in, *out")
  486. c.genDeepCopyIntoBlock(&namingInfo{typeInfo: underlyingElem}, eventualUnderlyingType(underlyingElem))
  487. })
  488. return
  489. }
  490. // otherwise...
  491. switch underlyingElem := underlyingElem.(type) {
  492. case *types.Struct:
  493. c.Linef("*out = new(%[1]s)", (&namingInfo{typeInfo: pointerType.Elem()}).Syntax(c.pkg, c.importsList))
  494. c.Line("(*in).DeepCopyInto(*out)")
  495. default:
  496. c.pkg.AddError(fmt.Errorf("invalid pointer element type: %s", underlyingElem))
  497. return
  498. }
  499. }
  500. // usePtrReceiver checks if we need a pointer receiver on methods for the given type
  501. // Pass-by-reference types don't get pointer receivers.
  502. func usePtrReceiver(typeInfo types.Type) bool {
  503. switch typeInfo.(type) {
  504. case *types.Pointer:
  505. return false
  506. case *types.Map:
  507. return false
  508. case *types.Slice:
  509. return false
  510. case *types.Named:
  511. return usePtrReceiver(typeInfo.Underlying())
  512. default:
  513. return true
  514. }
  515. }
  516. func resultWillBePointer(typeInfo types.Type, hasDeepCopy, deepCopyOnPtr bool) bool {
  517. // if we have a manual deepcopy, we can just check what that returns
  518. if hasDeepCopy {
  519. return deepCopyOnPtr
  520. }
  521. // otherwise, we'll need to check its type
  522. switch typeInfo := typeInfo.(type) {
  523. case *types.Pointer:
  524. // NB(directxman12): we don't have to worry about the elem having a deepcopy,
  525. // since hasManualDeepCopy would've caught that.
  526. // we'll be calling on the elem, so check that
  527. return resultWillBePointer(typeInfo.Elem(), false, false)
  528. case *types.Map:
  529. return false
  530. case *types.Slice:
  531. return false
  532. case *types.Named:
  533. return resultWillBePointer(typeInfo.Underlying(), false, false)
  534. default:
  535. return true
  536. }
  537. }
  538. // shouldBeCopied checks if we're supposed to make deepcopy methods the given type.
  539. //
  540. // This is the case if it's exported *and* either:
  541. // - has a partial manual DeepCopy implementation (in which case we fill in the rest)
  542. // - aliases to a non-basic type eventually
  543. // - is a struct
  544. func shouldBeCopied(pkg *loader.Package, info *markers.TypeInfo) bool {
  545. if !ast.IsExported(info.Name) {
  546. return false
  547. }
  548. typeInfo := pkg.TypesInfo.TypeOf(info.RawSpec.Name)
  549. if typeInfo == types.Typ[types.Invalid] {
  550. pkg.AddError(loader.ErrFromNode(fmt.Errorf("unknown type: %s", info.Name), info.RawSpec))
  551. return false
  552. }
  553. // according to gengo, everything named is an alias, except for an alias to a pointer,
  554. // which is just a pointer, afaict. Just roll with it.
  555. if asPtr, isPtr := typeInfo.(*types.Named).Underlying().(*types.Pointer); isPtr {
  556. typeInfo = asPtr
  557. }
  558. lastType := typeInfo
  559. if _, isNamed := typeInfo.(*types.Named); isNamed {
  560. // if it has a manual deepcopy or deepcopyinto, we're fine
  561. if hasAnyDeepCopyMethod(pkg, typeInfo) {
  562. return true
  563. }
  564. for underlyingType := typeInfo.Underlying(); underlyingType != lastType; lastType, underlyingType = underlyingType, underlyingType.Underlying() {
  565. // if it has a manual deepcopy or deepcopyinto, we're fine
  566. if hasAnyDeepCopyMethod(pkg, underlyingType) {
  567. return true
  568. }
  569. // aliases to other things besides basics need copy methods
  570. // (basics can be straight-up shallow-copied)
  571. if _, isBasic := underlyingType.(*types.Basic); !isBasic {
  572. return true
  573. }
  574. }
  575. }
  576. // structs are the only thing that's not a basic that's copiable by default
  577. _, isStruct := lastType.(*types.Struct)
  578. return isStruct
  579. }
  580. // hasDeepCopyMethod checks if this type has a manual DeepCopy method and if
  581. // the method has a pointer receiver.
  582. func hasDeepCopyMethod(pkg *loader.Package, typeInfo types.Type) (bool, bool) {
  583. deepCopyMethod, ind, _ := types.LookupFieldOrMethod(typeInfo, true /* check pointers too */, pkg.Types, "DeepCopy")
  584. if len(ind) != 1 {
  585. // ignore embedded methods
  586. return false, false
  587. }
  588. if deepCopyMethod == nil {
  589. return false, false
  590. }
  591. methodSig := deepCopyMethod.Type().(*types.Signature)
  592. if methodSig.Params() != nil && methodSig.Params().Len() != 0 {
  593. return false, false
  594. }
  595. if methodSig.Results() == nil || methodSig.Results().Len() != 1 {
  596. return false, false
  597. }
  598. recvAsPtr, recvIsPtr := methodSig.Recv().Type().(*types.Pointer)
  599. if recvIsPtr {
  600. // NB(directxman12): the pointer type returned here isn't comparable even though they
  601. // have the same underlying type, for some reason (probably that
  602. // LookupFieldOrMethod calls types.NewPointer for us), so check the
  603. // underlying values.
  604. resultPtr, resultIsPtr := methodSig.Results().At(0).Type().(*types.Pointer)
  605. if !resultIsPtr {
  606. // pointer vs non-pointer are different types
  607. return false, false
  608. }
  609. if recvAsPtr.Elem() != resultPtr.Elem() {
  610. return false, false
  611. }
  612. } else if methodSig.Results().At(0).Type() != methodSig.Recv().Type() {
  613. return false, false
  614. }
  615. return true, recvIsPtr
  616. }
  617. // hasDeepCopyIntoMethod checks if this type has a manual DeepCopyInto method.
  618. func hasDeepCopyIntoMethod(pkg *loader.Package, typeInfo types.Type) bool {
  619. deepCopyMethod, ind, _ := types.LookupFieldOrMethod(typeInfo, true /* check pointers too */, pkg.Types, "DeepCopyInto")
  620. if len(ind) != 1 {
  621. // ignore embedded methods
  622. return false
  623. }
  624. if deepCopyMethod == nil {
  625. return false
  626. }
  627. methodSig := deepCopyMethod.Type().(*types.Signature)
  628. if methodSig.Params() == nil || methodSig.Params().Len() != 1 {
  629. return false
  630. }
  631. paramPtr, isPtr := methodSig.Params().At(0).Type().(*types.Pointer)
  632. if !isPtr {
  633. return false
  634. }
  635. if methodSig.Results() != nil && methodSig.Results().Len() != 0 {
  636. return false
  637. }
  638. if recvPtr, recvIsPtr := methodSig.Recv().Type().(*types.Pointer); recvIsPtr {
  639. // NB(directxman12): the pointer type returned here isn't comparable even though they
  640. // have the same underlying type, for some reason (probably that
  641. // LookupFieldOrMethod calls types.NewPointer for us), so check the
  642. // underlying values.
  643. return paramPtr.Elem() == recvPtr.Elem()
  644. }
  645. return methodSig.Recv().Type() == paramPtr.Elem()
  646. }
  647. // hasAnyDeepCopyMethod checks if the given method has DeepCopy or DeepCopyInto
  648. // (either of which implies the other will exist eventually).
  649. func hasAnyDeepCopyMethod(pkg *loader.Package, typeInfo types.Type) bool {
  650. hasDeepCopy, _ := hasDeepCopyMethod(pkg, typeInfo)
  651. return hasDeepCopy || hasDeepCopyIntoMethod(pkg, typeInfo)
  652. }
  653. // eventualUnderlyingType gets the "final" type in a sequence of named aliases.
  654. // It's effectively a shortcut for calling Underlying in a loop.
  655. func eventualUnderlyingType(typeInfo types.Type) types.Type {
  656. for {
  657. underlying := typeInfo.Underlying()
  658. if underlying == typeInfo {
  659. break
  660. }
  661. typeInfo = underlying
  662. }
  663. return typeInfo
  664. }
  665. // fineToShallowCopy checks if a shallow-copying a type is equivalent to deepcopy-ing it.
  666. func fineToShallowCopy(typeInfo types.Type) bool {
  667. switch typeInfo := typeInfo.(type) {
  668. case *types.Basic:
  669. // basic types (int, string, etc) are always fine to shallow-copy,
  670. // except for Invalid and UnsafePointer, which can't be copied at all.
  671. switch typeInfo.Kind() {
  672. case types.Invalid, types.UnsafePointer:
  673. return false
  674. default:
  675. return true
  676. }
  677. case *types.Named:
  678. // aliases are fine to shallow-copy as long as they resolve to a shallow-copyable type
  679. return fineToShallowCopy(typeInfo.Underlying())
  680. case *types.Struct:
  681. // structs are fine to shallow-copy if they have all shallow-copyable fields
  682. for i := 0; i < typeInfo.NumFields(); i++ {
  683. field := typeInfo.Field(i)
  684. if !fineToShallowCopy(field.Type()) {
  685. return false
  686. }
  687. }
  688. return true
  689. default:
  690. return false
  691. }
  692. }
  693. // passesByReference checks if the given type passesByReference
  694. // (except for interfaces, which are handled separately).
  695. func passesByReference(typeInfo types.Type) bool {
  696. switch typeInfo.(type) {
  697. case *types.Slice:
  698. return true
  699. case *types.Map:
  700. return true
  701. case *types.Pointer:
  702. return true
  703. default:
  704. return false
  705. }
  706. }
  707. var (
  708. // ptrDeepCopy is a DeepCopy for a type with an existing DeepCopyInto and a pointer receiver.
  709. ptrDeepCopy = `
  710. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new %[1]s.
  711. func (in *%[1]s) DeepCopy() *%[1]s {
  712. if in == nil { return nil }
  713. out := new(%[1]s)
  714. in.DeepCopyInto(out)
  715. return out
  716. }
  717. `
  718. // ptrDeepCopy is a DeepCopy for a type with an existing DeepCopyInto and a non-pointer receiver.
  719. bareDeepCopy = `
  720. // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new %[1]s.
  721. func (in %[1]s) DeepCopy() %[1]s {
  722. if in == nil { return nil }
  723. out := new(%[1]s)
  724. in.DeepCopyInto(out)
  725. return *out
  726. }
  727. `
  728. // ptrDeepCopy is a DeepCopyObject for a type with an existing DeepCopyInto and a pointer receiver.
  729. ptrDeepCopyObj = `
  730. // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
  731. func (in *%[1]s) DeepCopyObject() %[2]s.Object {
  732. if c := in.DeepCopy(); c != nil {
  733. return c
  734. }
  735. return nil
  736. }
  737. `
  738. // ptrDeepCopy is a DeepCopyObject for a type with an existing DeepCopyInto and a non-pointer receiver.
  739. bareDeepCopyObj = `
  740. // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
  741. func (in %[1]s) DeepCopyObject() %[2]s.Object {
  742. return in.DeepCopy()
  743. }
  744. `
  745. )