internal/filedesc, internal/filetype: initial commit
The internal/fileinit package is split apart into two packages:
* internal/filedesc constructs descriptors from the raw proto.
It is very similar to the previous internal/fileinit package.
* internal/filetype wraps descriptors with Go type information
Overview:
* The internal/fileinit package will be deleted in a future CL.
It is kept around since the v1 repo currently depends on it.
* The internal/prototype package is deleted. All former usages of it
are now using internal/filedesc instead. Most significantly,
the reflect/protodesc package was almost entirely re-written.
* The internal/impl package drops support for messages that do not
have a Descriptor method (pre-2016). This removes a significant amount
of technical debt.
filedesc.Builder to parse raw descriptors.
* The internal/encoding/defval package now handles enum values by name.
Change-Id: I3957bcc8588a70470fd6c7de1122216b80615ab7
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/182360
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/internal/cmd/pbdump/pbdump.go b/internal/cmd/pbdump/pbdump.go
index 7a7c3ce..8bc1753 100644
--- a/internal/cmd/pbdump/pbdump.go
+++ b/internal/cmd/pbdump/pbdump.go
@@ -19,8 +19,8 @@
"google.golang.org/protobuf/internal/encoding/pack"
"google.golang.org/protobuf/internal/encoding/wire"
- "google.golang.org/protobuf/internal/prototype"
"google.golang.org/protobuf/internal/scalar"
+ "google.golang.org/protobuf/reflect/protodesc"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/descriptorpb"
@@ -202,41 +202,43 @@
// Descriptor returns the field tree as a message descriptor.
func (fs fields) Descriptor() (protoreflect.MessageDescriptor, error) {
- ftyp, err := prototype.NewFile(&prototype.File{
- Syntax: protoreflect.Proto2,
- Messages: []prototype.Message{fs.messageDescriptor("M")},
- })
+ fd, err := protodesc.NewFile(&descriptorpb.FileDescriptorProto{
+ Name: scalar.String("dump.proto"),
+ Syntax: scalar.String("proto2"),
+ MessageType: []*descriptorpb.DescriptorProto{fs.messageDescriptor("M")},
+ }, nil)
if err != nil {
return nil, err
}
- return ftyp.Messages().Get(0), nil
+ return fd.Messages().Get(0), nil
}
-func (fs fields) messageDescriptor(name protoreflect.FullName) prototype.Message {
- m := prototype.Message{Name: name.Name()}
+func (fs fields) messageDescriptor(name protoreflect.FullName) *descriptorpb.DescriptorProto {
+ m := &descriptorpb.DescriptorProto{Name: scalar.String(string(name.Name()))}
for _, n := range fs.sortedNums() {
- f := prototype.Field{
- Name: protoreflect.Name(fmt.Sprintf("f%d", n)),
- Number: n,
- Cardinality: protoreflect.Optional,
- Kind: fs[n].kind,
+ k := fs[n].kind
+ if !k.IsValid() {
+ k = protoreflect.MessageKind
}
- if !f.Kind.IsValid() {
- f.Kind = protoreflect.MessageKind
+ f := &descriptorpb.FieldDescriptorProto{
+ Name: scalar.String(fmt.Sprintf("f%d", n)),
+ Number: scalar.Int32(int32(n)),
+ Label: descriptorpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum(),
+ Type: descriptorpb.FieldDescriptorProto_Type(k).Enum(),
}
- switch f.Kind {
+ switch k {
case protoreflect.BoolKind, protoreflect.EnumKind,
protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Uint32Kind,
protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Uint64Kind,
protoreflect.Sfixed32Kind, protoreflect.Fixed32Kind, protoreflect.FloatKind,
protoreflect.Sfixed64Kind, protoreflect.Fixed64Kind, protoreflect.DoubleKind:
- f.Cardinality = protoreflect.Repeated
+ f.Label = descriptorpb.FieldDescriptorProto_LABEL_REPEATED.Enum()
f.Options = &descriptorpb.FieldOptions{Packed: scalar.Bool(true)}
case protoreflect.MessageKind, protoreflect.GroupKind:
s := name.Append(protoreflect.Name(fmt.Sprintf("M%d", n)))
- f.MessageType = prototype.PlaceholderMessage(s)
- m.Messages = append(m.Messages, fs[n].sub.messageDescriptor(s))
+ f.TypeName = scalar.String(string("." + s))
+ m.NestedType = append(m.NestedType, fs[n].sub.messageDescriptor(s))
}
- m.Fields = append(m.Fields, f)
+ m.Field = append(m.Field, f)
}
return m
}
diff --git a/internal/cmd/pbdump/pbdump_test.go b/internal/cmd/pbdump/pbdump_test.go
index 57ec1b5..a3f6998 100644
--- a/internal/cmd/pbdump/pbdump_test.go
+++ b/internal/cmd/pbdump/pbdump_test.go
@@ -9,13 +9,22 @@
"strings"
"testing"
- "github.com/google/go-cmp/cmp"
- "github.com/google/go-cmp/cmp/cmpopts"
-
- ptype "google.golang.org/protobuf/internal/prototype"
+ "google.golang.org/protobuf/encoding/prototext"
+ "google.golang.org/protobuf/proto"
pref "google.golang.org/protobuf/reflect/protoreflect"
+
+ "google.golang.org/protobuf/types/descriptorpb"
)
+func mustMakeMessage(s string) *descriptorpb.DescriptorProto {
+ s = fmt.Sprintf(`name:"test.proto" syntax:"proto2" message_type:[{%s}]`, s)
+ pb := new(descriptorpb.FileDescriptorProto)
+ if err := prototext.Unmarshal([]byte(s), pb); err != nil {
+ panic(err)
+ }
+ return pb.MessageType[0]
+}
+
func TestFields(t *testing.T) {
type fieldsKind struct {
kind pref.Kind
@@ -23,11 +32,11 @@
}
tests := []struct {
inFields []fieldsKind
- wantMsg ptype.Message
+ wantMsg *descriptorpb.DescriptorProto
wantErr string
}{{
inFields: []fieldsKind{{pref.MessageKind, ""}},
- wantMsg: ptype.Message{Name: "M"},
+ wantMsg: mustMakeMessage(`name:"M"`),
}, {
inFields: []fieldsKind{{pref.MessageKind, "987654321"}},
wantErr: "invalid field: 987654321",
@@ -52,44 +61,33 @@
{pref.MessageKind, " 10.20.30, 10.21 "},
{pref.GroupKind, "10"},
},
- wantMsg: ptype.Message{
- Name: "M",
- Fields: []ptype.Field{
- {Name: "f10", Number: 10, Cardinality: pref.Optional, Kind: pref.GroupKind, MessageType: ptype.PlaceholderMessage("M.M10")},
- },
- Messages: []ptype.Message{{
- Name: "M10",
- Fields: []ptype.Field{
- {Name: "f20", Number: 20, Cardinality: pref.Optional, Kind: pref.MessageKind, MessageType: ptype.PlaceholderMessage("M.M10.M20")},
- {Name: "f21", Number: 21, Cardinality: pref.Optional, Kind: pref.MessageKind, MessageType: ptype.PlaceholderMessage("M.M10.M21")},
- },
- Messages: []ptype.Message{{
- Name: "M20",
- Fields: []ptype.Field{
- {Name: "f30", Number: 30, Cardinality: pref.Optional, Kind: pref.MessageKind, MessageType: ptype.PlaceholderMessage("M.M10.M20.M30")},
- {Name: "f31", Number: 31, Cardinality: pref.Repeated, Kind: pref.Int32Kind},
- },
- Messages: []ptype.Message{{
- Name: "M30",
- }},
+ wantMsg: mustMakeMessage(`
+ name: "M"
+ field: [
+ {name:"f10" number:10 label:LABEL_OPTIONAL type:TYPE_GROUP type_name:".M.M10"}
+ ]
+ nested_type: [{
+ name: "M10"
+ field: [
+ {name:"f20" number:20 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".M.M10.M20"},
+ {name:"f21" number:21 label:LABEL_OPTIONAL type:TYPE_MESSAGE type_name:".M.M10.M21"}
+ ]
+ nested_type: [{
+ name: "M20"
+ field:[
+ {name:"f30" number:30 label:LABEL_OPTIONAL type:TYPE_MESSAGE, type_name:".M.M10.M20.M30"},
+ {name:"f31" number:31 label:LABEL_REPEATED type:TYPE_INT32 options:{packed:true}}
+ ]
+ nested_type: [{
+ name: "M30"
+ }]
}, {
- Name: "M21",
- }},
- }},
- },
+ name: "M21"
+ }]
+ }]
+ `),
}}
- opts := cmp.Options{
- cmp.Comparer(func(x, y pref.Descriptor) bool {
- if x == nil || y == nil {
- return x == nil && y == nil
- }
- return x.FullName() == y.FullName()
- }),
- cmpopts.IgnoreFields(ptype.Field{}, "Default"),
- cmpopts.IgnoreFields(ptype.Field{}, "Options"),
- cmpopts.IgnoreUnexported(ptype.Message{}, ptype.Field{}),
- }
for _, tt := range tests {
t.Run("", func(t *testing.T) {
var fields fields
@@ -106,8 +104,8 @@
t.Errorf("all Set calls succeeded, want %v error", tt.wantErr)
}
gotMsg := fields.messageDescriptor("M")
- if diff := cmp.Diff(tt.wantMsg, gotMsg, opts); diff != "" {
- t.Errorf("messageDescriptor() mismatch (-want +got):\n%v", diff)
+ if !proto.Equal(gotMsg, tt.wantMsg) {
+ t.Errorf("messageDescriptor() mismatch:\ngot %v\nwant %v", gotMsg, tt.wantMsg)
}
if _, err := fields.Descriptor(); err != nil {
t.Errorf("Descriptor() = %v, want nil error", err)