reflect.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. // Copyright 2018 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package internal_gengo
  5. import (
  6. "fmt"
  7. "math"
  8. "strings"
  9. "unicode/utf8"
  10. "google.golang.org/protobuf/compiler/protogen"
  11. "google.golang.org/protobuf/proto"
  12. "google.golang.org/protobuf/reflect/protopath"
  13. "google.golang.org/protobuf/reflect/protorange"
  14. "google.golang.org/protobuf/reflect/protoreflect"
  15. "google.golang.org/protobuf/types/descriptorpb"
  16. )
  17. func genReflectFileDescriptor(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo) {
  18. g.P("var ", f.GoDescriptorIdent, " ", protoreflectPackage.Ident("FileDescriptor"))
  19. g.P()
  20. genFileDescriptor(gen, g, f)
  21. if len(f.allEnums) > 0 {
  22. g.P("var ", enumTypesVarName(f), " = make([]", protoimplPackage.Ident("EnumInfo"), ",", len(f.allEnums), ")")
  23. }
  24. if len(f.allMessages) > 0 {
  25. g.P("var ", messageTypesVarName(f), " = make([]", protoimplPackage.Ident("MessageInfo"), ",", len(f.allMessages), ")")
  26. }
  27. // Generate a unique list of Go types for all declarations and dependencies,
  28. // and the associated index into the type list for all dependencies.
  29. var goTypes []string
  30. var depIdxs []string
  31. seen := map[protoreflect.FullName]int{}
  32. genDep := func(name protoreflect.FullName, depSource string) {
  33. if depSource != "" {
  34. line := fmt.Sprintf("%d, // %d: %s -> %s", seen[name], len(depIdxs), depSource, name)
  35. depIdxs = append(depIdxs, line)
  36. }
  37. }
  38. genEnum := func(e *protogen.Enum, depSource string) {
  39. if e != nil {
  40. name := e.Desc.FullName()
  41. if _, ok := seen[name]; !ok {
  42. line := fmt.Sprintf("(%s)(0), // %d: %s", g.QualifiedGoIdent(e.GoIdent), len(goTypes), name)
  43. goTypes = append(goTypes, line)
  44. seen[name] = len(seen)
  45. }
  46. if depSource != "" {
  47. genDep(name, depSource)
  48. }
  49. }
  50. }
  51. genMessage := func(m *protogen.Message, depSource string) {
  52. if m != nil {
  53. name := m.Desc.FullName()
  54. if _, ok := seen[name]; !ok {
  55. line := fmt.Sprintf("(*%s)(nil), // %d: %s", g.QualifiedGoIdent(m.GoIdent), len(goTypes), name)
  56. if m.Desc.IsMapEntry() {
  57. // Map entry messages have no associated Go type.
  58. line = fmt.Sprintf("nil, // %d: %s", len(goTypes), name)
  59. }
  60. goTypes = append(goTypes, line)
  61. seen[name] = len(seen)
  62. }
  63. if depSource != "" {
  64. genDep(name, depSource)
  65. }
  66. }
  67. }
  68. // This ordering is significant.
  69. // See filetype.TypeBuilder.DependencyIndexes.
  70. type offsetEntry struct {
  71. start int
  72. name string
  73. }
  74. var depOffsets []offsetEntry
  75. for _, enum := range f.allEnums {
  76. genEnum(enum.Enum, "")
  77. }
  78. for _, message := range f.allMessages {
  79. genMessage(message.Message, "")
  80. }
  81. depOffsets = append(depOffsets, offsetEntry{len(depIdxs), "field type_name"})
  82. for _, message := range f.allMessages {
  83. for _, field := range message.Fields {
  84. if field.Desc.IsWeak() {
  85. continue
  86. }
  87. source := string(field.Desc.FullName())
  88. genEnum(field.Enum, source+":type_name")
  89. genMessage(field.Message, source+":type_name")
  90. }
  91. }
  92. depOffsets = append(depOffsets, offsetEntry{len(depIdxs), "extension extendee"})
  93. for _, extension := range f.allExtensions {
  94. source := string(extension.Desc.FullName())
  95. genMessage(extension.Extendee, source+":extendee")
  96. }
  97. depOffsets = append(depOffsets, offsetEntry{len(depIdxs), "extension type_name"})
  98. for _, extension := range f.allExtensions {
  99. source := string(extension.Desc.FullName())
  100. genEnum(extension.Enum, source+":type_name")
  101. genMessage(extension.Message, source+":type_name")
  102. }
  103. depOffsets = append(depOffsets, offsetEntry{len(depIdxs), "method input_type"})
  104. for _, service := range f.Services {
  105. for _, method := range service.Methods {
  106. source := string(method.Desc.FullName())
  107. genMessage(method.Input, source+":input_type")
  108. }
  109. }
  110. depOffsets = append(depOffsets, offsetEntry{len(depIdxs), "method output_type"})
  111. for _, service := range f.Services {
  112. for _, method := range service.Methods {
  113. source := string(method.Desc.FullName())
  114. genMessage(method.Output, source+":output_type")
  115. }
  116. }
  117. depOffsets = append(depOffsets, offsetEntry{len(depIdxs), ""})
  118. for i := len(depOffsets) - 2; i >= 0; i-- {
  119. curr, next := depOffsets[i], depOffsets[i+1]
  120. depIdxs = append(depIdxs, fmt.Sprintf("%d, // [%d:%d] is the sub-list for %s",
  121. curr.start, curr.start, next.start, curr.name))
  122. }
  123. if len(depIdxs) > math.MaxInt32 {
  124. panic("too many dependencies") // sanity check
  125. }
  126. g.P("var ", goTypesVarName(f), " = []interface{}{")
  127. for _, s := range goTypes {
  128. g.P(s)
  129. }
  130. g.P("}")
  131. g.P("var ", depIdxsVarName(f), " = []int32{")
  132. for _, s := range depIdxs {
  133. g.P(s)
  134. }
  135. g.P("}")
  136. g.P("func init() { ", initFuncName(f.File), "() }")
  137. g.P("func ", initFuncName(f.File), "() {")
  138. g.P("if ", f.GoDescriptorIdent, " != nil {")
  139. g.P("return")
  140. g.P("}")
  141. // Ensure that initialization functions for different files in the same Go
  142. // package run in the correct order: Call the init funcs for every .proto file
  143. // imported by this one that is in the same Go package.
  144. for i, imps := 0, f.Desc.Imports(); i < imps.Len(); i++ {
  145. impFile := gen.FilesByPath[imps.Get(i).Path()]
  146. if impFile.GoImportPath != f.GoImportPath {
  147. continue
  148. }
  149. g.P(initFuncName(impFile), "()")
  150. }
  151. if len(f.allMessages) > 0 {
  152. // Populate MessageInfo.Exporters.
  153. g.P("if !", protoimplPackage.Ident("UnsafeEnabled"), " {")
  154. for _, message := range f.allMessages {
  155. if sf := f.allMessageFieldsByPtr[message]; len(sf.unexported) > 0 {
  156. idx := f.allMessagesByPtr[message]
  157. typesVar := messageTypesVarName(f)
  158. g.P(typesVar, "[", idx, "].Exporter = func(v interface{}, i int) interface{} {")
  159. g.P("switch v := v.(*", message.GoIdent, "); i {")
  160. for i := 0; i < sf.count; i++ {
  161. if name := sf.unexported[i]; name != "" {
  162. g.P("case ", i, ": return &v.", name)
  163. }
  164. }
  165. g.P("default: return nil")
  166. g.P("}")
  167. g.P("}")
  168. }
  169. }
  170. g.P("}")
  171. // Populate MessageInfo.OneofWrappers.
  172. for _, message := range f.allMessages {
  173. if len(message.Oneofs) > 0 {
  174. idx := f.allMessagesByPtr[message]
  175. typesVar := messageTypesVarName(f)
  176. // Associate the wrapper types by directly passing them to the MessageInfo.
  177. g.P(typesVar, "[", idx, "].OneofWrappers = []interface{} {")
  178. for _, oneof := range message.Oneofs {
  179. if !oneof.Desc.IsSynthetic() {
  180. for _, field := range oneof.Fields {
  181. g.P("(*", field.GoIdent, ")(nil),")
  182. }
  183. }
  184. }
  185. g.P("}")
  186. }
  187. }
  188. }
  189. g.P("type x struct{}")
  190. g.P("out := ", protoimplPackage.Ident("TypeBuilder"), "{")
  191. g.P("File: ", protoimplPackage.Ident("DescBuilder"), "{")
  192. g.P("GoPackagePath: ", reflectPackage.Ident("TypeOf"), "(x{}).PkgPath(),")
  193. g.P("RawDescriptor: ", rawDescVarName(f), ",")
  194. g.P("NumEnums: ", len(f.allEnums), ",")
  195. g.P("NumMessages: ", len(f.allMessages), ",")
  196. g.P("NumExtensions: ", len(f.allExtensions), ",")
  197. g.P("NumServices: ", len(f.Services), ",")
  198. g.P("},")
  199. g.P("GoTypes: ", goTypesVarName(f), ",")
  200. g.P("DependencyIndexes: ", depIdxsVarName(f), ",")
  201. if len(f.allEnums) > 0 {
  202. g.P("EnumInfos: ", enumTypesVarName(f), ",")
  203. }
  204. if len(f.allMessages) > 0 {
  205. g.P("MessageInfos: ", messageTypesVarName(f), ",")
  206. }
  207. if len(f.allExtensions) > 0 {
  208. g.P("ExtensionInfos: ", extensionTypesVarName(f), ",")
  209. }
  210. g.P("}.Build()")
  211. g.P(f.GoDescriptorIdent, " = out.File")
  212. // Set inputs to nil to allow GC to reclaim resources.
  213. g.P(rawDescVarName(f), " = nil")
  214. g.P(goTypesVarName(f), " = nil")
  215. g.P(depIdxsVarName(f), " = nil")
  216. g.P("}")
  217. }
  218. // stripSourceRetentionFieldsFromMessage walks the given message tree recursively
  219. // and clears any fields with the field option: [retention = RETENTION_SOURCE]
  220. func stripSourceRetentionFieldsFromMessage(m protoreflect.Message) {
  221. protorange.Range(m, func(ppv protopath.Values) error {
  222. m2, ok := ppv.Index(-1).Value.Interface().(protoreflect.Message)
  223. if !ok {
  224. return nil
  225. }
  226. m2.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
  227. fdo, ok := fd.Options().(*descriptorpb.FieldOptions)
  228. if ok && fdo.GetRetention() == descriptorpb.FieldOptions_RETENTION_SOURCE {
  229. m2.Clear(fd)
  230. }
  231. return true
  232. })
  233. return nil
  234. })
  235. }
  236. func genFileDescriptor(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo) {
  237. descProto := proto.Clone(f.Proto).(*descriptorpb.FileDescriptorProto)
  238. descProto.SourceCodeInfo = nil // drop source code information
  239. stripSourceRetentionFieldsFromMessage(descProto.ProtoReflect())
  240. b, err := proto.MarshalOptions{AllowPartial: true, Deterministic: true}.Marshal(descProto)
  241. if err != nil {
  242. gen.Error(err)
  243. return
  244. }
  245. g.P("var ", rawDescVarName(f), " = []byte{")
  246. for len(b) > 0 {
  247. n := 16
  248. if n > len(b) {
  249. n = len(b)
  250. }
  251. s := ""
  252. for _, c := range b[:n] {
  253. s += fmt.Sprintf("0x%02x,", c)
  254. }
  255. g.P(s)
  256. b = b[n:]
  257. }
  258. g.P("}")
  259. g.P()
  260. if f.needRawDesc {
  261. onceVar := rawDescVarName(f) + "Once"
  262. dataVar := rawDescVarName(f) + "Data"
  263. g.P("var (")
  264. g.P(onceVar, " ", syncPackage.Ident("Once"))
  265. g.P(dataVar, " = ", rawDescVarName(f))
  266. g.P(")")
  267. g.P()
  268. g.P("func ", rawDescVarName(f), "GZIP() []byte {")
  269. g.P(onceVar, ".Do(func() {")
  270. g.P(dataVar, " = ", protoimplPackage.Ident("X"), ".CompressGZIP(", dataVar, ")")
  271. g.P("})")
  272. g.P("return ", dataVar)
  273. g.P("}")
  274. g.P()
  275. }
  276. }
  277. func genEnumReflectMethods(g *protogen.GeneratedFile, f *fileInfo, e *enumInfo) {
  278. idx := f.allEnumsByPtr[e]
  279. typesVar := enumTypesVarName(f)
  280. // Descriptor method.
  281. g.P("func (", e.GoIdent, ") Descriptor() ", protoreflectPackage.Ident("EnumDescriptor"), " {")
  282. g.P("return ", typesVar, "[", idx, "].Descriptor()")
  283. g.P("}")
  284. g.P()
  285. // Type method.
  286. g.P("func (", e.GoIdent, ") Type() ", protoreflectPackage.Ident("EnumType"), " {")
  287. g.P("return &", typesVar, "[", idx, "]")
  288. g.P("}")
  289. g.P()
  290. // Number method.
  291. g.P("func (x ", e.GoIdent, ") Number() ", protoreflectPackage.Ident("EnumNumber"), " {")
  292. g.P("return ", protoreflectPackage.Ident("EnumNumber"), "(x)")
  293. g.P("}")
  294. g.P()
  295. }
  296. func genMessageReflectMethods(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
  297. idx := f.allMessagesByPtr[m]
  298. typesVar := messageTypesVarName(f)
  299. // ProtoReflect method.
  300. g.P("func (x *", m.GoIdent, ") ProtoReflect() ", protoreflectPackage.Ident("Message"), " {")
  301. g.P("mi := &", typesVar, "[", idx, "]")
  302. g.P("if ", protoimplPackage.Ident("UnsafeEnabled"), " && x != nil {")
  303. g.P("ms := ", protoimplPackage.Ident("X"), ".MessageStateOf(", protoimplPackage.Ident("Pointer"), "(x))")
  304. g.P("if ms.LoadMessageInfo() == nil {")
  305. g.P("ms.StoreMessageInfo(mi)")
  306. g.P("}")
  307. g.P("return ms")
  308. g.P("}")
  309. g.P("return mi.MessageOf(x)")
  310. g.P("}")
  311. g.P()
  312. }
  313. func fileVarName(f *protogen.File, suffix string) string {
  314. prefix := f.GoDescriptorIdent.GoName
  315. _, n := utf8.DecodeRuneInString(prefix)
  316. prefix = strings.ToLower(prefix[:n]) + prefix[n:]
  317. return prefix + "_" + suffix
  318. }
  319. func rawDescVarName(f *fileInfo) string {
  320. return fileVarName(f.File, "rawDesc")
  321. }
  322. func goTypesVarName(f *fileInfo) string {
  323. return fileVarName(f.File, "goTypes")
  324. }
  325. func depIdxsVarName(f *fileInfo) string {
  326. return fileVarName(f.File, "depIdxs")
  327. }
  328. func enumTypesVarName(f *fileInfo) string {
  329. return fileVarName(f.File, "enumTypes")
  330. }
  331. func messageTypesVarName(f *fileInfo) string {
  332. return fileVarName(f.File, "msgTypes")
  333. }
  334. func extensionTypesVarName(f *fileInfo) string {
  335. return fileVarName(f.File, "extTypes")
  336. }
  337. func initFuncName(f *protogen.File) string {
  338. return fileVarName(f, "init")
  339. }