mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-03-08 19:14:05 +00:00
all: implement proto1 weak fields
This implements generation of and reflection support for weak fields. Weak fields are a proto1 feature where the "weak" option can be specified on a singular message field. A weak reference results in generated code that does not directly link in the dependency containing the weak message. Weak field support is not added to any of the serialization logic. Change-Id: I08ccfa72bc80b2ffb6af527a1677a0a81dcf33fb Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/185399 Reviewed-by: Damien Neil <dneil@google.com>
This commit is contained in:
parent
691d8563c7
commit
3d8e369c4e
@ -403,6 +403,7 @@ func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, me
|
||||
g.P("state ", protoimplPackage.Ident("MessageState"))
|
||||
sf.append("state")
|
||||
}
|
||||
hasWeak := false
|
||||
for _, field := range message.Fields {
|
||||
if field.Oneof != nil {
|
||||
// It would be a bit simpler to iterate over the oneofs below,
|
||||
@ -443,8 +444,14 @@ func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, me
|
||||
fmt.Sprintf("protobuf_val:%q", fieldProtobufTag(val)),
|
||||
)
|
||||
}
|
||||
g.Annotate(message.GoIdent.GoName+"."+field.GoName, field.Location)
|
||||
g.P(field.GoName, " ", goType, " `", strings.Join(tags, " "), "`",
|
||||
|
||||
name := field.GoName
|
||||
if field.Desc.IsWeak() {
|
||||
hasWeak = true
|
||||
name = "XXX_weak_" + name
|
||||
}
|
||||
g.Annotate(message.GoIdent.GoName+"."+name, field.Location)
|
||||
g.P(name, " ", goType, " `", strings.Join(tags, " "), "`",
|
||||
deprecationComment(field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated()))
|
||||
sf.append(field.GoName)
|
||||
}
|
||||
@ -460,6 +467,10 @@ func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, me
|
||||
g.P("sizeCache", " ", protoimplPackage.Ident("SizeCache"))
|
||||
sf.append("sizeCache")
|
||||
}
|
||||
if hasWeak {
|
||||
g.P("XXX_weak", " ", protoimplPackage.Ident("WeakFields"), " `json:\"-\"`")
|
||||
sf.append("XXX_weak")
|
||||
}
|
||||
if generateExportedUnknownFields {
|
||||
g.P("XXX_unrecognized", " ", protoimplPackage.Ident("UnknownFields"), " `json:\"-\"`")
|
||||
sf.append("XXX_unrecognized")
|
||||
@ -591,6 +602,19 @@ func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, me
|
||||
g.P(deprecationComment(true))
|
||||
}
|
||||
g.Annotate(message.GoIdent.GoName+".Get"+field.GoName, field.Location)
|
||||
if field.Desc.IsWeak() {
|
||||
g.P("func (x *", message.GoIdent, ") Get", field.GoName, "() ", protoifacePackage.Ident("MessageV1"), "{")
|
||||
g.P("if x != nil {")
|
||||
g.P("v := x.XXX_weak[", field.Desc.Number(), "]")
|
||||
g.P("_ = x.XXX_weak_" + field.GoName) // for field tracking
|
||||
g.P("if v != nil {")
|
||||
g.P("return v")
|
||||
g.P("}")
|
||||
g.P("}")
|
||||
g.P("return ", protoimplPackage.Ident("X"), ".WeakNil(", strconv.Quote(string(field.Message.Desc.FullName())), ")")
|
||||
g.P("}")
|
||||
continue
|
||||
}
|
||||
g.P("func (x *", message.GoIdent, ") Get", field.GoName, "() ", goType, " {")
|
||||
if field.Oneof != nil {
|
||||
g.P("if x, ok := x.Get", field.Oneof.GoName, "().(*", fieldOneofType(field), "); ok {")
|
||||
@ -614,6 +638,25 @@ func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, me
|
||||
g.P()
|
||||
}
|
||||
|
||||
// Setter methods.
|
||||
for _, field := range message.Fields {
|
||||
if field.Desc.IsWeak() {
|
||||
g.Annotate(message.GoIdent.GoName+".Set"+field.GoName, field.Location)
|
||||
g.P("func (x *", message.GoIdent, ") Set", field.GoName, "(v ", protoifacePackage.Ident("MessageV1"), ") {")
|
||||
g.P("if x.XXX_weak == nil {")
|
||||
g.P("x.XXX_weak = make(", protoimplPackage.Ident("WeakFields"), ")")
|
||||
g.P("}")
|
||||
g.P("if v == nil {")
|
||||
g.P("delete(x.XXX_weak, ", field.Desc.Number(), ")")
|
||||
g.P("} else {")
|
||||
g.P("x.XXX_weak[", field.Desc.Number(), "] = v")
|
||||
g.P("x.XXX_weak_"+field.GoName, " = struct{}{}") // for field tracking
|
||||
g.P("}")
|
||||
g.P("}")
|
||||
g.P()
|
||||
}
|
||||
}
|
||||
|
||||
// Oneof wrapper types.
|
||||
if len(message.Oneofs) > 0 {
|
||||
genOneofWrappers(gen, g, f, message)
|
||||
@ -624,6 +667,10 @@ func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, me
|
||||
//
|
||||
// If it returns pointer=true, the struct field is a pointer to the type.
|
||||
func fieldGoType(g *protogen.GeneratedFile, field *protogen.Field) (goType string, pointer bool) {
|
||||
if field.Desc.IsWeak() {
|
||||
return "struct{}", false
|
||||
}
|
||||
|
||||
pointer = true
|
||||
switch field.Desc.Kind() {
|
||||
case protoreflect.BoolKind:
|
||||
|
@ -48,8 +48,8 @@ func Test(t *testing.T) {
|
||||
|
||||
if *regenerate {
|
||||
t.Run("Generate", func(t *testing.T) {
|
||||
fmt.Print(mustRunCommand(t, ".", "go", "run", "./internal/cmd/generate-types", "-execute"))
|
||||
fmt.Print(mustRunCommand(t, ".", "go", "run", "./internal/cmd/generate-protos", "-execute"))
|
||||
fmt.Print(mustRunCommand(t, ".", "go", "run", "-tags", "proto1_legacy", "./internal/cmd/generate-types", "-execute"))
|
||||
fmt.Print(mustRunCommand(t, ".", "go", "run", "-tags", "proto1_legacy", "./internal/cmd/generate-protos", "-execute"))
|
||||
files := strings.Split(strings.TrimSpace(mustRunCommand(t, ".", "git", "ls-files", "*.go")), "\n")
|
||||
mustRunCommand(t, ".", append([]string{"gofmt", "-w"}, files...)...)
|
||||
})
|
||||
@ -94,11 +94,11 @@ func Test(t *testing.T) {
|
||||
mustRunCommand(t, ".", runner, "--failure_list", failureList, "--enforce_recommended", driver)
|
||||
})
|
||||
t.Run("GeneratedGoFiles", func(t *testing.T) {
|
||||
diff := mustRunCommand(t, ".", "go", "run", "./internal/cmd/generate-types")
|
||||
diff := mustRunCommand(t, ".", "go", "run", "-tags", "proto1_legacy", "./internal/cmd/generate-types")
|
||||
if strings.TrimSpace(diff) != "" {
|
||||
t.Fatalf("stale generated files:\n%v", diff)
|
||||
}
|
||||
diff = mustRunCommand(t, ".", "go", "run", "./internal/cmd/generate-protos")
|
||||
diff = mustRunCommand(t, ".", "go", "run", "-tags", "proto1_legacy", "./internal/cmd/generate-protos")
|
||||
if strings.TrimSpace(diff) != "" {
|
||||
t.Fatalf("stale generated files:\n%v", diff)
|
||||
}
|
||||
|
@ -170,9 +170,6 @@ func Marshal(fd pref.FieldDescriptor, enumName string) string {
|
||||
if fd.IsPacked() {
|
||||
tag = append(tag, "packed")
|
||||
}
|
||||
if fd.IsWeak() {
|
||||
tag = append(tag, "weak="+string(fd.Message().FullName()))
|
||||
}
|
||||
name := string(fd.Name())
|
||||
if fd.Kind() == pref.GroupKind {
|
||||
// The name of the FieldDescriptor for a group field is
|
||||
@ -186,6 +183,9 @@ func Marshal(fd pref.FieldDescriptor, enumName string) string {
|
||||
// the exact same semantics from the previous generator.
|
||||
tag = append(tag, "json="+jsonName)
|
||||
}
|
||||
if fd.IsWeak() {
|
||||
tag = append(tag, "weak="+string(fd.Message().FullName()))
|
||||
}
|
||||
// The previous implementation does not tag extension fields as proto3,
|
||||
// even when the field is defined in a proto3 file. Match that behavior
|
||||
// for consistency.
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
testpb "google.golang.org/protobuf/internal/testprotos/test"
|
||||
_ "google.golang.org/protobuf/internal/testprotos/test/weak1"
|
||||
"google.golang.org/protobuf/types/descriptorpb"
|
||||
)
|
||||
|
||||
@ -104,14 +105,28 @@ func visitFields(m protoreflect.Message, f func(protoreflect.FieldDescriptor)) {
|
||||
|
||||
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)
|
||||
|
||||
// We do not expect to get a placeholder since weak1 is imported.
|
||||
fd1 := file.Messages().ByName("TestWeak").Fields().ByName("weak_message1")
|
||||
if got, want := fd1.IsWeak(), true; got != want {
|
||||
t.Errorf("field %v: IsWeak() = %v, want %v", fd1.FullName(), got, want)
|
||||
}
|
||||
if want, got := fd.Message().IsPlaceholder(), false; got != want {
|
||||
t.Errorf("field %v: Message.IsPlaceholder() = %v, want %v", fd.FullName(), want, got)
|
||||
if got, want := fd1.Message().IsPlaceholder(), false; got != want {
|
||||
t.Errorf("field %v: Message.IsPlaceholder() = %v, want %v", fd1.FullName(), got, want)
|
||||
}
|
||||
if fd.Message().Fields().Len() == 0 {
|
||||
t.Errorf("field %v: Message().Fields().Len() == 0, want >0", fd.FullName())
|
||||
if got, want := fd1.Message().Fields().Len(), 1; got != want {
|
||||
t.Errorf("field %v: Message().Fields().Len() == %d, want %d", fd1.FullName(), got, want)
|
||||
}
|
||||
|
||||
// We do expect to get a placeholder since weak2 is not imported.
|
||||
fd2 := file.Messages().ByName("TestWeak").Fields().ByName("weak_message2")
|
||||
if got, want := fd2.IsWeak(), true; got != want {
|
||||
t.Errorf("field %v: IsWeak() = %v, want %v", fd2.FullName(), got, want)
|
||||
}
|
||||
if got, want := fd2.Message().IsPlaceholder(), true; got != want {
|
||||
t.Errorf("field %v: Message.IsPlaceholder() = %v, want %v", fd2.FullName(), got, want)
|
||||
}
|
||||
if got, want := fd2.Message().Fields().Len(), 0; got != want {
|
||||
t.Errorf("field %v: Message().Fields().Len() == %d, want %d", fd2.FullName(), got, want)
|
||||
}
|
||||
}
|
||||
|
@ -7,11 +7,15 @@ package impl
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"math"
|
||||
"reflect"
|
||||
|
||||
"google.golang.org/protobuf/internal/errors"
|
||||
pref "google.golang.org/protobuf/reflect/protoreflect"
|
||||
"google.golang.org/protobuf/reflect/protoregistry"
|
||||
piface "google.golang.org/protobuf/runtime/protoiface"
|
||||
)
|
||||
|
||||
// These functions exist to support exported APIs in generated protobufs.
|
||||
@ -74,3 +78,13 @@ func (Export) CompressGZIP(in []byte) (out []byte) {
|
||||
out = append(out, gzipFooter[:]...)
|
||||
return out
|
||||
}
|
||||
|
||||
// WeakNil returns a typed nil pointer to a concrete message.
|
||||
// It panics if the message is not linked into the binary.
|
||||
func (Export) WeakNil(s pref.FullName) piface.MessageV1 {
|
||||
mt, err := protoregistry.GlobalTypes.FindMessageByName(s)
|
||||
if err == nil {
|
||||
panic(fmt.Sprintf("weak message %v is not linked in", s))
|
||||
}
|
||||
return reflect.Zero(mt.GoType()).Interface().(piface.MessageV1)
|
||||
}
|
||||
|
@ -120,18 +120,21 @@ func (mi *MessageInfo) initOnce() {
|
||||
|
||||
type (
|
||||
SizeCache = int32
|
||||
WeakFields = map[int32]piface.MessageV1
|
||||
UnknownFields = []byte
|
||||
ExtensionFields = map[int32]ExtensionField
|
||||
)
|
||||
|
||||
var (
|
||||
sizecacheType = reflect.TypeOf(SizeCache(0))
|
||||
weakFieldsType = reflect.TypeOf(WeakFields(nil))
|
||||
unknownFieldsType = reflect.TypeOf(UnknownFields(nil))
|
||||
extensionFieldsType = reflect.TypeOf(ExtensionFields(nil))
|
||||
)
|
||||
|
||||
type structInfo struct {
|
||||
sizecacheOffset offset
|
||||
weakOffset offset
|
||||
unknownOffset offset
|
||||
extensionOffset offset
|
||||
|
||||
@ -144,6 +147,7 @@ type structInfo struct {
|
||||
func (mi *MessageInfo) makeStructInfo(t reflect.Type) structInfo {
|
||||
si := structInfo{
|
||||
sizecacheOffset: invalidOffset,
|
||||
weakOffset: invalidOffset,
|
||||
unknownOffset: invalidOffset,
|
||||
extensionOffset: invalidOffset,
|
||||
|
||||
@ -159,6 +163,9 @@ func (mi *MessageInfo) makeStructInfo(t reflect.Type) structInfo {
|
||||
if f, _ := t.FieldByName("XXX_sizecache"); f.Type == sizecacheType {
|
||||
si.sizecacheOffset = offsetOf(f, mi.Exporter)
|
||||
}
|
||||
if f, _ := t.FieldByName("XXX_weak"); f.Type == weakFieldsType {
|
||||
si.weakOffset = offsetOf(f, mi.Exporter)
|
||||
}
|
||||
if f, _ := t.FieldByName("unknownFields"); f.Type == unknownFieldsType {
|
||||
si.unknownOffset = offsetOf(f, mi.Exporter)
|
||||
}
|
||||
@ -235,6 +242,8 @@ func (mi *MessageInfo) makeKnownFieldsFunc(si structInfo) {
|
||||
fi = fieldInfoForMap(fd, fs, mi.Exporter)
|
||||
case fd.IsList():
|
||||
fi = fieldInfoForList(fd, fs, mi.Exporter)
|
||||
case fd.IsWeak():
|
||||
fi = fieldInfoForWeakMessage(fd, si.weakOffset)
|
||||
case fd.Kind() == pref.MessageKind || fd.Kind() == pref.GroupKind:
|
||||
fi = fieldInfoForMessage(fd, fs, mi.Exporter)
|
||||
default:
|
||||
|
@ -9,8 +9,10 @@ import (
|
||||
"math"
|
||||
"reflect"
|
||||
|
||||
"google.golang.org/protobuf/internal/flags"
|
||||
pvalue "google.golang.org/protobuf/internal/value"
|
||||
pref "google.golang.org/protobuf/reflect/protoreflect"
|
||||
preg "google.golang.org/protobuf/reflect/protoregistry"
|
||||
piface "google.golang.org/protobuf/runtime/protoiface"
|
||||
)
|
||||
|
||||
@ -289,6 +291,89 @@ func fieldInfoForScalar(fd pref.FieldDescriptor, fs reflect.StructField, x expor
|
||||
}
|
||||
}
|
||||
|
||||
func fieldInfoForWeakMessage(fd pref.FieldDescriptor, weakOffset offset) fieldInfo {
|
||||
if !flags.Proto1Legacy {
|
||||
panic("no support for proto1 weak fields")
|
||||
}
|
||||
|
||||
messageName := fd.Message().FullName()
|
||||
messageType, _ := preg.GlobalTypes.FindMessageByName(messageName)
|
||||
if messageType == nil {
|
||||
return fieldInfo{
|
||||
fieldDesc: fd,
|
||||
has: func(p pointer) bool { return false },
|
||||
clear: func(p pointer) {},
|
||||
get: func(p pointer) pref.Value {
|
||||
panic(fmt.Sprintf("weak message %v is not linked in", messageName))
|
||||
},
|
||||
set: func(p pointer, v pref.Value) {
|
||||
panic(fmt.Sprintf("weak message %v is not linked in", messageName))
|
||||
},
|
||||
mutable: func(p pointer) pref.Value {
|
||||
panic(fmt.Sprintf("weak message %v is not linked in", messageName))
|
||||
},
|
||||
newMessage: func() pref.Message {
|
||||
panic(fmt.Sprintf("weak message %v is not linked in", messageName))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
num := int32(fd.Number())
|
||||
frozenEmpty := pref.ValueOf(frozenMessage{messageType.New()})
|
||||
return fieldInfo{
|
||||
fieldDesc: fd,
|
||||
has: func(p pointer) bool {
|
||||
if p.IsNil() {
|
||||
return false
|
||||
}
|
||||
fs := p.Apply(weakOffset).WeakFields()
|
||||
_, ok := (*fs)[num]
|
||||
return ok
|
||||
},
|
||||
clear: func(p pointer) {
|
||||
fs := p.Apply(weakOffset).WeakFields()
|
||||
delete(*fs, num)
|
||||
},
|
||||
get: func(p pointer) pref.Value {
|
||||
if p.IsNil() {
|
||||
return frozenEmpty
|
||||
}
|
||||
fs := p.Apply(weakOffset).WeakFields()
|
||||
m, ok := (*fs)[num]
|
||||
if !ok {
|
||||
return frozenEmpty
|
||||
}
|
||||
return pref.ValueOf(m.(pref.ProtoMessage).ProtoReflect())
|
||||
},
|
||||
set: func(p pointer, v pref.Value) {
|
||||
m := v.Message()
|
||||
if m.Descriptor() != messageType.Descriptor() {
|
||||
panic("mismatching message descriptor")
|
||||
}
|
||||
fs := p.Apply(weakOffset).WeakFields()
|
||||
if *fs == nil {
|
||||
*fs = make(WeakFields)
|
||||
}
|
||||
(*fs)[num] = m.Interface().(piface.MessageV1)
|
||||
},
|
||||
mutable: func(p pointer) pref.Value {
|
||||
fs := p.Apply(weakOffset).WeakFields()
|
||||
if *fs == nil {
|
||||
*fs = make(WeakFields)
|
||||
}
|
||||
m, ok := (*fs)[num]
|
||||
if !ok {
|
||||
m = messageType.New().Interface().(piface.MessageV1)
|
||||
(*fs)[num] = m
|
||||
}
|
||||
return pref.ValueOf(m.(pref.ProtoMessage).ProtoReflect())
|
||||
},
|
||||
newMessage: func() pref.Message {
|
||||
return messageType.New()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func fieldInfoForMessage(fd pref.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
|
||||
ft := fs.Type
|
||||
conv, _ := newConverter(ft, fd.Kind())
|
||||
|
@ -122,6 +122,7 @@ func (p pointer) StringPtr() **string { return p.v.Interface().(**string) }
|
||||
func (p pointer) StringSlice() *[]string { return p.v.Interface().(*[]string) }
|
||||
func (p pointer) Bytes() *[]byte { return p.v.Interface().(*[]byte) }
|
||||
func (p pointer) BytesSlice() *[][]byte { return p.v.Interface().(*[][]byte) }
|
||||
func (p pointer) WeakFields() *WeakFields { return p.v.Interface().(*WeakFields) }
|
||||
func (p pointer) Extensions() *map[int32]ExtensionField {
|
||||
return p.v.Interface().(*map[int32]ExtensionField)
|
||||
}
|
||||
|
@ -110,6 +110,7 @@ func (p pointer) StringPtr() **string { return (**string)(p.p)
|
||||
func (p pointer) StringSlice() *[]string { return (*[]string)(p.p) }
|
||||
func (p pointer) Bytes() *[]byte { return (*[]byte)(p.p) }
|
||||
func (p pointer) BytesSlice() *[][]byte { return (*[][]byte)(p.p) }
|
||||
func (p pointer) WeakFields() *WeakFields { return (*WeakFields)(p.p) }
|
||||
func (p pointer) Extensions() *map[int32]ExtensionField { return (*map[int32]ExtensionField)(p.p) }
|
||||
|
||||
func (p pointer) Elem() pointer {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,7 +8,8 @@ package goproto.proto.test;
|
||||
|
||||
import "test/test_import.proto";
|
||||
import public "test/test_public.proto";
|
||||
import weak "test/weak/test_weak.proto";
|
||||
import weak "test/weak1/test_weak.proto";
|
||||
import weak "test/weak2/test_weak.proto";
|
||||
|
||||
option go_package = "google.golang.org/protobuf/internal/testprotos/test";
|
||||
|
||||
@ -262,7 +263,8 @@ message TestRequiredGroupFields {
|
||||
}
|
||||
|
||||
message TestWeak {
|
||||
optional goproto.proto.test.weak.WeakImportMessage weak_message = 1 [weak=true];
|
||||
optional goproto.proto.test.weak.WeakImportMessage1 weak_message1 = 1 [weak=true];
|
||||
optional goproto.proto.test.weak.WeakImportMessage2 weak_message2 = 2 [weak=true];
|
||||
}
|
||||
|
||||
message TestPackedTypes {
|
||||
|
134
internal/testprotos/test/weak1/test_weak.pb.go
Normal file
134
internal/testprotos/test/weak1/test_weak.pb.go
Normal file
@ -0,0 +1,134 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: test/weak1/test_weak.proto
|
||||
|
||||
package weak1
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 0)
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(0 - protoimpl.MinVersion)
|
||||
)
|
||||
|
||||
type WeakImportMessage1 struct {
|
||||
state protoimpl.MessageState
|
||||
A *int32 `protobuf:"varint,1,opt,name=a" json:"a,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *WeakImportMessage1) Reset() {
|
||||
*x = WeakImportMessage1{}
|
||||
}
|
||||
|
||||
func (x *WeakImportMessage1) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*WeakImportMessage1) ProtoMessage() {}
|
||||
|
||||
func (x *WeakImportMessage1) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_test_weak1_test_weak_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use WeakImportMessage1.ProtoReflect.Type instead.
|
||||
func (*WeakImportMessage1) Descriptor() ([]byte, []int) {
|
||||
return file_test_weak1_test_weak_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *WeakImportMessage1) GetA() int32 {
|
||||
if x != nil && x.A != nil {
|
||||
return *x.A
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var File_test_weak1_test_weak_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_test_weak1_test_weak_proto_rawDesc = []byte{
|
||||
0x0a, 0x1a, 0x74, 0x65, 0x73, 0x74, 0x2f, 0x77, 0x65, 0x61, 0x6b, 0x31, 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, 0x22, 0x0a, 0x12, 0x57, 0x65, 0x61, 0x6b, 0x49, 0x6d, 0x70,
|
||||
0x6f, 0x72, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x31, 0x12, 0x0c, 0x0a, 0x01, 0x61,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x01, 0x61, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x6f, 0x6f,
|
||||
0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 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, 0x31,
|
||||
}
|
||||
|
||||
var (
|
||||
file_test_weak1_test_weak_proto_rawDescOnce sync.Once
|
||||
file_test_weak1_test_weak_proto_rawDescData = file_test_weak1_test_weak_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_test_weak1_test_weak_proto_rawDescGZIP() []byte {
|
||||
file_test_weak1_test_weak_proto_rawDescOnce.Do(func() {
|
||||
file_test_weak1_test_weak_proto_rawDescData = protoimpl.X.CompressGZIP(file_test_weak1_test_weak_proto_rawDescData)
|
||||
})
|
||||
return file_test_weak1_test_weak_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_test_weak1_test_weak_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_test_weak1_test_weak_proto_goTypes = []interface{}{
|
||||
(*WeakImportMessage1)(nil), // 0: goproto.proto.test.weak.WeakImportMessage1
|
||||
}
|
||||
var file_test_weak1_test_weak_proto_depIdxs = []int32{
|
||||
0, // starting offset of method output_type sub-list
|
||||
0, // starting offset of method input_type sub-list
|
||||
0, // starting offset of extension type_name sub-list
|
||||
0, // starting offset of extension extendee sub-list
|
||||
0, // starting offset of field type_name sub-list
|
||||
}
|
||||
|
||||
func init() { file_test_weak1_test_weak_proto_init() }
|
||||
func file_test_weak1_test_weak_proto_init() {
|
||||
if File_test_weak1_test_weak_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_test_weak1_test_weak_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*WeakImportMessage1); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 2:
|
||||
return &v.sizeCache
|
||||
case 3:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
RawDescriptor: file_test_weak1_test_weak_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_test_weak1_test_weak_proto_goTypes,
|
||||
DependencyIndexes: file_test_weak1_test_weak_proto_depIdxs,
|
||||
MessageInfos: file_test_weak1_test_weak_proto_msgTypes,
|
||||
}.Build()
|
||||
File_test_weak1_test_weak_proto = out.File
|
||||
file_test_weak1_test_weak_proto_rawDesc = nil
|
||||
file_test_weak1_test_weak_proto_goTypes = nil
|
||||
file_test_weak1_test_weak_proto_depIdxs = nil
|
||||
}
|
@ -6,8 +6,8 @@ syntax = "proto2";
|
||||
|
||||
package goproto.proto.test.weak;
|
||||
|
||||
option go_package = "google.golang.org/protobuf/internal/testprotos/test/weak";
|
||||
option go_package = "google.golang.org/protobuf/internal/testprotos/test/weak1";
|
||||
|
||||
message WeakImportMessage {
|
||||
message WeakImportMessage1 {
|
||||
optional int32 a = 1;
|
||||
}
|
134
internal/testprotos/test/weak2/test_weak.pb.go
Normal file
134
internal/testprotos/test/weak2/test_weak.pb.go
Normal file
@ -0,0 +1,134 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: test/weak2/test_weak.proto
|
||||
|
||||
package weak1
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 0)
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(0 - protoimpl.MinVersion)
|
||||
)
|
||||
|
||||
type WeakImportMessage2 struct {
|
||||
state protoimpl.MessageState
|
||||
A *int32 `protobuf:"varint,1,opt,name=a" json:"a,omitempty"`
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
}
|
||||
|
||||
func (x *WeakImportMessage2) Reset() {
|
||||
*x = WeakImportMessage2{}
|
||||
}
|
||||
|
||||
func (x *WeakImportMessage2) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*WeakImportMessage2) ProtoMessage() {}
|
||||
|
||||
func (x *WeakImportMessage2) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_test_weak2_test_weak_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use WeakImportMessage2.ProtoReflect.Type instead.
|
||||
func (*WeakImportMessage2) Descriptor() ([]byte, []int) {
|
||||
return file_test_weak2_test_weak_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *WeakImportMessage2) GetA() int32 {
|
||||
if x != nil && x.A != nil {
|
||||
return *x.A
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var File_test_weak2_test_weak_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_test_weak2_test_weak_proto_rawDesc = []byte{
|
||||
0x0a, 0x1a, 0x74, 0x65, 0x73, 0x74, 0x2f, 0x77, 0x65, 0x61, 0x6b, 0x32, 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, 0x22, 0x0a, 0x12, 0x57, 0x65, 0x61, 0x6b, 0x49, 0x6d, 0x70,
|
||||
0x6f, 0x72, 0x74, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x12, 0x0c, 0x0a, 0x01, 0x61,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x01, 0x61, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x6f, 0x6f,
|
||||
0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 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, 0x31,
|
||||
}
|
||||
|
||||
var (
|
||||
file_test_weak2_test_weak_proto_rawDescOnce sync.Once
|
||||
file_test_weak2_test_weak_proto_rawDescData = file_test_weak2_test_weak_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_test_weak2_test_weak_proto_rawDescGZIP() []byte {
|
||||
file_test_weak2_test_weak_proto_rawDescOnce.Do(func() {
|
||||
file_test_weak2_test_weak_proto_rawDescData = protoimpl.X.CompressGZIP(file_test_weak2_test_weak_proto_rawDescData)
|
||||
})
|
||||
return file_test_weak2_test_weak_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_test_weak2_test_weak_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_test_weak2_test_weak_proto_goTypes = []interface{}{
|
||||
(*WeakImportMessage2)(nil), // 0: goproto.proto.test.weak.WeakImportMessage2
|
||||
}
|
||||
var file_test_weak2_test_weak_proto_depIdxs = []int32{
|
||||
0, // starting offset of method output_type sub-list
|
||||
0, // starting offset of method input_type sub-list
|
||||
0, // starting offset of extension type_name sub-list
|
||||
0, // starting offset of extension extendee sub-list
|
||||
0, // starting offset of field type_name sub-list
|
||||
}
|
||||
|
||||
func init() { file_test_weak2_test_weak_proto_init() }
|
||||
func file_test_weak2_test_weak_proto_init() {
|
||||
if File_test_weak2_test_weak_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_test_weak2_test_weak_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*WeakImportMessage2); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 2:
|
||||
return &v.sizeCache
|
||||
case 3:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
RawDescriptor: file_test_weak2_test_weak_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_test_weak2_test_weak_proto_goTypes,
|
||||
DependencyIndexes: file_test_weak2_test_weak_proto_depIdxs,
|
||||
MessageInfos: file_test_weak2_test_weak_proto_msgTypes,
|
||||
}.Build()
|
||||
File_test_weak2_test_weak_proto = out.File
|
||||
file_test_weak2_test_weak_proto_rawDesc = nil
|
||||
file_test_weak2_test_weak_proto_goTypes = nil
|
||||
file_test_weak2_test_weak_proto_depIdxs = nil
|
||||
}
|
13
internal/testprotos/test/weak2/test_weak.proto
Normal file
13
internal/testprotos/test/weak2/test_weak.proto
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package goproto.proto.test.weak;
|
||||
|
||||
option go_package = "google.golang.org/protobuf/internal/testprotos/test/weak1";
|
||||
|
||||
message WeakImportMessage2 {
|
||||
optional int32 a = 1;
|
||||
}
|
@ -11,6 +11,7 @@ import (
|
||||
"google.golang.org/protobuf/internal/encoding/wire"
|
||||
"google.golang.org/protobuf/internal/errors"
|
||||
"google.golang.org/protobuf/internal/filedesc"
|
||||
"google.golang.org/protobuf/internal/flags"
|
||||
"google.golang.org/protobuf/internal/strs"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
|
||||
@ -102,6 +103,9 @@ func validateMessageDeclarations(ms []filedesc.Message, mds []*descriptorpb.Desc
|
||||
return errors.New("message %q has conflicting fields: %q with %q", m.FullName(), f1.Name(), f2.Name())
|
||||
}
|
||||
}
|
||||
if isMessageSet && !flags.Proto1Legacy {
|
||||
return errors.New("message %q is a MessageSet, which is a legacy proto1 feature that is no longer supported", m.FullName())
|
||||
}
|
||||
if isMessageSet && (m.Syntax() != protoreflect.Proto2 || m.Fields().Len() > 0 || m.ExtensionRanges().Len() == 0) {
|
||||
return errors.New("message %q is an invalid proto1 MessageSet", m.FullName())
|
||||
}
|
||||
@ -143,7 +147,10 @@ func validateMessageDeclarations(ms []filedesc.Message, mds []*descriptorpb.Desc
|
||||
if fd.Extendee != nil {
|
||||
return errors.New("message field %q may not have extendee: %q", f.FullName(), fd.GetExtendee())
|
||||
}
|
||||
if f.IsWeak() && (!isOptionalMessage(f) || f.ContainingOneof() != nil) {
|
||||
if f.IsWeak() && !flags.Proto1Legacy {
|
||||
return errors.New("message field %q is a weak field, which is a legacy proto1 feature that is no longer supported", f.FullName())
|
||||
}
|
||||
if f.IsWeak() && (f.Syntax() != protoreflect.Proto2 || !isOptionalMessage(f) || f.ContainingOneof() != nil) {
|
||||
return errors.New("message field %q may only be weak for an optional message", f.FullName())
|
||||
}
|
||||
if f.IsPacked() && !isPackable(f) {
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"google.golang.org/protobuf/encoding/prototext"
|
||||
"google.golang.org/protobuf/internal/flags"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/reflect/protoregistry"
|
||||
|
||||
@ -767,7 +768,13 @@ func TestNewFile(t *testing.T) {
|
||||
options: {message_set_wire_format:true}
|
||||
}]}]
|
||||
`),
|
||||
wantErr: `message "M.M" is an invalid proto1 MessageSet`,
|
||||
wantErr: func() string {
|
||||
if flags.Proto1Legacy {
|
||||
return `message "M.M" is an invalid proto1 MessageSet`
|
||||
} else {
|
||||
return `message "M.M" is a MessageSet, which is a legacy proto1 feature that is no longer supported`
|
||||
}
|
||||
}(),
|
||||
}, {
|
||||
label: "valid MessageSet",
|
||||
inDesc: mustParseFile(`
|
||||
@ -779,6 +786,13 @@ func TestNewFile(t *testing.T) {
|
||||
options: {message_set_wire_format:true}
|
||||
}]}]
|
||||
`),
|
||||
wantErr: func() string {
|
||||
if flags.Proto1Legacy {
|
||||
return ""
|
||||
} else {
|
||||
return `message "M.M" is a MessageSet, which is a legacy proto1 feature that is no longer supported`
|
||||
}
|
||||
}(),
|
||||
}, {
|
||||
label: "invalid extension ranges in proto3",
|
||||
inDesc: mustParseFile(`
|
||||
|
@ -68,6 +68,7 @@ type (
|
||||
MessageInfo = impl.MessageInfo
|
||||
MessageState = impl.MessageState
|
||||
SizeCache = impl.SizeCache
|
||||
WeakFields = impl.WeakFields
|
||||
UnknownFields = impl.UnknownFields
|
||||
ExtensionFields = impl.ExtensionFields
|
||||
ExtensionFieldV1 = impl.ExtensionField
|
||||
|
@ -8,22 +8,30 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
irregularpb "google.golang.org/protobuf/internal/testprotos/irregular"
|
||||
testpb "google.golang.org/protobuf/internal/testprotos/test"
|
||||
test3pb "google.golang.org/protobuf/internal/testprotos/test3"
|
||||
"google.golang.org/protobuf/internal/flags"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/testing/prototest"
|
||||
|
||||
irregularpb "google.golang.org/protobuf/internal/testprotos/irregular"
|
||||
testpb "google.golang.org/protobuf/internal/testprotos/test"
|
||||
_ "google.golang.org/protobuf/internal/testprotos/test/weak1"
|
||||
_ "google.golang.org/protobuf/internal/testprotos/test/weak2"
|
||||
test3pb "google.golang.org/protobuf/internal/testprotos/test3"
|
||||
)
|
||||
|
||||
func Test(t *testing.T) {
|
||||
for _, m := range []proto.Message{
|
||||
ms := []proto.Message{
|
||||
(*testpb.TestAllTypes)(nil),
|
||||
(*test3pb.TestAllTypes)(nil),
|
||||
(*testpb.TestRequired)(nil),
|
||||
(*testpb.TestWeak)(nil),
|
||||
(*irregularpb.Message)(nil),
|
||||
(*testpb.TestAllExtensions)(nil),
|
||||
} {
|
||||
}
|
||||
if flags.Proto1Legacy {
|
||||
ms = append(ms, (*testpb.TestWeak)(nil))
|
||||
}
|
||||
|
||||
for _, m := range ms {
|
||||
t.Run(fmt.Sprintf("%T", m), func(t *testing.T) {
|
||||
prototest.TestMessage(t, m, prototest.MessageOptions{})
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user