cmd/protoc-gen-go: generate oneofs
Generate everything related to oneofs: Message struct fields, wrapper
types, XXX_OneofFuncs.
Change-Id: I409040e0deb5716afabf59186eeaae21757d29f1
Reviewed-on: https://go-review.googlesource.com/135535
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/protogen/protogen.go b/protogen/protogen.go
index 29a6289..ae31fd2 100644
--- a/protogen/protogen.go
+++ b/protogen/protogen.go
@@ -392,11 +392,7 @@
f.GeneratedFilenamePrefix = prefix
for i, mdescs := 0, desc.Messages(); i < mdescs.Len(); i++ {
- message, err := newMessage(gen, f, nil, mdescs.Get(i))
- if err != nil {
- return nil, err
- }
- f.Messages = append(f.Messages, message)
+ f.Messages = append(f.Messages, newMessage(gen, f, nil, mdescs.Get(i)))
}
for i, edescs := 0, desc.Enums(); i < edescs.Len(); i++ {
f.Enums = append(f.Enums, newEnum(gen, f, nil, edescs.Get(i)))
@@ -433,12 +429,13 @@
GoIdent GoIdent // name of the generated Go type
Fields []*Field // message field declarations
+ Oneofs []*Oneof // oneof declarations
Messages []*Message // nested message declarations
Enums []*Enum // nested enum declarations
Path []int32 // location path of this message
}
-func newMessage(gen *Plugin, f *File, parent *Message, desc protoreflect.MessageDescriptor) (*Message, error) {
+func newMessage(gen *Plugin, f *File, parent *Message, desc protoreflect.MessageDescriptor) *Message {
var path []int32
if parent != nil {
path = pathAppend(parent.Path, messageMessageField, int32(desc.Index()))
@@ -452,21 +449,16 @@
}
gen.messagesByName[desc.FullName()] = message
for i, mdescs := 0, desc.Messages(); i < mdescs.Len(); i++ {
- m, err := newMessage(gen, f, message, mdescs.Get(i))
- if err != nil {
- return nil, err
- }
- message.Messages = append(message.Messages, m)
+ message.Messages = append(message.Messages, newMessage(gen, f, message, mdescs.Get(i)))
}
for i, edescs := 0, desc.Enums(); i < edescs.Len(); i++ {
message.Enums = append(message.Enums, newEnum(gen, f, message, edescs.Get(i)))
}
+ for i, odescs := 0, desc.Oneofs(); i < odescs.Len(); i++ {
+ message.Oneofs = append(message.Oneofs, newOneof(gen, f, message, odescs.Get(i)))
+ }
for i, fdescs := 0, desc.Fields(); i < fdescs.Len(); i++ {
- field, err := newField(gen, f, message, fdescs.Get(i))
- if err != nil {
- return nil, err
- }
- message.Fields = append(message.Fields, field)
+ message.Fields = append(message.Fields, newField(gen, f, message, fdescs.Get(i)))
}
// Field name conflict resolution.
@@ -502,13 +494,20 @@
usedNames["Get"+name] = true
return name
}
+ seenOneofs := make(map[int]bool)
for _, field := range message.Fields {
- field.GoIdent.GoName = makeNameUnique(field.GoIdent.GoName)
- // TODO: If this is the first field of a oneof that we haven't seen
- // before, generate the name for the oneof.
+ field.GoName = makeNameUnique(field.GoName)
+ if field.OneofType != nil {
+ if !seenOneofs[field.OneofType.Desc.Index()] {
+ // If this is a field in a oneof that we haven't seen before,
+ // make the name for that oneof unique as well.
+ field.OneofType.GoName = makeNameUnique(field.OneofType.GoName)
+ seenOneofs[field.OneofType.Desc.Index()] = true
+ }
+ }
}
- return message, nil
+ return message
}
func (message *Message) init(gen *Plugin) error {
@@ -522,6 +521,9 @@
return err
}
}
+ for _, oneof := range message.Oneofs {
+ oneof.init(gen, message)
+ }
return nil
}
@@ -529,26 +531,29 @@
type Field struct {
Desc protoreflect.FieldDescriptor
- // GoIdent is the base name of this field's Go fields and methods.
+ // GoName is the base name of this field's Go field and methods.
// For code generated by protoc-gen-go, this means a field named
- // '{{GoIdent}}' and a getter method named 'Get{{GoIdent}}'.
- GoIdent GoIdent
+ // '{{GoName}}' and a getter method named 'Get{{GoName}}'.
+ GoName string
- MessageType *Message // type for message or group fields; nil otherwise
- EnumType *Enum // type for enum fields; nil otherwise
- Path []int32 // location path of this field
+ ContainingType *Message // message in which this field occurs
+ MessageType *Message // type for message or group fields; nil otherwise
+ EnumType *Enum // type for enum fields; nil otherwise
+ OneofType *Oneof // containing oneof; nil if not part of a oneof
+ Path []int32 // location path of this field
}
-func newField(gen *Plugin, f *File, message *Message, desc protoreflect.FieldDescriptor) (*Field, error) {
+func newField(gen *Plugin, f *File, message *Message, desc protoreflect.FieldDescriptor) *Field {
field := &Field{
- Desc: desc,
- GoIdent: GoIdent{
- GoName: camelCase(string(desc.Name())),
- GoImportPath: f.GoImportPath,
- },
- Path: pathAppend(message.Path, messageFieldField, int32(desc.Index())),
+ Desc: desc,
+ GoName: camelCase(string(desc.Name())),
+ ContainingType: message,
+ Path: pathAppend(message.Path, messageFieldField, int32(desc.Index())),
}
- return field, nil
+ if desc.OneofType() != nil {
+ field.OneofType = message.Oneofs[desc.OneofType().Index()]
+ }
+ return field
}
func (field *Field) init(gen *Plugin) error {
@@ -572,6 +577,31 @@
return nil
}
+// A Oneof describes a oneof field.
+type Oneof struct {
+ Desc protoreflect.OneofDescriptor
+
+ GoName string // Go field name of this oneof
+ ContainingType *Message // message in which this oneof occurs
+ Fields []*Field // fields that are part of this oneof
+ Path []int32 // location path of this oneof
+}
+
+func newOneof(gen *Plugin, f *File, message *Message, desc protoreflect.OneofDescriptor) *Oneof {
+ return &Oneof{
+ Desc: desc,
+ ContainingType: message,
+ GoName: camelCase(string(desc.Name())),
+ Path: pathAppend(message.Path, messageOneofField, int32(desc.Index())),
+ }
+}
+
+func (oneof *Oneof) init(gen *Plugin, parent *Message) {
+ for i, fdescs := 0, oneof.Desc.Fields(); i < fdescs.Len(); i++ {
+ oneof.Fields = append(oneof.Fields, parent.Fields[fdescs.Get(i).Index()])
+ }
+}
+
// An Enum describes an enum.
type Enum struct {
Desc protoreflect.EnumDescriptor