internal/{fileinit,impl}: minimal weak field support

Weak fields are an obsolete proto1 feature. They have been superseded
by extensions. However, some vestigial support for weak fields does
remain, mostly as Google-internal patches. (They aren't exciting;
extensions really do everything weak fields do in a cleaner and
more portable fashion.)

At the moment, the only visible impact of marking a field [weak=true]
is to exclude it from "internal/fileinit".FileBuilder.DependencyIndexes.
We want to preserve that behavior just in case we ever do add full weak
field support here.

Extend fileinit to look up message descriptors for weak fields in the
global registry. If the descriptor cannot be found, use a placeholder
instead.

Remove special-case handling of weak fields in the impl package. The
code generator doesn't do anything special for them, so they can be
treated as any other field.

Change-Id: Ifa2ee3d30d63680a0eeb59c66ebc9521f38fd660
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/175997
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
This commit is contained in:
Damien Neil 2019-05-08 07:52:49 -07:00
parent bac4cd44d4
commit 82a0306187
11 changed files with 1128 additions and 1062 deletions

View File

@ -16,6 +16,7 @@ import (
ptype "github.com/golang/protobuf/v2/internal/prototype"
pvalue "github.com/golang/protobuf/v2/internal/value"
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
preg "github.com/golang/protobuf/v2/reflect/protoregistry"
)
func (file *fileDesc) lazyInit() *fileLazy {
@ -686,7 +687,12 @@ func (fd *fieldDesc) unmarshalFull(b []byte, nb *nameBuilder, pf *fileDesc, pd p
if len(rawTypeName) == 0 || rawTypeName[0] != '.' {
panic("weak target name must be fully qualified")
}
fd.messageType = ptype.PlaceholderMessage(pref.FullName(rawTypeName[1:]))
// Consult the global registry for weak messages.
name := pref.FullName(rawTypeName[1:])
fd.messageType, _ = preg.GlobalFiles.FindMessageByName(name)
if fd.messageType == nil {
fd.messageType = ptype.PlaceholderMessage(pref.FullName(rawTypeName[1:]))
}
}
}

View File

@ -99,3 +99,17 @@ func visitFields(m protoreflect.Message, f func(protoreflect.FieldDescriptor)) {
return true
})
}
func TestWeakInit(t *testing.T) {
file := testpb.File_test_test_proto
fd := file.Messages().ByName("TestWeak").Fields().ByName("weak_message")
if want, got := fd.IsWeak(), true; got != want {
t.Errorf("field %v: IsWeak() = %v, want %v", fd.FullName(), want, got)
}
if want, got := fd.Message().IsPlaceholder(), false; got != want {
t.Errorf("field %v: Message.IsPlaceholder() = %v, want %v", fd.FullName(), want, got)
}
if fd.Message().Fields().Len() == 0 {
t.Errorf("field %v: Message().Fields().Len() == 0, want >0", fd.FullName())
}
}

View File

@ -113,8 +113,6 @@ fieldLoop:
fs := fieldsByNumber[fd.Number()]
var fi fieldInfo
switch {
case fd.IsWeak():
fi = fieldInfoForWeak(fd, specialByName["XXX_weak"])
case fd.Oneof() != nil:
fi = fieldInfoForOneof(fd, oneofsByName[fd.Oneof().Name()], oneofWrappersByNumber[fd.Number()])
case fd.IsMap():

View File

@ -9,7 +9,6 @@ import (
"math"
"reflect"
"github.com/golang/protobuf/v2/internal/flags"
pvalue "github.com/golang/protobuf/v2/internal/value"
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
)
@ -24,14 +23,6 @@ type fieldInfo struct {
newMessage func() pref.Message
}
func fieldInfoForWeak(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
if !flags.Proto1Legacy {
panic("weak fields not supported")
}
// TODO: support weak fields.
panic(fmt.Sprintf("invalid field: %v", fd))
}
func fieldInfoForOneof(fd pref.FieldDescriptor, fs reflect.StructField, ot reflect.Type) fieldInfo {
ft := fs.Type
if ft.Kind() != reflect.Interface {

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@ package goproto.proto.test;
import "test/test_import.proto";
import public "test/test_public.proto";
import weak "test/test_weak.proto";
import weak "test/weak/test_weak.proto";
option go_package = "github.com/golang/protobuf/v2/internal/testprotos/test";
@ -258,6 +258,10 @@ message TestRequiredGroupFields {
}
}
message TestWeak {
optional goproto.proto.test.weak.WeakImportMessage weak_message = 1 [weak=true];
}
// Test that RPC services work.
message FooRequest {}
message FooResponse {}

View File

@ -1,92 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: test/test_weak.proto
package test
import (
protoreflect "github.com/golang/protobuf/v2/reflect/protoreflect"
protoregistry "github.com/golang/protobuf/v2/reflect/protoregistry"
protoiface "github.com/golang/protobuf/v2/runtime/protoiface"
protoimpl "github.com/golang/protobuf/v2/runtime/protoimpl"
sync "sync"
)
const _ = protoimpl.EnforceVersion(protoimpl.Version - 0)
type WeakImportMessage struct {
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized protoimpl.UnknownFields `json:"-"`
XXX_sizecache protoimpl.SizeCache `json:"-"`
}
func (x *WeakImportMessage) Reset() {
*x = WeakImportMessage{}
}
func (x *WeakImportMessage) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*WeakImportMessage) ProtoMessage() {}
func (x *WeakImportMessage) ProtoReflect() protoreflect.Message {
return file_test_test_weak_proto_msgTypes[0].MessageOf(x)
}
func (m *WeakImportMessage) XXX_Methods() *protoiface.Methods {
return file_test_test_weak_proto_msgTypes[0].Methods()
}
// Deprecated: Use WeakImportMessage.ProtoReflect.Type instead.
func (*WeakImportMessage) Descriptor() ([]byte, []int) {
return file_test_test_weak_proto_rawDescGZIP(), []int{0}
}
var File_test_test_weak_proto protoreflect.FileDescriptor
var file_test_test_weak_proto_rawDesc = []byte{
0x0a, 0x14, 0x74, 0x65, 0x73, 0x74, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x77, 0x65, 0x61, 0x6b,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x67, 0x6f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x22, 0x13, 0x0a, 0x11, 0x57, 0x65,
0x61, 0x6b, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x42,
0x38, 0x5a, 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f,
0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x76, 0x32,
0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x74, 0x65, 0x73, 0x74,
}
var (
file_test_test_weak_proto_rawDescOnce sync.Once
file_test_test_weak_proto_rawDescData = file_test_test_weak_proto_rawDesc
)
func file_test_test_weak_proto_rawDescGZIP() []byte {
file_test_test_weak_proto_rawDescOnce.Do(func() {
file_test_test_weak_proto_rawDescData = protoimpl.X.CompressGZIP(file_test_test_weak_proto_rawDescData)
})
return file_test_test_weak_proto_rawDescData
}
var file_test_test_weak_proto_msgTypes = make([]protoimpl.MessageType, 1)
var file_test_test_weak_proto_goTypes = []interface{}{
(*WeakImportMessage)(nil), // 0: goproto.proto.test.WeakImportMessage
}
var file_test_test_weak_proto_depIdxs = []int32{}
func init() { file_test_test_weak_proto_init() }
func file_test_test_weak_proto_init() {
if File_test_test_weak_proto != nil {
return
}
File_test_test_weak_proto = protoimpl.FileBuilder{
RawDescriptor: file_test_test_weak_proto_rawDesc,
GoTypes: file_test_test_weak_proto_goTypes,
DependencyIndexes: file_test_test_weak_proto_depIdxs,
MessageOutputTypes: file_test_test_weak_proto_msgTypes,
FilesRegistry: protoregistry.GlobalFiles,
TypesRegistry: protoregistry.GlobalTypes,
}.Init()
file_test_test_weak_proto_rawDesc = nil
file_test_test_weak_proto_goTypes = nil
file_test_test_weak_proto_depIdxs = nil
}

View File

@ -0,0 +1,102 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: test/weak/test_weak.proto
package weak
import (
protoreflect "github.com/golang/protobuf/v2/reflect/protoreflect"
protoregistry "github.com/golang/protobuf/v2/reflect/protoregistry"
protoiface "github.com/golang/protobuf/v2/runtime/protoiface"
protoimpl "github.com/golang/protobuf/v2/runtime/protoimpl"
sync "sync"
)
const _ = protoimpl.EnforceVersion(protoimpl.Version - 0)
type WeakImportMessage struct {
A *int32 `protobuf:"varint,1,opt,name=a" json:"a,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized protoimpl.UnknownFields `json:"-"`
XXX_sizecache protoimpl.SizeCache `json:"-"`
}
func (x *WeakImportMessage) Reset() {
*x = WeakImportMessage{}
}
func (x *WeakImportMessage) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*WeakImportMessage) ProtoMessage() {}
func (x *WeakImportMessage) ProtoReflect() protoreflect.Message {
return file_test_weak_test_weak_proto_msgTypes[0].MessageOf(x)
}
func (m *WeakImportMessage) XXX_Methods() *protoiface.Methods {
return file_test_weak_test_weak_proto_msgTypes[0].Methods()
}
// Deprecated: Use WeakImportMessage.ProtoReflect.Type instead.
func (*WeakImportMessage) Descriptor() ([]byte, []int) {
return file_test_weak_test_weak_proto_rawDescGZIP(), []int{0}
}
func (x *WeakImportMessage) GetA() int32 {
if x != nil && x.A != nil {
return *x.A
}
return 0
}
var File_test_weak_test_weak_proto protoreflect.FileDescriptor
var file_test_weak_test_weak_proto_rawDesc = []byte{
0x0a, 0x19, 0x74, 0x65, 0x73, 0x74, 0x2f, 0x77, 0x65, 0x61, 0x6b, 0x2f, 0x74, 0x65, 0x73, 0x74,
0x5f, 0x77, 0x65, 0x61, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x17, 0x67, 0x6f, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e,
0x77, 0x65, 0x61, 0x6b, 0x22, 0x21, 0x0a, 0x11, 0x57, 0x65, 0x61, 0x6b, 0x49, 0x6d, 0x70, 0x6f,
0x72, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x0c, 0x0a, 0x01, 0x61, 0x18, 0x01,
0x20, 0x01, 0x28, 0x05, 0x52, 0x01, 0x61, 0x42, 0x3d, 0x5a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75,
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2f, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x76, 0x32, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
0x6c, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x74, 0x65, 0x73,
0x74, 0x2f, 0x77, 0x65, 0x61, 0x6b,
}
var (
file_test_weak_test_weak_proto_rawDescOnce sync.Once
file_test_weak_test_weak_proto_rawDescData = file_test_weak_test_weak_proto_rawDesc
)
func file_test_weak_test_weak_proto_rawDescGZIP() []byte {
file_test_weak_test_weak_proto_rawDescOnce.Do(func() {
file_test_weak_test_weak_proto_rawDescData = protoimpl.X.CompressGZIP(file_test_weak_test_weak_proto_rawDescData)
})
return file_test_weak_test_weak_proto_rawDescData
}
var file_test_weak_test_weak_proto_msgTypes = make([]protoimpl.MessageType, 1)
var file_test_weak_test_weak_proto_goTypes = []interface{}{
(*WeakImportMessage)(nil), // 0: goproto.proto.test.weak.WeakImportMessage
}
var file_test_weak_test_weak_proto_depIdxs = []int32{}
func init() { file_test_weak_test_weak_proto_init() }
func file_test_weak_test_weak_proto_init() {
if File_test_weak_test_weak_proto != nil {
return
}
File_test_weak_test_weak_proto = protoimpl.FileBuilder{
RawDescriptor: file_test_weak_test_weak_proto_rawDesc,
GoTypes: file_test_weak_test_weak_proto_goTypes,
DependencyIndexes: file_test_weak_test_weak_proto_depIdxs,
MessageOutputTypes: file_test_weak_test_weak_proto_msgTypes,
FilesRegistry: protoregistry.GlobalFiles,
TypesRegistry: protoregistry.GlobalTypes,
}.Init()
file_test_weak_test_weak_proto_rawDesc = nil
file_test_weak_test_weak_proto_goTypes = nil
file_test_weak_test_weak_proto_depIdxs = nil
}

View File

@ -4,9 +4,10 @@
syntax = "proto2";
package goproto.proto.test;
package goproto.proto.test.weak;
option go_package = "github.com/golang/protobuf/v2/internal/testprotos/test";
option go_package = "github.com/golang/protobuf/v2/internal/testprotos/test/weak";
message WeakImportMessage {
optional int32 a = 1;
}

View File

@ -26,9 +26,6 @@ func TestMessage(t testing.TB, message proto.Message) {
for i := 0; i < md.Fields().Len(); i++ {
fd := md.Fields().Get(i)
switch {
case fd.IsWeak():
// TODO: Weak field support.
continue
case fd.IsMap():
testFieldMap(t, m, fd)
case fd.Cardinality() == pref.Repeated:

View File

@ -19,6 +19,7 @@ func Test(t *testing.T) {
(*testpb.TestAllTypes)(nil),
(*test3pb.TestAllTypes)(nil),
(*testpb.TestRequired)(nil),
(*testpb.TestWeak)(nil),
} {
t.Run(fmt.Sprintf("%T", m), func(t *testing.T) {
prototest.TestMessage(t, m)