cmd/protoc-gen-go: add support for map fields
Generate the proper map[key]value type for map fields.
Include the protobuf_key and protobuf_val field tags.
Do not generate the map entry structs.
Fix an initialization order bug in protogen: While proto files cannot
contain circular dependencies, a single file can contain dependency
cycles. First create types for all the descriptors in a file, then add
in references (currently just field->message and field->enum) in a
second pass.
Change-Id: Ifedfa657d8dbb00413ba493adee1119b19c1b773
Reviewed-on: https://go-review.googlesource.com/135355
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/cmd/protoc-gen-go/main.go b/cmd/protoc-gen-go/main.go
index 3a062b4..815f080 100644
--- a/cmd/protoc-gen-go/main.go
+++ b/cmd/protoc-gen-go/main.go
@@ -246,6 +246,10 @@
}
func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, f *File, message *protogen.Message) {
+ if message.Desc.IsMapEntry() {
+ return
+ }
+
for _, e := range message.Enums {
genEnum(gen, g, f, e)
}
@@ -263,7 +267,19 @@
if pointer {
goType = "*" + goType
}
- g.P(field.GoIdent, " ", goType, fmt.Sprintf(" `protobuf:%q json:%q`", fieldProtobufTag(field), fieldJSONTag(field)))
+ tags := []string{
+ fmt.Sprintf("protobuf:%q", fieldProtobufTag(field)),
+ fmt.Sprintf("json:%q", fieldJSONTag(field)),
+ }
+ if field.Desc.IsMap() {
+ key := field.MessageType.Fields[0]
+ val := field.MessageType.Fields[1]
+ tags = append(tags,
+ fmt.Sprintf("protobuf_key:%q", fieldProtobufTag(key)),
+ fmt.Sprintf("protobuf_val:%q", fieldProtobufTag(val)),
+ )
+ }
+ g.P(field.GoIdent, " ", goType, " `", strings.Join(tags, " "), "`")
}
g.P("XXX_NoUnkeyedLiteral struct{} `json:\"-\"`")
// TODO XXX_InternalExtensions
@@ -408,7 +424,6 @@
//
// If it returns pointer=true, the struct field is a pointer to the type.
func fieldGoType(g *protogen.GeneratedFile, field *protogen.Field) (goType string, pointer bool) {
- // TODO: map types
pointer = true
switch field.Desc.Kind() {
case protoreflect.BoolKind:
@@ -433,6 +448,11 @@
goType = "[]byte"
pointer = false
case protoreflect.MessageKind, protoreflect.GroupKind:
+ if field.Desc.IsMap() {
+ keyType, _ := fieldGoType(g, field.MessageType.Fields[0])
+ valType, _ := fieldGoType(g, field.MessageType.Fields[1])
+ return fmt.Sprintf("map[%v]%v", keyType, valType), false
+ }
goType = "*" + g.QualifiedGoIdent(field.MessageType.GoIdent)
pointer = false
}