types/known/fieldmaskpb: repeated and map fields are only valid in the last position of a path
Fixes golang/protobuf#1179.
Change-Id: Ia40c287036889c798305cdaf7c8930811d25f957
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/246097
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/cmd/protoc-gen-go/internal_gengo/well_known_types.go b/cmd/protoc-gen-go/internal_gengo/well_known_types.go
index 9a1b7bd..dbaa529 100644
--- a/cmd/protoc-gen-go/internal_gengo/well_known_types.go
+++ b/cmd/protoc-gen-go/internal_gengo/well_known_types.go
@@ -971,9 +971,12 @@
g.P()
g.P(" // Identify the next message to search within.")
g.P(" md = fd.Message() // may be nil")
- g.P(" if fd.IsMap() {")
- g.P(" md = fd.MapValue().Message() // may be nil")
+ g.P()
+ g.P(" // Repeated fields are only allowed at the last postion.")
+ g.P(" if fd.IsList() || fd.IsMap() {")
+ g.P(" md = nil")
g.P(" }")
+ g.P()
g.P(" return true")
g.P(" }) {")
g.P(" return i")
diff --git a/types/known/fieldmaskpb/field_mask.pb.go b/types/known/fieldmaskpb/field_mask.pb.go
index 6a8d872..a852bef 100644
--- a/types/known/fieldmaskpb/field_mask.pb.go
+++ b/types/known/fieldmaskpb/field_mask.pb.go
@@ -393,9 +393,12 @@
// Identify the next message to search within.
md = fd.Message() // may be nil
- if fd.IsMap() {
- md = fd.MapValue().Message() // may be nil
+
+ // Repeated fields are only allowed at the last postion.
+ if fd.IsList() || fd.IsMap() {
+ md = nil
}
+
return true
}) {
return i
diff --git a/types/known/fieldmaskpb/field_mask_test.go b/types/known/fieldmaskpb/field_mask_test.go
index 6d21711..19756c5 100644
--- a/types/known/fieldmaskpb/field_mask_test.go
+++ b/types/known/fieldmaskpb/field_mask_test.go
@@ -37,7 +37,8 @@
}, {
inMessage: (*testpb.TestAllTypes)(nil),
inPaths: []string{"optional_int32", "OptionalGroup.optional_nested_message", "map_uint32_uint32", "map_string_nested_message.corecursive", "oneof_bool"},
- wantPaths: []string{"optional_int32", "OptionalGroup.optional_nested_message", "map_uint32_uint32", "map_string_nested_message.corecursive", "oneof_bool"},
+ wantPaths: []string{"optional_int32", "OptionalGroup.optional_nested_message", "map_uint32_uint32"},
+ wantError: cmpopts.AnyError,
}, {
inMessage: (*testpb.TestAllTypes)(nil),
inPaths: []string{"optional_nested_message", "optional_nested_message.corecursive", "optional_nested_message.corecursive.optional_nested_message", "optional_nested_message.corecursive.optional_nested_message.corecursive"},
@@ -194,3 +195,144 @@
})
}
}
+
+func TestIsValid(t *testing.T) {
+ tests := []struct {
+ message proto.Message
+ paths []string
+ want bool
+ }{{
+ message: (*testpb.TestAllTypes)(nil),
+ paths: []string{"no_such_field"},
+ want: false,
+ }, {
+ message: (*testpb.TestAllTypes)(nil),
+ paths: []string{""},
+ want: false,
+ }, {
+ message: (*testpb.TestAllTypes)(nil),
+ paths: []string{
+ "optional_int32",
+ "optional_int32",
+ "optional_int64",
+ "optional_uint32",
+ "optional_uint64",
+ "optional_sint32",
+ "optional_sint64",
+ "optional_fixed32",
+ "optional_fixed64",
+ "optional_sfixed32",
+ "optional_sfixed64",
+ "optional_float",
+ "optional_double",
+ "optional_bool",
+ "optional_string",
+ "optional_bytes",
+ "OptionalGroup",
+ "optional_nested_message",
+ "optional_foreign_message",
+ "optional_import_message",
+ "optional_nested_enum",
+ "optional_foreign_enum",
+ "optional_import_enum",
+ "repeated_int32",
+ "repeated_int64",
+ "repeated_uint32",
+ "repeated_uint64",
+ "repeated_sint32",
+ "repeated_sint64",
+ "repeated_fixed32",
+ "repeated_fixed64",
+ "repeated_sfixed32",
+ "repeated_sfixed64",
+ "repeated_float",
+ "repeated_double",
+ "repeated_bool",
+ "repeated_string",
+ "repeated_bytes",
+ "RepeatedGroup",
+ "repeated_nested_message",
+ "repeated_foreign_message",
+ "repeated_importmessage",
+ "repeated_nested_enum",
+ "repeated_foreign_enum",
+ "repeated_importenum",
+ "map_int32_int32",
+ "map_int64_int64",
+ "map_uint32_uint32",
+ "map_uint64_uint64",
+ "map_sint32_sint32",
+ "map_sint64_sint64",
+ "map_fixed32_fixed32",
+ "map_fixed64_fixed64",
+ "map_sfixed32_sfixed32",
+ "map_sfixed64_sfixed64",
+ "map_int32_float",
+ "map_int32_double",
+ "map_bool_bool",
+ "map_string_string",
+ "map_string_bytes",
+ "map_string_nested_message",
+ "map_string_nested_enum",
+ "oneof_uint32",
+ "oneof_nested_message",
+ "oneof_string",
+ "oneof_bytes",
+ "oneof_bool",
+ "oneof_uint64",
+ "oneof_float",
+ "oneof_double",
+ "oneof_enum",
+ "OneofGroup",
+ },
+ want: true,
+ }, {
+ message: (*testpb.TestAllTypes)(nil),
+ paths: []string{
+ "optional_nested_message.a",
+ "optional_nested_message.corecursive",
+ "optional_nested_message.corecursive.optional_int32",
+ "optional_nested_message.corecursive.optional_nested_message.corecursive.optional_nested_message.a",
+ "OptionalGroup.a",
+ "OptionalGroup.optional_nested_message",
+ "OptionalGroup.optional_nested_message.corecursive",
+ "oneof_nested_message.a",
+ "oneof_nested_message.corecursive",
+ },
+ want: true,
+ }, {
+ message: (*testpb.TestAllTypes)(nil),
+ paths: []string{"repeated_nested_message.a"},
+ want: false,
+ }, {
+ message: (*testpb.TestAllTypes)(nil),
+ paths: []string{"repeated_nested_message[0]"},
+ want: false,
+ }, {
+ message: (*testpb.TestAllTypes)(nil),
+ paths: []string{"repeated_nested_message[0].a"},
+ want: false,
+ }, {
+ message: (*testpb.TestAllTypes)(nil),
+ paths: []string{"map_string_nested_message.a"},
+ want: false,
+ }, {
+ message: (*testpb.TestAllTypes)(nil),
+ paths: []string{`map_string_nested_message["key"]`},
+ want: false,
+ }, {
+ message: (*testpb.TestAllExtensions)(nil),
+ paths: []string{"nested_string_extension"},
+ want: false,
+ }}
+
+ for _, tt := range tests {
+ t.Run("", func(t *testing.T) {
+ mask := &fmpb.FieldMask{Paths: tt.paths}
+ got := mask.IsValid(tt.message)
+ if got != tt.want {
+ t.Errorf("IsValid() returns %v want %v", got, tt.want)
+ }
+ })
+ }
+}