func (p *plugin) Generate(file *generator.FileDescriptor) { for _, msg := range file.Messages() { for _, os := range overwriters { possible := true for _, overwriter := range os { if overwriter(file.FileDescriptorProto, msg.DescriptorProto) { possible = false } } if possible { p.checkOverwrite(msg, os) } } p.checkNameSpace(msg) for _, field := range msg.GetField() { if gogoproto.IsEmbed(field) && gogoproto.IsCustomName(field) { fmt.Fprintf(os.Stderr, "ERROR: field %v with custom name %v cannot be embedded", *field.Name, gogoproto.GetCustomName(field)) os.Exit(1) } } p.checkRepeated(msg) } for _, e := range file.GetExtension() { if gogoproto.IsEmbed(e) { fmt.Fprintf(os.Stderr, "ERROR: extended field %v cannot be embedded", generator.CamelCase(*e.Name)) os.Exit(1) } } }
//Collapses a proto fieldpath into a go fieldpath. They are different if some of the fields in the fieldpath have been embedded. func Collapse(rootPkg string, rootMsg string, path string, descriptorSet *descriptor.FileDescriptorSet) (string, error) { msg := descriptorSet.GetMessage(rootPkg, rootMsg) if msg == nil { return "", &errUndefined{rootPkg, rootMsg, path} } paths := strings.Split(path, ".") if len(paths) == 0 { return "", &errUndefined{rootPkg, rootMsg, path} } if len(paths) == 1 { return path, nil } for _, f := range msg.GetField() { if f.GetName() != paths[0] { continue } if f.IsMessage() { newRootPkg, newRootMsg := descriptorSet.FindMessage(rootPkg, rootMsg, f.GetName()) if len(newRootPkg) == 0 || len(newRootMsg) == 0 { return "", &errUndefined{rootPkg, rootMsg, path} } newPath, err := Collapse(newRootPkg, newRootMsg, strings.Join(paths[1:], "."), descriptorSet) if err != nil { return "", err } if gogoproto.IsEmbed(f) { return newPath, nil } else { return paths[0] + "." + newPath, nil } } } if msg.IsExtendable() { newRootPkg, f := descriptorSet.FindExtension(rootPkg, rootMsg, paths[0]) if f == nil { return "", &errUndefined{rootPkg, rootMsg, path} } typeName := f.GetTypeName() typeNames := strings.Split(typeName, ".") newRootMsg := typeName if len(typeNames) > 1 { newRootMsg = typeNames[len(typeNames)-1] } newPath, err := Collapse(newRootPkg, newRootMsg, strings.Join(paths[1:], "."), descriptorSet) if err != nil { return "", err } if gogoproto.IsEmbed(f) { return newPath, nil } else { return paths[0] + "." + newPath, nil } } return "", nil }
func (p *plugin) checkNameSpace(message *generator.Descriptor) map[string]bool { ccTypeName := generator.CamelCaseSlice(message.TypeName()) names := make(map[string]bool) for _, field := range message.Field { fieldname := generator.CamelCase(*field.Name) if field.IsMessage() && gogoproto.IsEmbed(field) { desc := p.ObjectNamed(field.GetTypeName()) moreNames := p.checkNameSpace(desc.(*generator.Descriptor)) for another := range moreNames { if names[another] { fmt.Fprintf(os.Stderr, "ERROR: duplicate embedded fieldname %v in type %v\n", fieldname, ccTypeName) os.Exit(1) } names[another] = true } } else { if names[fieldname] { fmt.Fprintf(os.Stderr, "ERROR: duplicate embedded fieldname %v in type %v\n", fieldname, ccTypeName) os.Exit(1) } names[fieldname] = true } } return names }
func (g *Generator) GetFieldName(message *Descriptor, field *descriptor.FieldDescriptorProto) string { goTyp, _ := g.GoType(message, field) fieldname := CamelCase(*field.Name) if gogoproto.IsCustomName(field) { fieldname = gogoproto.GetCustomName(field) } if gogoproto.IsEmbed(field) { fieldname = EmbedFieldName(goTyp) } for _, f := range methodNames { if f == fieldname { return fieldname + "_" } } return fieldname }
func (p *plugin) checkRepeated(message *generator.Descriptor) { ccTypeName := generator.CamelCaseSlice(message.TypeName()) for _, field := range message.Field { if !gogoproto.IsEmbed(field) { continue } if field.IsBytes() { fieldname := generator.CamelCase(*field.Name) fmt.Fprintf(os.Stderr, "ERROR: found embedded bytes field %s in message %s\n", fieldname, ccTypeName) os.Exit(1) } if !field.IsRepeated() { continue } fieldname := generator.CamelCase(*field.Name) fmt.Fprintf(os.Stderr, "ERROR: found repeated embedded field %s in message %s\n", fieldname, ccTypeName) os.Exit(1) } }
func (p *plugin) checkOverwrite(message *generator.Descriptor, enablers map[string]gogoproto.EnableFunc) { ccTypeName := generator.CamelCaseSlice(message.TypeName()) names := []string{} for name := range enablers { names = append(names, name) } for _, field := range message.Field { if field.IsMessage() && gogoproto.IsEmbed(field) { fieldname := generator.CamelCase(*field.Name) desc := p.ObjectNamed(field.GetTypeName()) msg := desc.(*generator.Descriptor) for errStr, enabled := range enablers { if enabled(msg.File(), msg.DescriptorProto) { fmt.Fprintf(os.Stderr, "WARNING: found non-%v %v with embedded %v %v\n", names, ccTypeName, errStr, fieldname) } } p.checkOverwrite(msg, enablers) } } }