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/cmd/protoc-gen-go/main.go b/cmd/protoc-gen-go/main.go
index a6bc626..a03ae36 100644
--- a/cmd/protoc-gen-go/main.go
+++ b/cmd/protoc-gen-go/main.go
@@ -270,8 +270,14 @@
// TODO: deprecation
g.P("type ", message.GoIdent, " struct {")
for _, field := range message.Fields {
- if field.Desc.OneofType() != nil {
- // TODO oneofs
+ if field.OneofType != nil {
+ // It would be a bit simpler to iterate over the oneofs below,
+ // but generating the field here keeps the contents of the Go
+ // struct in the same order as the contents of the source
+ // .proto file.
+ if field == field.OneofType.Fields[0] {
+ genOneofField(gen, g, f, message, field.OneofType)
+ }
continue
}
genComment(g, f, field.Path)
@@ -291,7 +297,7 @@
fmt.Sprintf("protobuf_val:%q", fieldProtobufTag(val)),
)
}
- g.P(field.GoIdent, " ", goType, " `", strings.Join(tags, " "), "`")
+ g.P(field.GoName, " ", goType, " `", strings.Join(tags, " "), "`")
}
g.P("XXX_NoUnkeyedLiteral struct{} `json:\"-\"`")
// TODO XXX_InternalExtensions
@@ -359,7 +365,7 @@
if !field.Desc.HasDefault() {
continue
}
- defVarName := "Default_" + message.GoIdent.GoName + "_" + field.GoIdent.GoName
+ defVarName := "Default_" + message.GoIdent.GoName + "_" + field.GoName
def := field.Desc.Default()
switch field.Desc.Kind() {
case protoreflect.StringKind:
@@ -408,26 +414,41 @@
// Getters.
for _, field := range message.Fields {
+ if field.OneofType != nil {
+ if field == field.OneofType.Fields[0] {
+ genOneofTypes(gen, g, f, message, field.OneofType)
+ }
+ }
goType, pointer := fieldGoType(g, field)
defaultValue := fieldDefaultValue(g, message, field)
- g.P("func (m *", message.GoIdent, ") Get", field.GoIdent, "() ", goType, " {")
- if field.Desc.Syntax() == protoreflect.Proto3 || defaultValue == "nil" {
- g.P("if m != nil {")
+ g.P("func (m *", message.GoIdent, ") Get", field.GoName, "() ", goType, " {")
+ if field.OneofType != nil {
+ g.P("if x, ok := m.Get", field.OneofType.GoName, "().(*", message.GoIdent.GoName, "_", field.GoName, "); ok {")
+ g.P("return x.", field.GoName)
+ g.P("}")
} else {
- g.P("if m != nil && m.", field.GoIdent, " != nil {")
+ if field.Desc.Syntax() == protoreflect.Proto3 || defaultValue == "nil" {
+ g.P("if m != nil {")
+ } else {
+ g.P("if m != nil && m.", field.GoName, " != nil {")
+ }
+ star := ""
+ if pointer {
+ star = "*"
+ }
+ g.P("return ", star, " m.", field.GoName)
+ g.P("}")
}
- star := ""
- if pointer {
- star = "*"
- }
- g.P("return ", star, " m.", field.GoIdent)
- g.P("}")
g.P("return ", defaultValue)
g.P("}")
g.P()
}
genWellKnownType(g, message.GoIdent, message.Desc)
+
+ if len(message.Oneofs) > 0 {
+ genOneofFuncs(gen, g, f, message)
+ }
}
// fieldGoType returns the Go type used for a field.
@@ -555,7 +576,7 @@
return "nil"
}
if field.Desc.HasDefault() {
- defVarName := "Default_" + message.GoIdent.GoName + "_" + field.GoIdent.GoName
+ defVarName := "Default_" + message.GoIdent.GoName + "_" + field.GoName
if field.Desc.Kind() == protoreflect.BytesKind {
return "append([]byte(nil), " + defVarName + "...)"
}
@@ -651,16 +672,18 @@
g.P()
}
-func genComment(g *protogen.GeneratedFile, f *File, path []int32) {
+func genComment(g *protogen.GeneratedFile, f *File, path []int32) (hasComment bool) {
for _, loc := range f.locationMap[pathKey(path)] {
if loc.LeadingComments == nil {
continue
}
for _, line := range strings.Split(strings.TrimSuffix(loc.GetLeadingComments(), "\n"), "\n") {
+ hasComment = true
g.P("//", line)
}
- return
+ break
}
+ return hasComment
}
// pathKey converts a location path to a string suitable for use as a map key.