| // Copyright 2024 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package protogen |
| |
| import ( |
| "google.golang.org/protobuf/internal/strs" |
| "google.golang.org/protobuf/reflect/protoreflect" |
| ) |
| |
| func opaqueNewFieldHook(desc protoreflect.FieldDescriptor, field *Field) { |
| field.camelCase = strs.GoCamelCase(string(desc.Name())) |
| } |
| |
| func opaqueNewOneofHook(desc protoreflect.OneofDescriptor, oneof *Oneof) { |
| oneof.camelCase = strs.GoCamelCase(string(desc.Name())) |
| } |
| |
| func opaqueNewMessageHook(message *Message) { |
| // New name mangling scheme: Add a '_' between method base |
| // name (Get, Set, Clear etc) and original field name if |
| // needed. As a special case, there is one globally reserved |
| // name, e.g. "Build" thet still results in actual renaming of |
| // the builder field like in the old scheme. We begin by |
| // taking care of this special case. |
| for _, field := range message.Fields { |
| if field.camelCase == "Build" { |
| field.camelCase += "_" |
| } |
| } |
| |
| // Then find all names of the original field names, we do not want the old scheme to affect |
| // how we name things. |
| |
| camelCases := map[string]bool{} |
| for _, field := range message.Fields { |
| if field.Oneof != nil { |
| // We add the name of the union here (potentially many times). |
| camelCases[field.Oneof.camelCase] = true |
| } |
| // The member fields of the oneof are considered fields in the struct although |
| // they are not technically there. This is to allow changing a proto2 optional |
| // to a oneof with source code compatibility. |
| camelCases[field.camelCase] = true |
| |
| } |
| // For each field, check if any of it's methods would clash with an original field name |
| for _, field := range message.Fields { |
| // Every field (except the union fields, that are taken care of separately) has |
| // a Get and a Set method. |
| methods := []string{"Set", "Get"} |
| // For explicit presence fields, we also have Has and Clear. |
| if field.Desc.HasPresence() { |
| methods = append(methods, "Has", "Clear") |
| } |
| for _, method := range methods { |
| // If any method name clashes with a field name, all methods get a |
| // "_" inserted between the operation and the field name. |
| if camelCases[method+field.camelCase] { |
| field.hasConflictHybrid = true |
| } |
| } |
| } |
| // The union names for oneofs need only have a methods prefix if there is a clash with Has, Clear or Which in |
| // hybrid and opaque-v0. |
| for _, field := range message.Fields { |
| if field.Oneof == nil { |
| continue |
| } |
| for _, method := range []string{"Has", "Clear", "Which"} { |
| // Same logic as for regular fields - all methods get the "_" if one needs it. |
| if camelCases[method+field.Oneof.camelCase] { |
| field.Oneof.hasConflictHybrid = true |
| } |
| } |
| } |
| |
| } |