blob: 93c318f9eacaf8ca39e402e34f4fdd2d7706d052 [file] [log] [blame]
Joe Tsai08e00302018-11-26 22:32:06 -08001// 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
Joe Tsai21ade492019-05-22 13:42:54 -04005package impl
Joe Tsai08e00302018-11-26 22:32:06 -08006
7import (
Joe Tsai08e00302018-11-26 22:32:06 -08008 "reflect"
9
Joe Tsaibee62522019-09-05 17:25:15 -070010 "google.golang.org/protobuf/internal/descopts"
Joe Tsai945a1702019-07-20 14:57:56 -070011 "google.golang.org/protobuf/internal/encoding/messageset"
Damien Neile89e6242019-05-13 23:55:40 -070012 ptag "google.golang.org/protobuf/internal/encoding/tag"
Joe Tsaid8881392019-06-06 13:01:53 -070013 "google.golang.org/protobuf/internal/filedesc"
Joe Tsaibee62522019-09-05 17:25:15 -070014 "google.golang.org/protobuf/internal/pragma"
Damien Neile89e6242019-05-13 23:55:40 -070015 pref "google.golang.org/protobuf/reflect/protoreflect"
16 preg "google.golang.org/protobuf/reflect/protoregistry"
17 piface "google.golang.org/protobuf/runtime/protoiface"
Joe Tsai08e00302018-11-26 22:32:06 -080018)
19
Damien Neilf1e905b2019-08-08 15:45:59 -070020func (xi *ExtensionInfo) initToLegacy() {
21 xd := xi.desc
Joe Tsai4fddeba2019-03-20 18:29:32 -070022 var parent piface.MessageV1
Damien Neil92f76182019-08-02 16:58:08 -070023 messageName := xd.ContainingMessage().FullName()
Joe Tsaiac31a352019-05-13 14:32:56 -070024 if mt, _ := preg.GlobalTypes.FindMessageByName(messageName); mt != nil {
Joe Tsai08e00302018-11-26 22:32:06 -080025 // Create a new parent message and unwrap it if possible.
Joe Tsai3bc7d6f2019-01-09 02:57:13 -080026 mv := mt.New().Interface()
Joe Tsai08e00302018-11-26 22:32:06 -080027 t := reflect.TypeOf(mv)
Joe Tsaifd528ff2019-09-03 16:30:39 -070028 if mv, ok := mv.(unwrapper); ok {
29 t = reflect.TypeOf(mv.protoUnwrap())
Joe Tsai08e00302018-11-26 22:32:06 -080030 }
31
32 // Check whether the message implements the legacy v1 Message interface.
33 mz := reflect.Zero(t).Interface()
Joe Tsai4fddeba2019-03-20 18:29:32 -070034 if mz, ok := mz.(piface.MessageV1); ok {
Joe Tsai08e00302018-11-26 22:32:06 -080035 parent = mz
36 }
37 }
38
39 // Determine the v1 extension type, which is unfortunately not the same as
40 // the v2 ExtensionType.GoType.
Damien Neilf1e905b2019-08-08 15:45:59 -070041 extType := xi.goType
Joe Tsai08e00302018-11-26 22:32:06 -080042 switch extType.Kind() {
43 case reflect.Bool, reflect.Int32, reflect.Int64, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64, reflect.String:
44 extType = reflect.PtrTo(extType) // T -> *T for singular scalar fields
Joe Tsai08e00302018-11-26 22:32:06 -080045 }
46
Joe Tsai2e7817f2019-08-23 12:18:57 -070047 // Reconstruct the legacy enum full name.
Joe Tsai08e00302018-11-26 22:32:06 -080048 var enumName string
Damien Neil92f76182019-08-02 16:58:08 -070049 if xd.Kind() == pref.EnumKind {
Joe Tsai2e7817f2019-08-23 12:18:57 -070050 enumName = legacyEnumName(xd.Enum())
Joe Tsai08e00302018-11-26 22:32:06 -080051 }
52
53 // Derive the proto file that the extension was declared within.
54 var filename string
Damien Neil92f76182019-08-02 16:58:08 -070055 if fd := xd.ParentFile(); fd != nil {
Joe Tsai08e00302018-11-26 22:32:06 -080056 filename = fd.Path()
57 }
58
Joe Tsai945a1702019-07-20 14:57:56 -070059 // For MessageSet extensions, the name used is the parent message.
60 name := xd.FullName()
61 if messageset.IsMessageSetExtension(xd) {
62 name = name.Parent()
63 }
64
Damien Neilf1e905b2019-08-08 15:45:59 -070065 xi.ExtendedType = parent
66 xi.ExtensionType = reflect.Zero(extType).Interface()
67 xi.Field = int32(xd.Number())
Joe Tsai945a1702019-07-20 14:57:56 -070068 xi.Name = string(name)
Damien Neilf1e905b2019-08-08 15:45:59 -070069 xi.Tag = ptag.Marshal(xd, enumName)
70 xi.Filename = filename
Joe Tsai08e00302018-11-26 22:32:06 -080071}
72
Damien Neilf1e905b2019-08-08 15:45:59 -070073// initFromLegacy initializes an ExtensionInfo from
74// the contents of the deprecated exported fields of the type.
75func (xi *ExtensionInfo) initFromLegacy() {
Joe Tsaibee62522019-09-05 17:25:15 -070076 // The v1 API returns "type incomplete" descriptors where only the
77 // field number is specified. In such a case, use a placeholder.
78 if xi.ExtendedType == nil || xi.ExtensionType == nil {
79 xd := placeholderExtension{
80 name: pref.FullName(xi.Name),
81 number: pref.FieldNumber(xi.Field),
82 }
83 xi.desc = extensionTypeDescriptor{xd, xi}
84 return
85 }
86
Joe Tsaid8881392019-06-06 13:01:53 -070087 // Resolve enum or message dependencies.
88 var ed pref.EnumDescriptor
89 var md pref.MessageDescriptor
Damien Neilf1e905b2019-08-08 15:45:59 -070090 t := reflect.TypeOf(xi.ExtensionType)
Joe Tsai08e00302018-11-26 22:32:06 -080091 isOptional := t.Kind() == reflect.Ptr && t.Elem().Kind() != reflect.Struct
92 isRepeated := t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8
93 if isOptional || isRepeated {
94 t = t.Elem()
95 }
Joe Tsaid8881392019-06-06 13:01:53 -070096 switch v := reflect.Zero(t).Interface().(type) {
97 case pref.Enum:
98 ed = v.Descriptor()
99 case enumV1:
100 ed = LegacyLoadEnumDesc(t)
101 case pref.ProtoMessage:
102 md = v.ProtoReflect().Descriptor()
103 case messageV1:
104 md = LegacyLoadMessageDesc(t)
105 }
106
107 // Derive basic field information from the struct tag.
108 var evs pref.EnumValueDescriptors
109 if ed != nil {
110 evs = ed.Values()
111 }
Damien Neilf1e905b2019-08-08 15:45:59 -0700112 fd := ptag.Unmarshal(xi.Tag, t, evs).(*filedesc.Field)
Joe Tsai08e00302018-11-26 22:32:06 -0800113
114 // Construct a v2 ExtensionType.
Joe Tsaid8881392019-06-06 13:01:53 -0700115 xd := &filedesc.Extension{L2: new(filedesc.ExtensionL2)}
116 xd.L0.ParentFile = filedesc.SurrogateProto2
Damien Neilf1e905b2019-08-08 15:45:59 -0700117 xd.L0.FullName = pref.FullName(xi.Name)
118 xd.L1.Number = pref.FieldNumber(xi.Field)
Joe Tsaifd4c6052019-09-16 13:30:15 -0700119 xd.L1.Cardinality = fd.L1.Cardinality
Joe Tsaid8881392019-06-06 13:01:53 -0700120 xd.L1.Kind = fd.L1.Kind
121 xd.L2.IsPacked = fd.L1.IsPacked
122 xd.L2.Default = fd.L1.Default
Damien Neilf1e905b2019-08-08 15:45:59 -0700123 xd.L1.Extendee = Export{}.MessageDescriptorOf(xi.ExtendedType)
Joe Tsaid8881392019-06-06 13:01:53 -0700124 xd.L2.Enum = ed
125 xd.L2.Message = md
Joe Tsai945a1702019-07-20 14:57:56 -0700126
127 // Derive real extension field name for MessageSets.
128 if messageset.IsMessageSet(xd.L1.Extendee) && md.FullName() == xd.L0.FullName {
129 xd.L0.FullName = xd.L0.FullName.Append(messageset.ExtensionName)
130 }
131
Damien Neilf1e905b2019-08-08 15:45:59 -0700132 tt := reflect.TypeOf(xi.ExtensionType)
Damien Neil954bd922019-07-17 16:52:10 -0700133 if isOptional {
134 tt = tt.Elem()
Damien Neil954bd922019-07-17 16:52:10 -0700135 }
Damien Neilf1e905b2019-08-08 15:45:59 -0700136 xi.goType = tt
Joe Tsaifd4c6052019-09-16 13:30:15 -0700137 xi.desc = extensionTypeDescriptor{xd, xi}
Joe Tsai08e00302018-11-26 22:32:06 -0800138}
Joe Tsaibee62522019-09-05 17:25:15 -0700139
140type placeholderExtension struct {
141 name pref.FullName
142 number pref.FieldNumber
143}
144
145func (x placeholderExtension) ParentFile() pref.FileDescriptor { return nil }
146func (x placeholderExtension) Parent() pref.Descriptor { return nil }
147func (x placeholderExtension) Index() int { return 0 }
148func (x placeholderExtension) Syntax() pref.Syntax { return 0 }
149func (x placeholderExtension) Name() pref.Name { return x.name.Name() }
150func (x placeholderExtension) FullName() pref.FullName { return x.name }
151func (x placeholderExtension) IsPlaceholder() bool { return true }
152func (x placeholderExtension) Options() pref.ProtoMessage { return descopts.Field }
153func (x placeholderExtension) Number() pref.FieldNumber { return x.number }
154func (x placeholderExtension) Cardinality() pref.Cardinality { return 0 }
155func (x placeholderExtension) Kind() pref.Kind { return 0 }
156func (x placeholderExtension) HasJSONName() bool { return false }
157func (x placeholderExtension) JSONName() string { return "" }
158func (x placeholderExtension) IsExtension() bool { return true }
159func (x placeholderExtension) IsWeak() bool { return false }
160func (x placeholderExtension) IsPacked() bool { return false }
161func (x placeholderExtension) IsList() bool { return false }
162func (x placeholderExtension) IsMap() bool { return false }
163func (x placeholderExtension) MapKey() pref.FieldDescriptor { return nil }
164func (x placeholderExtension) MapValue() pref.FieldDescriptor { return nil }
165func (x placeholderExtension) HasDefault() bool { return false }
166func (x placeholderExtension) Default() pref.Value { return pref.Value{} }
167func (x placeholderExtension) DefaultEnumValue() pref.EnumValueDescriptor { return nil }
168func (x placeholderExtension) ContainingOneof() pref.OneofDescriptor { return nil }
169func (x placeholderExtension) ContainingMessage() pref.MessageDescriptor { return nil }
170func (x placeholderExtension) Enum() pref.EnumDescriptor { return nil }
171func (x placeholderExtension) Message() pref.MessageDescriptor { return nil }
172func (x placeholderExtension) ProtoType(pref.FieldDescriptor) { return }
173func (x placeholderExtension) ProtoInternal(pragma.DoNotImplement) { return }