legacy_extension.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  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 impl
  5. import (
  6. "reflect"
  7. "google.golang.org/protobuf/internal/descopts"
  8. "google.golang.org/protobuf/internal/encoding/messageset"
  9. ptag "google.golang.org/protobuf/internal/encoding/tag"
  10. "google.golang.org/protobuf/internal/filedesc"
  11. "google.golang.org/protobuf/internal/pragma"
  12. "google.golang.org/protobuf/reflect/protoreflect"
  13. "google.golang.org/protobuf/reflect/protoregistry"
  14. "google.golang.org/protobuf/runtime/protoiface"
  15. )
  16. func (xi *ExtensionInfo) initToLegacy() {
  17. xd := xi.desc
  18. var parent protoiface.MessageV1
  19. messageName := xd.ContainingMessage().FullName()
  20. if mt, _ := protoregistry.GlobalTypes.FindMessageByName(messageName); mt != nil {
  21. // Create a new parent message and unwrap it if possible.
  22. mv := mt.New().Interface()
  23. t := reflect.TypeOf(mv)
  24. if mv, ok := mv.(unwrapper); ok {
  25. t = reflect.TypeOf(mv.protoUnwrap())
  26. }
  27. // Check whether the message implements the legacy v1 Message interface.
  28. mz := reflect.Zero(t).Interface()
  29. if mz, ok := mz.(protoiface.MessageV1); ok {
  30. parent = mz
  31. }
  32. }
  33. // Determine the v1 extension type, which is unfortunately not the same as
  34. // the v2 ExtensionType.GoType.
  35. extType := xi.goType
  36. switch extType.Kind() {
  37. case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
  38. extType = reflect.PtrTo(extType) // T -> *T for singular scalar fields
  39. }
  40. // Reconstruct the legacy enum full name.
  41. var enumName string
  42. if xd.Kind() == protoreflect.EnumKind {
  43. enumName = legacyEnumName(xd.Enum())
  44. }
  45. // Derive the proto file that the extension was declared within.
  46. var filename string
  47. if fd := xd.ParentFile(); fd != nil {
  48. filename = fd.Path()
  49. }
  50. // For MessageSet extensions, the name used is the parent message.
  51. name := xd.FullName()
  52. if messageset.IsMessageSetExtension(xd) {
  53. name = name.Parent()
  54. }
  55. xi.ExtendedType = parent
  56. xi.ExtensionType = reflect.Zero(extType).Interface()
  57. xi.Field = int32(xd.Number())
  58. xi.Name = string(name)
  59. xi.Tag = ptag.Marshal(xd, enumName)
  60. xi.Filename = filename
  61. }
  62. // initFromLegacy initializes an ExtensionInfo from
  63. // the contents of the deprecated exported fields of the type.
  64. func (xi *ExtensionInfo) initFromLegacy() {
  65. // The v1 API returns "type incomplete" descriptors where only the
  66. // field number is specified. In such a case, use a placeholder.
  67. if xi.ExtendedType == nil || xi.ExtensionType == nil {
  68. xd := placeholderExtension{
  69. name: protoreflect.FullName(xi.Name),
  70. number: protoreflect.FieldNumber(xi.Field),
  71. }
  72. xi.desc = extensionTypeDescriptor{xd, xi}
  73. return
  74. }
  75. // Resolve enum or message dependencies.
  76. var ed protoreflect.EnumDescriptor
  77. var md protoreflect.MessageDescriptor
  78. t := reflect.TypeOf(xi.ExtensionType)
  79. isOptional := t.Kind() == reflect.Ptr && t.Elem().Kind() != reflect.Struct
  80. isRepeated := t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8
  81. if isOptional || isRepeated {
  82. t = t.Elem()
  83. }
  84. switch v := reflect.Zero(t).Interface().(type) {
  85. case protoreflect.Enum:
  86. ed = v.Descriptor()
  87. case enumV1:
  88. ed = LegacyLoadEnumDesc(t)
  89. case protoreflect.ProtoMessage:
  90. md = v.ProtoReflect().Descriptor()
  91. case messageV1:
  92. md = LegacyLoadMessageDesc(t)
  93. }
  94. // Derive basic field information from the struct tag.
  95. var evs protoreflect.EnumValueDescriptors
  96. if ed != nil {
  97. evs = ed.Values()
  98. }
  99. fd := ptag.Unmarshal(xi.Tag, t, evs).(*filedesc.Field)
  100. // Construct a v2 ExtensionType.
  101. xd := &filedesc.Extension{L2: new(filedesc.ExtensionL2)}
  102. xd.L0.ParentFile = filedesc.SurrogateProto2
  103. xd.L0.FullName = protoreflect.FullName(xi.Name)
  104. xd.L1.Number = protoreflect.FieldNumber(xi.Field)
  105. xd.L1.Cardinality = fd.L1.Cardinality
  106. xd.L1.Kind = fd.L1.Kind
  107. xd.L2.IsPacked = fd.L1.IsPacked
  108. xd.L2.Default = fd.L1.Default
  109. xd.L1.Extendee = Export{}.MessageDescriptorOf(xi.ExtendedType)
  110. xd.L2.Enum = ed
  111. xd.L2.Message = md
  112. // Derive real extension field name for MessageSets.
  113. if messageset.IsMessageSet(xd.L1.Extendee) && md.FullName() == xd.L0.FullName {
  114. xd.L0.FullName = xd.L0.FullName.Append(messageset.ExtensionName)
  115. }
  116. tt := reflect.TypeOf(xi.ExtensionType)
  117. if isOptional {
  118. tt = tt.Elem()
  119. }
  120. xi.goType = tt
  121. xi.desc = extensionTypeDescriptor{xd, xi}
  122. }
  123. type placeholderExtension struct {
  124. name protoreflect.FullName
  125. number protoreflect.FieldNumber
  126. }
  127. func (x placeholderExtension) ParentFile() protoreflect.FileDescriptor { return nil }
  128. func (x placeholderExtension) Parent() protoreflect.Descriptor { return nil }
  129. func (x placeholderExtension) Index() int { return 0 }
  130. func (x placeholderExtension) Syntax() protoreflect.Syntax { return 0 }
  131. func (x placeholderExtension) Name() protoreflect.Name { return x.name.Name() }
  132. func (x placeholderExtension) FullName() protoreflect.FullName { return x.name }
  133. func (x placeholderExtension) IsPlaceholder() bool { return true }
  134. func (x placeholderExtension) Options() protoreflect.ProtoMessage { return descopts.Field }
  135. func (x placeholderExtension) Number() protoreflect.FieldNumber { return x.number }
  136. func (x placeholderExtension) Cardinality() protoreflect.Cardinality { return 0 }
  137. func (x placeholderExtension) Kind() protoreflect.Kind { return 0 }
  138. func (x placeholderExtension) HasJSONName() bool { return false }
  139. func (x placeholderExtension) JSONName() string { return "[" + string(x.name) + "]" }
  140. func (x placeholderExtension) TextName() string { return "[" + string(x.name) + "]" }
  141. func (x placeholderExtension) HasPresence() bool { return false }
  142. func (x placeholderExtension) HasOptionalKeyword() bool { return false }
  143. func (x placeholderExtension) IsExtension() bool { return true }
  144. func (x placeholderExtension) IsWeak() bool { return false }
  145. func (x placeholderExtension) IsPacked() bool { return false }
  146. func (x placeholderExtension) IsList() bool { return false }
  147. func (x placeholderExtension) IsMap() bool { return false }
  148. func (x placeholderExtension) MapKey() protoreflect.FieldDescriptor { return nil }
  149. func (x placeholderExtension) MapValue() protoreflect.FieldDescriptor { return nil }
  150. func (x placeholderExtension) HasDefault() bool { return false }
  151. func (x placeholderExtension) Default() protoreflect.Value { return protoreflect.Value{} }
  152. func (x placeholderExtension) DefaultEnumValue() protoreflect.EnumValueDescriptor { return nil }
  153. func (x placeholderExtension) ContainingOneof() protoreflect.OneofDescriptor { return nil }
  154. func (x placeholderExtension) ContainingMessage() protoreflect.MessageDescriptor { return nil }
  155. func (x placeholderExtension) Enum() protoreflect.EnumDescriptor { return nil }
  156. func (x placeholderExtension) Message() protoreflect.MessageDescriptor { return nil }
  157. func (x placeholderExtension) ProtoType(protoreflect.FieldDescriptor) { return }
  158. func (x placeholderExtension) ProtoInternal(pragma.DoNotImplement) { return }