Selaa lähdekoodia

Ensure all field and method names are unique.

This change forces the compiler to pick unique names when generating
getters. If a name collision is found when generating a getter, it
follows the same convention as fields do and appends an "_" to the end
of the method name.

Signed-off-by: David Symonds <dsymonds@golang.org>
Andrew Braunstein 10 vuotta sitten
vanhempi
commit
8081512d5b

+ 28 - 10
protoc-gen-go/generator/generator.go

@@ -1607,18 +1607,36 @@ func (g *Generator) generateMessage(message *Descriptor) {
 	g.P("type ", ccTypeName, " struct {")
 	g.In()
 
-	allocName := func(basis string) string {
-		n := CamelCase(basis)
-		for usedNames[n] {
-			n += "_"
+	// allocNames finds a conflict-free variation of the given strings,
+	// consistently mutating their suffixes.
+	// It returns the same number of strings.
+	allocNames := func(ns ...string) []string {
+	Loop:
+		for {
+			for _, n := range ns {
+				if usedNames[n] {
+					for i := range ns {
+						ns[i] += "_"
+					}
+					continue Loop
+				}
+			}
+			for _, n := range ns {
+				usedNames[n] = true
+			}
+			return ns
 		}
-		usedNames[n] = true
-		return n
 	}
 
 	for i, field := range message.Field {
-		fieldName := allocName(*field.Name)
-		fieldGetterName := fieldName
+		// Allocate the getter and the field at the same time so name
+		// collisions create field/method consistent names.
+		// TODO: This allocation occurs based on the order of the fields
+		// in the proto file, meaning that a change in the field
+		// ordering can change generated Method/Field names.
+		base := CamelCase(*field.Name)
+		ns := allocNames(base, "Get"+base)
+		fieldName, fieldGetterName := ns[0], ns[1]
 		typename, wiretype := g.GoType(message, field)
 		jsonName := *field.Name
 		tag := fmt.Sprintf("protobuf:%s json:%q", g.goTag(message, field, wiretype), jsonName+",omitempty")
@@ -1629,7 +1647,7 @@ func (g *Generator) generateMessage(message *Descriptor) {
 		oneof := field.OneofIndex != nil
 		if oneof && oneofFieldName[*field.OneofIndex] == "" {
 			odp := message.OneofDecl[int(*field.OneofIndex)]
-			fname := allocName(odp.GetName())
+			fname := allocNames(CamelCase(odp.GetName()))[0]
 
 			// This is the first field of a oneof we haven't seen before.
 			// Generate the union field.
@@ -1907,7 +1925,7 @@ func (g *Generator) generateMessage(message *Descriptor) {
 		if t, ok := mapFieldTypes[field]; ok {
 			typename = t
 		}
-		mname := "Get" + fieldGetterNames[field]
+		mname := fieldGetterNames[field]
 		star := ""
 		if needsStar(*field.Type) && typename[0] == '*' {
 			typename = typename[1:]

+ 12 - 3
protoc-gen-go/testdata/my_test/test.pb.go

@@ -184,9 +184,11 @@ type Request struct {
 	// This is a map field. It will generate map[int32]string.
 	NameMapping map[int32]string `protobuf:"bytes,14,rep,name=name_mapping" json:"name_mapping,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
 	// This is a map field whose value type is a message.
-	MsgMapping       map[int64]*Reply `protobuf:"bytes,15,rep,name=msg_mapping" json:"msg_mapping,omitempty" protobuf_key:"zigzag64,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
-	Reset_           *int32           `protobuf:"varint,12,opt,name=reset" json:"reset,omitempty"`
-	XXX_unrecognized []byte           `json:"-"`
+	MsgMapping map[int64]*Reply `protobuf:"bytes,15,rep,name=msg_mapping" json:"msg_mapping,omitempty" protobuf_key:"zigzag64,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	Reset_     *int32           `protobuf:"varint,12,opt,name=reset" json:"reset,omitempty"`
+	// This field should not conflict with any getters.
+	GetKey_          *string `protobuf:"bytes,16,opt,name=get_key" json:"get_key,omitempty"`
+	XXX_unrecognized []byte  `json:"-"`
 }
 
 func (m *Request) Reset()         { *m = Request{} }
@@ -253,6 +255,13 @@ func (m *Request) GetReset_() int32 {
 	return 0
 }
 
+func (m *Request) GetGetKey_() string {
+	if m != nil && m.GetKey_ != nil {
+		return *m.GetKey_
+	}
+	return ""
+}
+
 type Request_SomeGroup struct {
 	GroupField       *int32 `protobuf:"varint,9,opt,name=group_field" json:"group_field,omitempty"`
 	XXX_unrecognized []byte `json:"-"`

+ 12 - 3
protoc-gen-go/testdata/my_test/test.pb.go.golden

@@ -184,9 +184,11 @@ type Request struct {
 	// This is a map field. It will generate map[int32]string.
 	NameMapping map[int32]string `protobuf:"bytes,14,rep,name=name_mapping" json:"name_mapping,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
 	// This is a map field whose value type is a message.
-	MsgMapping       map[int64]*Reply `protobuf:"bytes,15,rep,name=msg_mapping" json:"msg_mapping,omitempty" protobuf_key:"zigzag64,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
-	Reset_           *int32           `protobuf:"varint,12,opt,name=reset" json:"reset,omitempty"`
-	XXX_unrecognized []byte           `json:"-"`
+	MsgMapping map[int64]*Reply `protobuf:"bytes,15,rep,name=msg_mapping" json:"msg_mapping,omitempty" protobuf_key:"zigzag64,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	Reset_     *int32           `protobuf:"varint,12,opt,name=reset" json:"reset,omitempty"`
+	// This field should not conflict with any getters.
+	GetKey_          *string `protobuf:"bytes,16,opt,name=get_key" json:"get_key,omitempty"`
+	XXX_unrecognized []byte  `json:"-"`
 }
 
 func (m *Request) Reset()         { *m = Request{} }
@@ -253,6 +255,13 @@ func (m *Request) GetReset_() int32 {
 	return 0
 }
 
+func (m *Request) GetGetKey_() string {
+	if m != nil && m.GetKey_ != nil {
+		return *m.GetKey_
+	}
+	return ""
+}
+
 type Request_SomeGroup struct {
 	GroupField       *int32 `protobuf:"varint,9,opt,name=group_field" json:"group_field,omitempty"`
 	XXX_unrecognized []byte `json:"-"`

+ 2 - 0
protoc-gen-go/testdata/my_test/test.proto

@@ -81,6 +81,8 @@ message Request {
   map<sint64, Reply> msg_mapping = 15;
 
   optional int32 reset = 12;
+  // This field should not conflict with any getters.
+  optional string get_key = 16;
 }
 
 message Reply {