Skip to content

Commit

Permalink
protobuf: fix delimited fields under editions in go
Browse files Browse the repository at this point in the history
This brings go into conformance with other implementations.  Group-like message fields with delimited encoding will continue to use the type name for text-format, but everything else will use the field name.

Change-Id: Ib6d07f19ccfa853ce0370392c89fd24fb7148793
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/575896
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Stapelberg <stapelberg@google.com>
Commit-Queue: Michael Stapelberg <stapelberg@google.com>
  • Loading branch information
mkruskal-google authored and stapelberg committed Apr 4, 2024
1 parent 8a74430 commit a18684d
Show file tree
Hide file tree
Showing 8 changed files with 1,112 additions and 997 deletions.
19 changes: 14 additions & 5 deletions encoding/prototext/decode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -622,10 +622,12 @@ OptGroup: {}
inputText: `
opt_nested: {}
OptGroup: {}
delimited_field: {}
`,
wantMessage: &pbeditions.Nests{
OptNested: &pbeditions.Nested{},
Optgroup: &pbeditions.Nests_OptGroup{},
OptNested: &pbeditions.Nested{},
Optgroup: &pbeditions.Nests_OptGroup{},
DelimitedField: &pbeditions.Nests_OptGroup{},
},
}, {
desc: "message fields with no field separator",
Expand All @@ -644,21 +646,28 @@ OptGroup {}
inputText: `
opt_nested {}
OptGroup {}
delimited_field {}
`,
wantMessage: &pbeditions.Nests{
OptNested: &pbeditions.Nested{},
Optgroup: &pbeditions.Nests_OptGroup{},
OptNested: &pbeditions.Nested{},
Optgroup: &pbeditions.Nests_OptGroup{},
DelimitedField: &pbeditions.Nests_OptGroup{},
},
}, {
desc: "group field name",
inputMessage: &pb2.Nests{},
inputText: `optgroup: {}`,
wantErr: "unknown field: optgroup",
}, {
desc: "delimited encoded message field name",
desc: "delimited encoded group-line message field name",
inputMessage: &pbeditions.Nests{},
inputText: `optgroup: {}`,
wantErr: "unknown field: optgroup",
}, {
desc: "delimited encoded message field name",
inputMessage: &pbeditions.Nests{},
inputText: `Delimited_Field: {}`,
wantErr: "unknown field: Delimited_Field",
}, {
desc: "proto2 nested messages",
inputMessage: &pb2.Nests{},
Expand Down
25 changes: 24 additions & 1 deletion encoding/prototext/encode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ OptGroup: {}
}
`,
}, {
desc: "protoeditions delimited encoded meesage field",
desc: "protoeditions group-like delimited encoded message field",
input: &pbeditions.Nests{
Optgroup: &pbeditions.Nests_OptGroup{
OptString: proto.String("inside a group"),
Expand All @@ -548,6 +548,29 @@ OptGroup: {}
opt_fixed32: 47
}
}
`,
}, {
desc: "protoeditions delimited encoded message field",
input: &pbeditions.Nests{
DelimitedField: &pbeditions.Nests_OptGroup{
OptString: proto.String("second group"),
OptNested: &pbeditions.Nested{
OptString: proto.String("second nested message inside a group"),
},
NestedDelimitedField: &pbeditions.Nests_OptGroup_OptNestedGroup{
OptFixed32: proto.Uint32(47),
},
},
},
want: `delimited_field: {
opt_string: "second group"
opt_nested: {
opt_string: "second nested message inside a group"
}
nested_delimited_field: {
opt_fixed32: 47
}
}
`,
}, {
desc: "proto3 nested message not set",
Expand Down
31 changes: 30 additions & 1 deletion internal/filedesc/desc.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package filedesc
import (
"bytes"
"fmt"
"strings"
"sync"
"sync/atomic"

Expand Down Expand Up @@ -580,6 +581,34 @@ func (s *stringName) InitJSON(name string) {
s.nameJSON = name
}

// Returns true if this field is structured like the synthetic field of a proto2
// group. This allows us to expand our treatment of delimited fields without
// breaking proto2 files that have been upgraded to editions.
func isGroupLike(fd protoreflect.FieldDescriptor) bool {
// Groups are always group types.
if fd.Kind() != protoreflect.GroupKind {
return false
}

// Group fields are always the lowercase type name.
if strings.ToLower(string(fd.Message().Name())) != string(fd.Name()) {
return false
}

// Groups could only be defined in the same file they're used.
if fd.Message().ParentFile() != fd.ParentFile() {
return false
}

// Group messages are always defined in the same scope as the field. File
// level extensions will compare NULL == NULL here, which is why the file
// comparison above is necessary to ensure both come from the same file.
if fd.IsExtension() {
return fd.Parent() == fd.Message().Parent()
}
return fd.ContainingMessage() == fd.Message().Parent()
}

func (s *stringName) lazyInit(fd protoreflect.FieldDescriptor) *stringName {
s.once.Do(func() {
if fd.IsExtension() {
Expand All @@ -600,7 +629,7 @@ func (s *stringName) lazyInit(fd protoreflect.FieldDescriptor) *stringName {

// Format the text name.
s.nameText = string(fd.Name())
if fd.Kind() == protoreflect.GroupKind {
if isGroupLike(fd) {
s.nameText = string(fd.Message().Name())
}
}
Expand Down
1,284 changes: 650 additions & 634 deletions internal/testprotos/testeditions/test.pb.go

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions internal/testprotos/testeditions/test.proto
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ message TestAllTypes {
int32 same_field_number = 16;
}
OptionalGroup optionalgroup = 16 [features.message_encoding = DELIMITED];
OptionalGroup not_group_like_delimited = 17
[features.message_encoding = DELIMITED];
NestedMessage optional_nested_message = 18;
ForeignMessage optional_foreign_message = 19;
NestedEnum optional_nested_enum = 21;
Expand Down

0 comments on commit a18684d

Please sign in to comment.