Skip to content

Commit acaef6a

Browse files
committed
cmd/protoc-gen-go: avoid referencing remote enum values by name
The Go generator has historically always prefixed an enum value with the name of the enum type, when it was unnecessary to do so. For example: enum Status { STATUS_FAILED = 0; STATUS_PASSED = 1; } would be generated as: type Status int32 const ( Status_STATUS_FAILED Status = 0 Status_STATUS_PASSED Status = 1 ) It is common for the enum values to be manually prefixed by the enum type since protobuf enums use C++ namespace rules where enum types and enum values are in the same namespace scope. Thus, having the Go generator add a prefix is redundant. See golang/protobuf#513. Some custom Go generators like protoc-gen-gogo allow removing the prefix with the gogoproto.goproto_enum_prefix feature. However, this leads to interoperability issues between protoc-gen-go and protoc-gen-gogo, where the enum value names cannot be accurately inferred. Avoid this problem by just hard-coding the enum value number for values declared in other packages. This provides benefits in interoperability at the small cost of enum values possibly being stale if their value were ever changed in a remote package. However, this would only occur with use of proto2 enums and default values, which seems to be an exceptionally rare situation. Before: Default_MyMessage_MyField = remotepb.FooEnum_FOO_ENUM After: Default_MyMessage_MyField = remotepb.FooEnum(4) // remotepb.FooEnum_FOO_ENUM Before: func (x *MyMessage) GetField() remotepb.FooEnum { ... return remotepb.FooEnum_FOO_ZERO } After: func (x *MyMessage) GetField() remotepb.FooEnum { ... return remotepb.FooEnum(0) // always 0 for proto3 and often 0 for proto2 } Change-Id: I3a06cd553f2eaf6124666f6c36c196d500d35718 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/319649 Trust: Joe Tsai <joetsai@digital-static.net> Reviewed-by: Damien Neil <dneil@google.com>
1 parent 50a8591 commit acaef6a

File tree

9 files changed

+1392
-1295
lines changed

9 files changed

+1392
-1295
lines changed

cmd/protoc-gen-go/internal_gengo/main.go

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,15 @@ func genMessageDefaultDecls(g *protogen.GeneratedFile, f *fileInfo, m *messageIn
447447
case protoreflect.EnumKind:
448448
idx := field.Desc.DefaultEnumValue().Index()
449449
val := field.Enum.Values[idx]
450-
consts = append(consts, fmt.Sprintf("%s = %s", name, g.QualifiedGoIdent(val.GoIdent)))
450+
if val.GoIdent.GoImportPath == f.GoImportPath {
451+
consts = append(consts, fmt.Sprintf("%s = %s", name, g.QualifiedGoIdent(val.GoIdent)))
452+
} else {
453+
// If the enum value is declared in a different Go package,
454+
// reference it by number since the name may not be correct.
455+
// See https://github.com/golang/protobuf/issues/513.
456+
consts = append(consts, fmt.Sprintf("%s = %s(%d) // %s",
457+
name, g.QualifiedGoIdent(field.Enum.GoIdent), val.Desc.Number(), g.QualifiedGoIdent(val.GoIdent)))
458+
}
451459
case protoreflect.FloatKind, protoreflect.DoubleKind:
452460
if f := defVal.Float(); math.IsNaN(f) || math.IsInf(f, 0) {
453461
var fn, arg string
@@ -550,7 +558,7 @@ func genMessageGetterMethods(g *protogen.GeneratedFile, f *fileInfo, m *messageI
550558

551559
// Getter for message field.
552560
goType, pointer := fieldGoType(g, f, field)
553-
defaultValue := fieldDefaultValue(g, m, field)
561+
defaultValue := fieldDefaultValue(g, f, m, field)
554562
g.Annotate(m.GoIdent.GoName+".Get"+field.GoName, field.Location)
555563
leadingComments := appendDeprecationSuffix("",
556564
field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated())
@@ -672,7 +680,7 @@ func fieldProtobufTagValue(field *protogen.Field) string {
672680
return tag.Marshal(field.Desc, enumName)
673681
}
674682

675-
func fieldDefaultValue(g *protogen.GeneratedFile, m *messageInfo, field *protogen.Field) string {
683+
func fieldDefaultValue(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo, field *protogen.Field) string {
676684
if field.Desc.IsList() {
677685
return "nil"
678686
}
@@ -691,7 +699,15 @@ func fieldDefaultValue(g *protogen.GeneratedFile, m *messageInfo, field *protoge
691699
case protoreflect.MessageKind, protoreflect.GroupKind, protoreflect.BytesKind:
692700
return "nil"
693701
case protoreflect.EnumKind:
694-
return g.QualifiedGoIdent(field.Enum.Values[0].GoIdent)
702+
val := field.Enum.Values[0]
703+
if val.GoIdent.GoImportPath == f.GoImportPath {
704+
return g.QualifiedGoIdent(val.GoIdent)
705+
} else {
706+
// If the enum value is declared in a different Go package,
707+
// reference it by number since the name may not be correct.
708+
// See https://github.com/golang/protobuf/issues/513.
709+
return g.QualifiedGoIdent(field.Enum.GoIdent) + "(" + strconv.FormatInt(int64(val.Desc.Number()), 32) + ")"
710+
}
695711
default:
696712
return "0"
697713
}

cmd/protoc-gen-go/testdata/import_public/a.pb.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/protoc-gen-go/testdata/import_public/b.pb.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/testprotos/conformance/test_messages_proto3.pb.go

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/testprotos/fieldtrack/fieldtrack.pb.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/testprotos/test/test.pb.go

Lines changed: 1359 additions & 1283 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/testprotos/test/test.proto

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ syntax = "proto2";
66

77
package goproto.proto.test;
88

9+
import "google/protobuf/descriptor.proto";
910
import "internal/testprotos/test/test_import.proto";
1011
import public "internal/testprotos/test/test_public.proto";
1112
import weak "internal/testprotos/test/weak1/test_weak.proto";
@@ -381,3 +382,7 @@ service TestDeprecatedService {
381382
message WeirdDefault {
382383
optional bytes weird_default = 1 [default = "hello, \"world!\"\ndead\xde\xad\xbe\xefbeef`"];
383384
}
385+
386+
message RemoteDefault {
387+
optional google.protobuf.FieldDescriptorProto.Type type = 1 [default = TYPE_ENUM];
388+
}

internal/testprotos/textpb2/test.pb.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

types/known/apipb/api.pb.go

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)