legacy_extension.go

  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
  5package impl
  6
  7import (
  8	"reflect"
  9
 10	"google.golang.org/protobuf/internal/descopts"
 11	"google.golang.org/protobuf/internal/encoding/messageset"
 12	ptag "google.golang.org/protobuf/internal/encoding/tag"
 13	"google.golang.org/protobuf/internal/filedesc"
 14	"google.golang.org/protobuf/internal/pragma"
 15	"google.golang.org/protobuf/reflect/protoreflect"
 16	"google.golang.org/protobuf/reflect/protoregistry"
 17	"google.golang.org/protobuf/runtime/protoiface"
 18)
 19
 20func (xi *ExtensionInfo) initToLegacy() {
 21	xd := xi.desc
 22	var parent protoiface.MessageV1
 23	messageName := xd.ContainingMessage().FullName()
 24	if mt, _ := protoregistry.GlobalTypes.FindMessageByName(messageName); mt != nil {
 25		// Create a new parent message and unwrap it if possible.
 26		mv := mt.New().Interface()
 27		t := reflect.TypeOf(mv)
 28		if mv, ok := mv.(unwrapper); ok {
 29			t = reflect.TypeOf(mv.protoUnwrap())
 30		}
 31
 32		// Check whether the message implements the legacy v1 Message interface.
 33		mz := reflect.Zero(t).Interface()
 34		if mz, ok := mz.(protoiface.MessageV1); ok {
 35			parent = mz
 36		}
 37	}
 38
 39	// Determine the v1 extension type, which is unfortunately not the same as
 40	// the v2 ExtensionType.GoType.
 41	extType := xi.goType
 42	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
 45	}
 46
 47	// Reconstruct the legacy enum full name.
 48	var enumName string
 49	if xd.Kind() == protoreflect.EnumKind {
 50		enumName = legacyEnumName(xd.Enum())
 51	}
 52
 53	// Derive the proto file that the extension was declared within.
 54	var filename string
 55	if fd := xd.ParentFile(); fd != nil {
 56		filename = fd.Path()
 57	}
 58
 59	// 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
 65	xi.ExtendedType = parent
 66	xi.ExtensionType = reflect.Zero(extType).Interface()
 67	xi.Field = int32(xd.Number())
 68	xi.Name = string(name)
 69	xi.Tag = ptag.Marshal(xd, enumName)
 70	xi.Filename = filename
 71}
 72
 73// initFromLegacy initializes an ExtensionInfo from
 74// the contents of the deprecated exported fields of the type.
 75func (xi *ExtensionInfo) initFromLegacy() {
 76	// 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:   protoreflect.FullName(xi.Name),
 81			number: protoreflect.FieldNumber(xi.Field),
 82		}
 83		xi.desc = extensionTypeDescriptor{xd, xi}
 84		return
 85	}
 86
 87	// Resolve enum or message dependencies.
 88	var ed protoreflect.EnumDescriptor
 89	var md protoreflect.MessageDescriptor
 90	t := reflect.TypeOf(xi.ExtensionType)
 91	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	}
 96	switch v := reflect.Zero(t).Interface().(type) {
 97	case protoreflect.Enum:
 98		ed = v.Descriptor()
 99	case enumV1:
100		ed = LegacyLoadEnumDesc(t)
101	case protoreflect.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 protoreflect.EnumValueDescriptors
109	if ed != nil {
110		evs = ed.Values()
111	}
112	fd := ptag.Unmarshal(xi.Tag, t, evs).(*filedesc.Field)
113
114	// Construct a v2 ExtensionType.
115	xd := &filedesc.Extension{L2: new(filedesc.ExtensionL2)}
116	xd.L0.ParentFile = filedesc.SurrogateProto2
117	xd.L0.FullName = protoreflect.FullName(xi.Name)
118	xd.L1.Number = protoreflect.FieldNumber(xi.Field)
119	xd.L1.Cardinality = fd.L1.Cardinality
120	xd.L1.Kind = fd.L1.Kind
121	xd.L1.EditionFeatures = fd.L1.EditionFeatures
122	xd.L2.Default = fd.L1.Default
123	xd.L1.Extendee = Export{}.MessageDescriptorOf(xi.ExtendedType)
124	xd.L2.Enum = ed
125	xd.L2.Message = md
126
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
132	tt := reflect.TypeOf(xi.ExtensionType)
133	if isOptional {
134		tt = tt.Elem()
135	}
136	xi.goType = tt
137	xi.desc = extensionTypeDescriptor{xd, xi}
138}
139
140type placeholderExtension struct {
141	name   protoreflect.FullName
142	number protoreflect.FieldNumber
143}
144
145func (x placeholderExtension) ParentFile() protoreflect.FileDescriptor            { return nil }
146func (x placeholderExtension) Parent() protoreflect.Descriptor                    { return nil }
147func (x placeholderExtension) Index() int                                         { return 0 }
148func (x placeholderExtension) Syntax() protoreflect.Syntax                        { return 0 }
149func (x placeholderExtension) Name() protoreflect.Name                            { return x.name.Name() }
150func (x placeholderExtension) FullName() protoreflect.FullName                    { return x.name }
151func (x placeholderExtension) IsPlaceholder() bool                                { return true }
152func (x placeholderExtension) Options() protoreflect.ProtoMessage                 { return descopts.Field }
153func (x placeholderExtension) Number() protoreflect.FieldNumber                   { return x.number }
154func (x placeholderExtension) Cardinality() protoreflect.Cardinality              { return 0 }
155func (x placeholderExtension) Kind() protoreflect.Kind                            { return 0 }
156func (x placeholderExtension) HasJSONName() bool                                  { return false }
157func (x placeholderExtension) JSONName() string                                   { return "[" + string(x.name) + "]" }
158func (x placeholderExtension) TextName() string                                   { return "[" + string(x.name) + "]" }
159func (x placeholderExtension) HasPresence() bool                                  { return false }
160func (x placeholderExtension) HasOptionalKeyword() bool                           { return false }
161func (x placeholderExtension) IsExtension() bool                                  { return true }
162func (x placeholderExtension) IsWeak() bool                                       { return false }
163func (x placeholderExtension) IsLazy() bool                                       { return false }
164func (x placeholderExtension) IsPacked() bool                                     { return false }
165func (x placeholderExtension) IsList() bool                                       { return false }
166func (x placeholderExtension) IsMap() bool                                        { return false }
167func (x placeholderExtension) MapKey() protoreflect.FieldDescriptor               { return nil }
168func (x placeholderExtension) MapValue() protoreflect.FieldDescriptor             { return nil }
169func (x placeholderExtension) HasDefault() bool                                   { return false }
170func (x placeholderExtension) Default() protoreflect.Value                        { return protoreflect.Value{} }
171func (x placeholderExtension) DefaultEnumValue() protoreflect.EnumValueDescriptor { return nil }
172func (x placeholderExtension) ContainingOneof() protoreflect.OneofDescriptor      { return nil }
173func (x placeholderExtension) ContainingMessage() protoreflect.MessageDescriptor  { return nil }
174func (x placeholderExtension) Enum() protoreflect.EnumDescriptor                  { return nil }
175func (x placeholderExtension) Message() protoreflect.MessageDescriptor            { return nil }
176func (x placeholderExtension) ProtoType(protoreflect.FieldDescriptor)             { return }
177func (x placeholderExtension) ProtoInternal(pragma.DoNotImplement)                { return }