namer.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. /*
  2. Copyright 2015 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 protobuf
  14. import (
  15. "fmt"
  16. "reflect"
  17. "strings"
  18. "k8s.io/kubernetes/cmd/libs/go2idl/generator"
  19. "k8s.io/kubernetes/cmd/libs/go2idl/namer"
  20. "k8s.io/kubernetes/cmd/libs/go2idl/types"
  21. )
  22. type localNamer struct {
  23. localPackage types.Name
  24. }
  25. func (n localNamer) Name(t *types.Type) string {
  26. if t.Key != nil && t.Elem != nil {
  27. return fmt.Sprintf("map<%s, %s>", n.Name(t.Key), n.Name(t.Elem))
  28. }
  29. if len(n.localPackage.Package) != 0 && n.localPackage.Package == t.Name.Package {
  30. return t.Name.Name
  31. }
  32. return t.Name.String()
  33. }
  34. type protobufNamer struct {
  35. packages []*protobufPackage
  36. packagesByPath map[string]*protobufPackage
  37. }
  38. func NewProtobufNamer() *protobufNamer {
  39. return &protobufNamer{
  40. packagesByPath: make(map[string]*protobufPackage),
  41. }
  42. }
  43. func (n *protobufNamer) Name(t *types.Type) string {
  44. if t.Kind == types.Map {
  45. return fmt.Sprintf("map<%s, %s>", n.Name(t.Key), n.Name(t.Elem))
  46. }
  47. return t.Name.String()
  48. }
  49. func (n *protobufNamer) List() []generator.Package {
  50. packages := make([]generator.Package, 0, len(n.packages))
  51. for i := range n.packages {
  52. packages = append(packages, n.packages[i])
  53. }
  54. return packages
  55. }
  56. func (n *protobufNamer) Add(p *protobufPackage) {
  57. if _, ok := n.packagesByPath[p.PackagePath]; !ok {
  58. n.packagesByPath[p.PackagePath] = p
  59. n.packages = append(n.packages, p)
  60. }
  61. }
  62. func (n *protobufNamer) GoNameToProtoName(name types.Name) types.Name {
  63. if p, ok := n.packagesByPath[name.Package]; ok {
  64. return types.Name{
  65. Name: name.Name,
  66. Package: p.PackageName,
  67. Path: p.ImportPath(),
  68. }
  69. }
  70. for _, p := range n.packages {
  71. if _, ok := p.FilterTypes[name]; ok {
  72. return types.Name{
  73. Name: name.Name,
  74. Package: p.PackageName,
  75. Path: p.ImportPath(),
  76. }
  77. }
  78. }
  79. return types.Name{Name: name.Name}
  80. }
  81. func protoSafePackage(name string) string {
  82. return strings.Replace(name, "/", ".", -1)
  83. }
  84. type typeNameSet map[types.Name]*protobufPackage
  85. // assignGoTypeToProtoPackage looks for Go and Protobuf types that are referenced by a type in
  86. // a package. It will not recurse into protobuf types.
  87. func assignGoTypeToProtoPackage(p *protobufPackage, t *types.Type, local, global typeNameSet, optional map[types.Name]struct{}) {
  88. newT, isProto := isFundamentalProtoType(t)
  89. if isProto {
  90. t = newT
  91. }
  92. if otherP, ok := global[t.Name]; ok {
  93. if _, ok := local[t.Name]; !ok {
  94. p.Imports.AddType(&types.Type{
  95. Kind: types.Protobuf,
  96. Name: otherP.ProtoTypeName(),
  97. })
  98. }
  99. return
  100. }
  101. global[t.Name] = p
  102. if _, ok := local[t.Name]; ok {
  103. return
  104. }
  105. // don't recurse into existing proto types
  106. if isProto {
  107. p.Imports.AddType(t)
  108. return
  109. }
  110. local[t.Name] = p
  111. for _, m := range t.Members {
  112. if namer.IsPrivateGoName(m.Name) {
  113. continue
  114. }
  115. field := &protoField{}
  116. tag := reflect.StructTag(m.Tags).Get("protobuf")
  117. if tag == "-" {
  118. continue
  119. }
  120. if err := protobufTagToField(tag, field, m, t, p.ProtoTypeName()); err == nil && field.Type != nil {
  121. assignGoTypeToProtoPackage(p, field.Type, local, global, optional)
  122. continue
  123. }
  124. assignGoTypeToProtoPackage(p, m.Type, local, global, optional)
  125. }
  126. // TODO: should methods be walked?
  127. if t.Elem != nil {
  128. assignGoTypeToProtoPackage(p, t.Elem, local, global, optional)
  129. }
  130. if t.Key != nil {
  131. assignGoTypeToProtoPackage(p, t.Key, local, global, optional)
  132. }
  133. if t.Underlying != nil {
  134. if t.Kind == types.Alias && isOptionalAlias(t) {
  135. optional[t.Name] = struct{}{}
  136. }
  137. assignGoTypeToProtoPackage(p, t.Underlying, local, global, optional)
  138. }
  139. }
  140. func (n *protobufNamer) AssignTypesToPackages(c *generator.Context) error {
  141. global := make(typeNameSet)
  142. for _, p := range n.packages {
  143. local := make(typeNameSet)
  144. optional := make(map[types.Name]struct{})
  145. p.Imports = NewImportTracker(p.ProtoTypeName())
  146. for _, t := range c.Order {
  147. if t.Name.Package != p.PackagePath {
  148. continue
  149. }
  150. assignGoTypeToProtoPackage(p, t, local, global, optional)
  151. }
  152. p.FilterTypes = make(map[types.Name]struct{})
  153. p.LocalNames = make(map[string]struct{})
  154. p.OptionalTypeNames = make(map[string]struct{})
  155. for k, v := range local {
  156. if v == p {
  157. p.FilterTypes[k] = struct{}{}
  158. p.LocalNames[k.Name] = struct{}{}
  159. if _, ok := optional[k]; ok {
  160. p.OptionalTypeNames[k.Name] = struct{}{}
  161. }
  162. }
  163. }
  164. }
  165. return nil
  166. }