1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
42 package generator
43
44 import (
45 "bufio"
46 "bytes"
47 "compress/gzip"
48 "crypto/sha256"
49 "encoding/hex"
50 "fmt"
51 "go/ast"
52 "go/build"
53 "go/parser"
54 "go/printer"
55 "go/token"
56 "log"
57 "os"
58 "path"
59 "sort"
60 "strconv"
61 "strings"
62 "unicode"
63 "unicode/utf8"
64
65 "github.com/gogo/protobuf/gogoproto"
66 "github.com/gogo/protobuf/proto"
67 descriptor "github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
68 "github.com/gogo/protobuf/protoc-gen-gogo/generator/internal/remap"
69 plugin "github.com/gogo/protobuf/protoc-gen-gogo/plugin"
70 )
71
72
73
74
75
76 const generatedCodeVersion = 3
77
78
79
80 type Plugin interface {
81
82 Name() string
83
84
85 Init(g *Generator)
86
87
88 Generate(file *FileDescriptor)
89
90
91 GenerateImports(file *FileDescriptor)
92 }
93
94 type pluginSlice []Plugin
95
96 func (ps pluginSlice) Len() int {
97 return len(ps)
98 }
99
100 func (ps pluginSlice) Less(i, j int) bool {
101 return ps[i].Name() < ps[j].Name()
102 }
103
104 func (ps pluginSlice) Swap(i, j int) {
105 ps[i], ps[j] = ps[j], ps[i]
106 }
107
108 var plugins pluginSlice
109
110
111
112 func RegisterPlugin(p Plugin) {
113 plugins = append(plugins, p)
114 }
115
116
117 type GoImportPath string
118
119 func (p GoImportPath) String() string { return strconv.Quote(string(p)) }
120
121
122 type GoPackageName string
123
124
125
126
127
128
129
130
131 type common struct {
132 file *FileDescriptor
133 }
134
135
136 func (c *common) GoImportPath() GoImportPath {
137 return c.file.importPath
138 }
139
140 func (c *common) File() *FileDescriptor { return c.file }
141
142 func fileIsProto3(file *descriptor.FileDescriptorProto) bool {
143 return file.GetSyntax() == "proto3"
144 }
145
146 func (c *common) proto3() bool { return fileIsProto3(c.file.FileDescriptorProto) }
147
148
149 type Descriptor struct {
150 common
151 *descriptor.DescriptorProto
152 parent *Descriptor
153 nested []*Descriptor
154 enums []*EnumDescriptor
155 ext []*ExtensionDescriptor
156 typename []string
157 index int
158 path string
159 group bool
160 }
161
162
163
164 func (d *Descriptor) TypeName() []string {
165 if d.typename != nil {
166 return d.typename
167 }
168 n := 0
169 for parent := d; parent != nil; parent = parent.parent {
170 n++
171 }
172 s := make([]string, n)
173 for parent := d; parent != nil; parent = parent.parent {
174 n--
175 s[n] = parent.GetName()
176 }
177 d.typename = s
178 return s
179 }
180
181 func (d *Descriptor) allowOneof() bool {
182 return true
183 }
184
185
186
187 type EnumDescriptor struct {
188 common
189 *descriptor.EnumDescriptorProto
190 parent *Descriptor
191 typename []string
192 index int
193 path string
194 }
195
196
197
198 func (e *EnumDescriptor) TypeName() (s []string) {
199 if e.typename != nil {
200 return e.typename
201 }
202 name := e.GetName()
203 if e.parent == nil {
204 s = make([]string, 1)
205 } else {
206 pname := e.parent.TypeName()
207 s = make([]string, len(pname)+1)
208 copy(s, pname)
209 }
210 s[len(s)-1] = name
211 e.typename = s
212 return s
213 }
214
215
216
217
218 func (e *EnumDescriptor) alias() (s []string) {
219 s = e.TypeName()
220 if gogoproto.IsEnumCustomName(e.EnumDescriptorProto) {
221 s[len(s)-1] = gogoproto.GetEnumCustomName(e.EnumDescriptorProto)
222 }
223
224 return
225 }
226
227
228
229 func (e *EnumDescriptor) prefix() string {
230 typeName := e.alias()
231 if e.parent == nil {
232
233 return CamelCase(typeName[len(typeName)-1]) + "_"
234 }
235 return CamelCaseSlice(typeName[0:len(typeName)-1]) + "_"
236 }
237
238
239 func (e *EnumDescriptor) integerValueAsString(name string) string {
240 for _, c := range e.Value {
241 if c.GetName() == name {
242 return fmt.Sprint(c.GetNumber())
243 }
244 }
245 log.Fatal("cannot find value for enum constant")
246 return ""
247 }
248
249
250
251 type ExtensionDescriptor struct {
252 common
253 *descriptor.FieldDescriptorProto
254 parent *Descriptor
255 }
256
257
258
259 func (e *ExtensionDescriptor) TypeName() (s []string) {
260 name := e.GetName()
261 if e.parent == nil {
262
263 s = make([]string, 1)
264 } else {
265 pname := e.parent.TypeName()
266 s = make([]string, len(pname)+1)
267 copy(s, pname)
268 }
269 s[len(s)-1] = name
270 return s
271 }
272
273
274 func (e *ExtensionDescriptor) DescName() string {
275
276 typeName := e.TypeName()
277
278 for i, s := range typeName {
279 typeName[i] = CamelCase(s)
280 }
281 return "E_" + strings.Join(typeName, "_")
282 }
283
284
285 type ImportedDescriptor struct {
286 common
287 o Object
288 }
289
290 func (id *ImportedDescriptor) TypeName() []string { return id.o.TypeName() }
291
292
293
294
295 type FileDescriptor struct {
296 *descriptor.FileDescriptorProto
297 desc []*Descriptor
298 enum []*EnumDescriptor
299 ext []*ExtensionDescriptor
300 imp []*ImportedDescriptor
301
302
303 comments map[string]*descriptor.SourceCodeInfo_Location
304
305
306
307
308 exported map[Object][]symbol
309
310 importPath GoImportPath
311 packageName GoPackageName
312
313 proto3 bool
314 }
315
316
317
318
319 func (d *FileDescriptor) VarName() string {
320 h := sha256.Sum256([]byte(d.GetName()))
321 return fmt.Sprintf("fileDescriptor_%s", hex.EncodeToString(h[:8]))
322 }
323
324
325
326
327
328 func (d *FileDescriptor) goPackageOption() (impPath GoImportPath, pkg GoPackageName, ok bool) {
329 opt := d.GetOptions().GetGoPackage()
330 if opt == "" {
331 return "", "", false
332 }
333
334 sc := strings.Index(opt, ";")
335 if sc >= 0 {
336 return GoImportPath(opt[:sc]), cleanPackageName(opt[sc+1:]), true
337 }
338
339 slash := strings.LastIndex(opt, "/")
340 if slash >= 0 {
341 return GoImportPath(opt), cleanPackageName(opt[slash+1:]), true
342 }
343 return "", cleanPackageName(opt), true
344 }
345
346
347 func (d *FileDescriptor) goFileName(pathType pathType) string {
348 name := *d.Name
349 if ext := path.Ext(name); ext == ".proto" || ext == ".protodevel" {
350 name = name[:len(name)-len(ext)]
351 }
352 name += ".pb.go"
353
354 if pathType == pathTypeSourceRelative {
355 return name
356 }
357
358
359
360 if impPath, _, ok := d.goPackageOption(); ok && impPath != "" {
361
362 _, name = path.Split(name)
363 name = path.Join(string(impPath), name)
364 return name
365 }
366
367 return name
368 }
369
370 func (d *FileDescriptor) addExport(obj Object, sym symbol) {
371 d.exported[obj] = append(d.exported[obj], sym)
372 }
373
374
375 type symbol interface {
376
377
378 GenerateAlias(g *Generator, filename string, pkg GoPackageName)
379 }
380
381 type messageSymbol struct {
382 sym string
383 hasExtensions, isMessageSet bool
384 oneofTypes []string
385 }
386
387 type getterSymbol struct {
388 name string
389 typ string
390 typeName string
391 genType bool
392 }
393
394 func (ms *messageSymbol) GenerateAlias(g *Generator, filename string, pkg GoPackageName) {
395 g.P("// ", ms.sym, " from public import ", filename)
396 g.P("type ", ms.sym, " = ", pkg, ".", ms.sym)
397 for _, name := range ms.oneofTypes {
398 g.P("type ", name, " = ", pkg, ".", name)
399 }
400 }
401
402 type enumSymbol struct {
403 name string
404 proto3 bool
405 }
406
407 func (es enumSymbol) GenerateAlias(g *Generator, filename string, pkg GoPackageName) {
408 s := es.name
409 g.P("// ", s, " from public import ", filename)
410 g.P("type ", s, " = ", pkg, ".", s)
411 g.P("var ", s, "_name = ", pkg, ".", s, "_name")
412 g.P("var ", s, "_value = ", pkg, ".", s, "_value")
413 }
414
415 type constOrVarSymbol struct {
416 sym string
417 typ string
418 cast string
419 }
420
421 func (cs constOrVarSymbol) GenerateAlias(g *Generator, filename string, pkg GoPackageName) {
422 v := string(pkg) + "." + cs.sym
423 if cs.cast != "" {
424 v = cs.cast + "(" + v + ")"
425 }
426 g.P(cs.typ, " ", cs.sym, " = ", v)
427 }
428
429
430 type Object interface {
431 GoImportPath() GoImportPath
432 TypeName() []string
433 File() *FileDescriptor
434 }
435
436
437 type Generator struct {
438 *bytes.Buffer
439
440 Request *plugin.CodeGeneratorRequest
441 Response *plugin.CodeGeneratorResponse
442
443 Param map[string]string
444 PackageImportPath string
445 ImportPrefix string
446 ImportMap map[string]string
447
448 Pkg map[string]string
449
450 outputImportPath GoImportPath
451 allFiles []*FileDescriptor
452 allFilesByName map[string]*FileDescriptor
453 genFiles []*FileDescriptor
454 file *FileDescriptor
455 packageNames map[GoImportPath]GoPackageName
456 usedPackages map[GoImportPath]bool
457 usedPackageNames map[GoPackageName]bool
458 addedImports map[GoImportPath]bool
459 typeNameToObject map[string]Object
460 init []string
461 indent string
462 pathType pathType
463 writeOutput bool
464 annotateCode bool
465 annotations []*descriptor.GeneratedCodeInfo_Annotation
466
467 customImports []string
468 writtenImports map[string]bool
469 }
470
471 type pathType int
472
473 const (
474 pathTypeImport pathType = iota
475 pathTypeSourceRelative
476 )
477
478
479 func New() *Generator {
480 g := new(Generator)
481 g.Buffer = new(bytes.Buffer)
482 g.Request = new(plugin.CodeGeneratorRequest)
483 g.Response = new(plugin.CodeGeneratorResponse)
484 g.writtenImports = make(map[string]bool)
485 g.addedImports = make(map[GoImportPath]bool)
486 return g
487 }
488
489
490 func (g *Generator) Error(err error, msgs ...string) {
491 s := strings.Join(msgs, " ") + ":" + err.Error()
492 log.Print("protoc-gen-gogo: error:", s)
493 os.Exit(1)
494 }
495
496
497 func (g *Generator) Fail(msgs ...string) {
498 s := strings.Join(msgs, " ")
499 log.Print("protoc-gen-gogo: error:", s)
500 os.Exit(1)
501 }
502
503
504
505
506 func (g *Generator) CommandLineParameters(parameter string) {
507 g.Param = make(map[string]string)
508 for _, p := range strings.Split(parameter, ",") {
509 if i := strings.Index(p, "="); i < 0 {
510 g.Param[p] = ""
511 } else {
512 g.Param[p[0:i]] = p[i+1:]
513 }
514 }
515
516 g.ImportMap = make(map[string]string)
517 pluginList := "none"
518 for k, v := range g.Param {
519 switch k {
520 case "import_prefix":
521 g.ImportPrefix = v
522 case "import_path":
523 g.PackageImportPath = v
524 case "paths":
525 switch v {
526 case "import":
527 g.pathType = pathTypeImport
528 case "source_relative":
529 g.pathType = pathTypeSourceRelative
530 default:
531 g.Fail(fmt.Sprintf(`Unknown path type %q: want "import" or "source_relative".`, v))
532 }
533 case "plugins":
534 pluginList = v
535 case "annotate_code":
536 if v == "true" {
537 g.annotateCode = true
538 }
539 default:
540 if len(k) > 0 && k[0] == 'M' {
541 g.ImportMap[k[1:]] = v
542 }
543 }
544 }
545 if pluginList == "" {
546 return
547 }
548 if pluginList == "none" {
549 pluginList = ""
550 }
551 gogoPluginNames := []string{"unmarshal", "unsafeunmarshaler", "union", "stringer", "size", "protosizer", "populate", "marshalto", "unsafemarshaler", "gostring", "face", "equal", "enumstringer", "embedcheck", "description", "defaultcheck", "oneofcheck", "compare"}
552 pluginList = strings.Join(append(gogoPluginNames, pluginList), "+")
553 if pluginList != "" {
554
555 enabled := make(map[string]bool)
556 for _, name := range strings.Split(pluginList, "+") {
557 enabled[name] = true
558 }
559 var nplugins pluginSlice
560 for _, p := range plugins {
561 if enabled[p.Name()] {
562 nplugins = append(nplugins, p)
563 }
564 }
565 sort.Sort(nplugins)
566 plugins = nplugins
567 }
568 }
569
570
571
572
573 func (g *Generator) DefaultPackageName(obj Object) string {
574 importPath := obj.GoImportPath()
575 if importPath == g.outputImportPath {
576 return ""
577 }
578 return string(g.GoPackageName(importPath)) + "."
579 }
580
581
582 func (g *Generator) GoPackageName(importPath GoImportPath) GoPackageName {
583 if name, ok := g.packageNames[importPath]; ok {
584 return name
585 }
586 name := cleanPackageName(baseName(string(importPath)))
587 for i, orig := 1, name; g.usedPackageNames[name] || isGoPredeclaredIdentifier[string(name)]; i++ {
588 name = orig + GoPackageName(strconv.Itoa(i))
589 }
590 if g.packageNames == nil {
591 g.packageNames = make(map[GoImportPath]GoPackageName)
592 }
593 g.packageNames[importPath] = name
594 if g.usedPackageNames == nil {
595 g.usedPackageNames = make(map[GoPackageName]bool)
596 }
597 g.usedPackageNames[name] = true
598 return name
599 }
600
601
602
603 func (g *Generator) AddImport(importPath GoImportPath) GoPackageName {
604 g.addedImports[importPath] = true
605 return g.GoPackageName(importPath)
606 }
607
608 var globalPackageNames = map[GoPackageName]bool{
609 "fmt": true,
610 "math": true,
611 "proto": true,
612 }
613
614
615
616 func RegisterUniquePackageName(pkg string, f *FileDescriptor) string {
617 name := cleanPackageName(pkg)
618 for i, orig := 1, name; globalPackageNames[name]; i++ {
619 name = orig + GoPackageName(strconv.Itoa(i))
620 }
621 globalPackageNames[name] = true
622 return string(name)
623 }
624
625 var isGoKeyword = map[string]bool{
626 "break": true,
627 "case": true,
628 "chan": true,
629 "const": true,
630 "continue": true,
631 "default": true,
632 "else": true,
633 "defer": true,
634 "fallthrough": true,
635 "for": true,
636 "func": true,
637 "go": true,
638 "goto": true,
639 "if": true,
640 "import": true,
641 "interface": true,
642 "map": true,
643 "package": true,
644 "range": true,
645 "return": true,
646 "select": true,
647 "struct": true,
648 "switch": true,
649 "type": true,
650 "var": true,
651 }
652
653 var isGoPredeclaredIdentifier = map[string]bool{
654 "append": true,
655 "bool": true,
656 "byte": true,
657 "cap": true,
658 "close": true,
659 "complex": true,
660 "complex128": true,
661 "complex64": true,
662 "copy": true,
663 "delete": true,
664 "error": true,
665 "false": true,
666 "float32": true,
667 "float64": true,
668 "imag": true,
669 "int": true,
670 "int16": true,
671 "int32": true,
672 "int64": true,
673 "int8": true,
674 "iota": true,
675 "len": true,
676 "make": true,
677 "new": true,
678 "nil": true,
679 "panic": true,
680 "print": true,
681 "println": true,
682 "real": true,
683 "recover": true,
684 "rune": true,
685 "string": true,
686 "true": true,
687 "uint": true,
688 "uint16": true,
689 "uint32": true,
690 "uint64": true,
691 "uint8": true,
692 "uintptr": true,
693 }
694
695 func cleanPackageName(name string) GoPackageName {
696 name = strings.Map(badToUnderscore, name)
697
698 if isGoKeyword[name] {
699 name = "_" + name
700 }
701
702 if r, _ := utf8.DecodeRuneInString(name); unicode.IsDigit(r) {
703 name = "_" + name
704 }
705 return GoPackageName(name)
706 }
707
708
709
710 func (g *Generator) defaultGoPackage() GoPackageName {
711 p := g.PackageImportPath
712 if i := strings.LastIndex(p, "/"); i >= 0 {
713 p = p[i+1:]
714 }
715 return cleanPackageName(p)
716 }
717
718
719
720
721 func (g *Generator) SetPackageNames() {
722 g.outputImportPath = g.genFiles[0].importPath
723
724 defaultPackageNames := make(map[GoImportPath]GoPackageName)
725 for _, f := range g.genFiles {
726 if _, p, ok := f.goPackageOption(); ok {
727 defaultPackageNames[f.importPath] = p
728 }
729 }
730 for _, f := range g.genFiles {
731 if _, p, ok := f.goPackageOption(); ok {
732
733 f.packageName = p
734 } else if p, ok := defaultPackageNames[f.importPath]; ok {
735
736
737
738
739
740 f.packageName = p
741 } else if p := g.defaultGoPackage(); p != "" {
742
743
744
745
746 f.packageName = p
747 } else if p := f.GetPackage(); p != "" {
748
749 f.packageName = cleanPackageName(p)
750 } else {
751
752 f.packageName = cleanPackageName(baseName(f.GetName()))
753 }
754 }
755
756
757 for _, f := range g.genFiles[1:] {
758 if a, b := g.genFiles[0].importPath, f.importPath; a != b {
759 g.Fail(fmt.Sprintf("inconsistent package import paths: %v, %v", a, b))
760 }
761 if a, b := g.genFiles[0].packageName, f.packageName; a != b {
762 g.Fail(fmt.Sprintf("inconsistent package names: %v, %v", a, b))
763 }
764 }
765
766
767
768 g.Pkg = map[string]string{
769 "fmt": "fmt",
770 "math": "math",
771 "proto": "proto",
772 "golang_proto": "golang_proto",
773 }
774 }
775
776
777
778
779 func (g *Generator) WrapTypes() {
780 g.allFiles = make([]*FileDescriptor, 0, len(g.Request.ProtoFile))
781 g.allFilesByName = make(map[string]*FileDescriptor, len(g.allFiles))
782 genFileNames := make(map[string]bool)
783 for _, n := range g.Request.FileToGenerate {
784 genFileNames[n] = true
785 }
786 for _, f := range g.Request.ProtoFile {
787 fd := &FileDescriptor{
788 FileDescriptorProto: f,
789 exported: make(map[Object][]symbol),
790 proto3: fileIsProto3(f),
791 }
792
793 if substitution, ok := g.ImportMap[f.GetName()]; ok {
794
795
796
797 fd.importPath = GoImportPath(substitution)
798 } else if genFileNames[f.GetName()] && g.PackageImportPath != "" {
799
800
801
802
803 fd.importPath = GoImportPath(g.PackageImportPath)
804 } else if p, _, _ := fd.goPackageOption(); p != "" {
805
806
807
808 fd.importPath = p
809 } else {
810
811
812
813 fd.importPath = GoImportPath(path.Dir(f.GetName()))
814 }
815
816 fd.desc = wrapDescriptors(fd)
817 g.buildNestedDescriptors(fd.desc)
818 fd.enum = wrapEnumDescriptors(fd, fd.desc)
819 g.buildNestedEnums(fd.desc, fd.enum)
820 fd.ext = wrapExtensions(fd)
821 extractComments(fd)
822 g.allFiles = append(g.allFiles, fd)
823 g.allFilesByName[f.GetName()] = fd
824 }
825 for _, fd := range g.allFiles {
826 fd.imp = wrapImported(fd, g)
827 }
828
829 g.genFiles = make([]*FileDescriptor, 0, len(g.Request.FileToGenerate))
830 for _, fileName := range g.Request.FileToGenerate {
831 fd := g.allFilesByName[fileName]
832 if fd == nil {
833 g.Fail("could not find file named", fileName)
834 }
835 g.genFiles = append(g.genFiles, fd)
836 }
837 }
838
839
840 func (g *Generator) buildNestedDescriptors(descs []*Descriptor) {
841 for _, desc := range descs {
842 if len(desc.NestedType) != 0 {
843 for _, nest := range descs {
844 if nest.parent == desc {
845 desc.nested = append(desc.nested, nest)
846 }
847 }
848 if len(desc.nested) != len(desc.NestedType) {
849 g.Fail("internal error: nesting failure for", desc.GetName())
850 }
851 }
852 }
853 }
854
855 func (g *Generator) buildNestedEnums(descs []*Descriptor, enums []*EnumDescriptor) {
856 for _, desc := range descs {
857 if len(desc.EnumType) != 0 {
858 for _, enum := range enums {
859 if enum.parent == desc {
860 desc.enums = append(desc.enums, enum)
861 }
862 }
863 if len(desc.enums) != len(desc.EnumType) {
864 g.Fail("internal error: enum nesting failure for", desc.GetName())
865 }
866 }
867 }
868 }
869
870
871 func newDescriptor(desc *descriptor.DescriptorProto, parent *Descriptor, file *FileDescriptor, index int) *Descriptor {
872 d := &Descriptor{
873 common: common{file},
874 DescriptorProto: desc,
875 parent: parent,
876 index: index,
877 }
878 if parent == nil {
879 d.path = fmt.Sprintf("%d,%d", messagePath, index)
880 } else {
881 d.path = fmt.Sprintf("%s,%d,%d", parent.path, messageMessagePath, index)
882 }
883
884
885
886 if parent != nil {
887 parts := d.TypeName()
888 if file.Package != nil {
889 parts = append([]string{*file.Package}, parts...)
890 }
891 exp := "." + strings.Join(parts, ".")
892 for _, field := range parent.Field {
893 if field.GetType() == descriptor.FieldDescriptorProto_TYPE_GROUP && field.GetTypeName() == exp {
894 d.group = true
895 break
896 }
897 }
898 }
899
900 for _, field := range desc.Extension {
901 d.ext = append(d.ext, &ExtensionDescriptor{common{file}, field, d})
902 }
903
904 return d
905 }
906
907
908 func wrapDescriptors(file *FileDescriptor) []*Descriptor {
909 sl := make([]*Descriptor, 0, len(file.MessageType)+10)
910 for i, desc := range file.MessageType {
911 sl = wrapThisDescriptor(sl, desc, nil, file, i)
912 }
913 return sl
914 }
915
916
917 func wrapThisDescriptor(sl []*Descriptor, desc *descriptor.DescriptorProto, parent *Descriptor, file *FileDescriptor, index int) []*Descriptor {
918 sl = append(sl, newDescriptor(desc, parent, file, index))
919 me := sl[len(sl)-1]
920 for i, nested := range desc.NestedType {
921 sl = wrapThisDescriptor(sl, nested, me, file, i)
922 }
923 return sl
924 }
925
926
927 func newEnumDescriptor(desc *descriptor.EnumDescriptorProto, parent *Descriptor, file *FileDescriptor, index int) *EnumDescriptor {
928 ed := &EnumDescriptor{
929 common: common{file},
930 EnumDescriptorProto: desc,
931 parent: parent,
932 index: index,
933 }
934 if parent == nil {
935 ed.path = fmt.Sprintf("%d,%d", enumPath, index)
936 } else {
937 ed.path = fmt.Sprintf("%s,%d,%d", parent.path, messageEnumPath, index)
938 }
939 return ed
940 }
941
942
943 func wrapEnumDescriptors(file *FileDescriptor, descs []*Descriptor) []*EnumDescriptor {
944 sl := make([]*EnumDescriptor, 0, len(file.EnumType)+10)
945
946 for i, enum := range file.EnumType {
947 sl = append(sl, newEnumDescriptor(enum, nil, file, i))
948 }
949
950 for _, nested := range descs {
951 for i, enum := range nested.EnumType {
952 sl = append(sl, newEnumDescriptor(enum, nested, file, i))
953 }
954 }
955 return sl
956 }
957
958
959 func wrapExtensions(file *FileDescriptor) []*ExtensionDescriptor {
960 var sl []*ExtensionDescriptor
961 for _, field := range file.Extension {
962 sl = append(sl, &ExtensionDescriptor{common{file}, field, nil})
963 }
964 return sl
965 }
966
967
968 func wrapImported(file *FileDescriptor, g *Generator) (sl []*ImportedDescriptor) {
969 for _, index := range file.PublicDependency {
970 df := g.fileByName(file.Dependency[index])
971 for _, d := range df.desc {
972 if d.GetOptions().GetMapEntry() {
973 continue
974 }
975 sl = append(sl, &ImportedDescriptor{common{file}, d})
976 }
977 for _, e := range df.enum {
978 sl = append(sl, &ImportedDescriptor{common{file}, e})
979 }
980 for _, ext := range df.ext {
981 sl = append(sl, &ImportedDescriptor{common{file}, ext})
982 }
983 }
984 return
985 }
986
987 func extractComments(file *FileDescriptor) {
988 file.comments = make(map[string]*descriptor.SourceCodeInfo_Location)
989 for _, loc := range file.GetSourceCodeInfo().GetLocation() {
990 if loc.LeadingComments == nil {
991 continue
992 }
993 var p []string
994 for _, n := range loc.Path {
995 p = append(p, strconv.Itoa(int(n)))
996 }
997 file.comments[strings.Join(p, ",")] = loc
998 }
999 }
1000
1001
1002
1003
1004 func (g *Generator) BuildTypeNameMap() {
1005 g.typeNameToObject = make(map[string]Object)
1006 for _, f := range g.allFiles {
1007
1008
1009
1010 dottedPkg := "." + f.GetPackage()
1011 if dottedPkg != "." {
1012 dottedPkg += "."
1013 }
1014 for _, enum := range f.enum {
1015 name := dottedPkg + dottedSlice(enum.TypeName())
1016 g.typeNameToObject[name] = enum
1017 }
1018 for _, desc := range f.desc {
1019 name := dottedPkg + dottedSlice(desc.TypeName())
1020 g.typeNameToObject[name] = desc
1021 }
1022 }
1023 }
1024
1025
1026
1027 func (g *Generator) ObjectNamed(typeName string) Object {
1028 o, ok := g.typeNameToObject[typeName]
1029 if !ok {
1030 g.Fail("can't find object with type", typeName)
1031 }
1032 return o
1033 }
1034
1035
1036 type AnnotatedAtoms struct {
1037 source string
1038 path string
1039 atoms []interface{}
1040 }
1041
1042
1043
1044 func Annotate(file *FileDescriptor, path string, atoms ...interface{}) *AnnotatedAtoms {
1045 return &AnnotatedAtoms{source: *file.Name, path: path, atoms: atoms}
1046 }
1047
1048
1049 func (g *Generator) printAtom(v interface{}) {
1050 switch v := v.(type) {
1051 case string:
1052 g.WriteString(v)
1053 case *string:
1054 g.WriteString(*v)
1055 case bool:
1056 fmt.Fprint(g, v)
1057 case *bool:
1058 fmt.Fprint(g, *v)
1059 case int:
1060 fmt.Fprint(g, v)
1061 case *int32:
1062 fmt.Fprint(g, *v)
1063 case *int64:
1064 fmt.Fprint(g, *v)
1065 case float64:
1066 fmt.Fprint(g, v)
1067 case *float64:
1068 fmt.Fprint(g, *v)
1069 case GoPackageName:
1070 g.WriteString(string(v))
1071 case GoImportPath:
1072 g.WriteString(strconv.Quote(string(v)))
1073 default:
1074 g.Fail(fmt.Sprintf("unknown type in printer: %T", v))
1075 }
1076 }
1077
1078
1079
1080
1081
1082 func (g *Generator) P(str ...interface{}) {
1083 if !g.writeOutput {
1084 return
1085 }
1086 g.WriteString(g.indent)
1087 for _, v := range str {
1088 switch v := v.(type) {
1089 case *AnnotatedAtoms:
1090 begin := int32(g.Len())
1091 for _, v := range v.atoms {
1092 g.printAtom(v)
1093 }
1094 if g.annotateCode {
1095 end := int32(g.Len())
1096 var path []int32
1097 for _, token := range strings.Split(v.path, ",") {
1098 val, err := strconv.ParseInt(token, 10, 32)
1099 if err != nil {
1100 g.Fail("could not parse proto AST path: ", err.Error())
1101 }
1102 path = append(path, int32(val))
1103 }
1104 g.annotations = append(g.annotations, &descriptor.GeneratedCodeInfo_Annotation{
1105 Path: path,
1106 SourceFile: &v.source,
1107 Begin: &begin,
1108 End: &end,
1109 })
1110 }
1111 default:
1112 g.printAtom(v)
1113 }
1114 }
1115 g.WriteByte('\n')
1116 }
1117
1118
1119
1120 func (g *Generator) addInitf(stmt string, a ...interface{}) {
1121 g.init = append(g.init, fmt.Sprintf(stmt, a...))
1122 }
1123
1124 func (g *Generator) PrintImport(alias GoPackageName, pkg GoImportPath) {
1125 statement := string(alias) + " " + strconv.Quote(string(pkg))
1126 if g.writtenImports[statement] {
1127 return
1128 }
1129 g.P(statement)
1130 g.writtenImports[statement] = true
1131 }
1132
1133
1134 func (g *Generator) In() { g.indent += "\t" }
1135
1136
1137 func (g *Generator) Out() {
1138 if len(g.indent) > 0 {
1139 g.indent = g.indent[1:]
1140 }
1141 }
1142
1143
1144 func (g *Generator) GenerateAllFiles() {
1145
1146 for _, p := range plugins {
1147 p.Init(g)
1148 }
1149
1150
1151
1152 genFileMap := make(map[*FileDescriptor]bool, len(g.genFiles))
1153 for _, file := range g.genFiles {
1154 genFileMap[file] = true
1155 }
1156 for _, file := range g.allFiles {
1157 g.Reset()
1158 g.annotations = nil
1159 g.writeOutput = genFileMap[file]
1160 g.generate(file)
1161 if !g.writeOutput {
1162 continue
1163 }
1164 fname := file.goFileName(g.pathType)
1165 g.Response.File = append(g.Response.File, &plugin.CodeGeneratorResponse_File{
1166 Name: proto.String(fname),
1167 Content: proto.String(g.String()),
1168 })
1169 if g.annotateCode {
1170
1171
1172 g.Response.File = append(g.Response.File, &plugin.CodeGeneratorResponse_File{
1173 Name: proto.String(file.goFileName(g.pathType) + ".meta"),
1174 Content: proto.String(proto.CompactTextString(&descriptor.GeneratedCodeInfo{Annotation: g.annotations})),
1175 })
1176 }
1177 }
1178 }
1179
1180
1181 func (g *Generator) runPlugins(file *FileDescriptor) {
1182 for _, p := range plugins {
1183 p.Generate(file)
1184 }
1185 }
1186
1187
1188
1189 func (g *Generator) generate(file *FileDescriptor) {
1190 g.customImports = make([]string, 0)
1191 g.file = file
1192 g.usedPackages = make(map[GoImportPath]bool)
1193 g.packageNames = make(map[GoImportPath]GoPackageName)
1194 g.usedPackageNames = make(map[GoPackageName]bool)
1195 g.addedImports = make(map[GoImportPath]bool)
1196 for name := range globalPackageNames {
1197 g.usedPackageNames[name] = true
1198 }
1199
1200 g.P("// This is a compile-time assertion to ensure that this generated file")
1201 g.P("// is compatible with the proto package it is being compiled against.")
1202 g.P("// A compilation error at this line likely means your copy of the")
1203 g.P("// proto package needs to be updated.")
1204 if gogoproto.ImportsGoGoProto(file.FileDescriptorProto) {
1205 g.P("const _ = ", g.Pkg["proto"], ".GoGoProtoPackageIsVersion", generatedCodeVersion, " // please upgrade the proto package")
1206 } else {
1207 g.P("const _ = ", g.Pkg["proto"], ".ProtoPackageIsVersion", generatedCodeVersion, " // please upgrade the proto package")
1208 }
1209 g.P()
1210
1211 g.writtenImports = make(map[string]bool)
1212 for _, td := range g.file.imp {
1213 g.generateImported(td)
1214 }
1215 for _, enum := range g.file.enum {
1216 g.generateEnum(enum)
1217 }
1218 for _, desc := range g.file.desc {
1219
1220 if desc.GetOptions().GetMapEntry() {
1221 continue
1222 }
1223 g.generateMessage(desc)
1224 }
1225 for _, ext := range g.file.ext {
1226 g.generateExtension(ext)
1227 }
1228 g.generateInitFunction()
1229 g.generateFileDescriptor(file)
1230
1231
1232 g.runPlugins(file)
1233
1234
1235 rem := g.Buffer
1236 remAnno := g.annotations
1237 g.Buffer = new(bytes.Buffer)
1238 g.annotations = nil
1239 g.generateHeader()
1240 g.generateImports()
1241 if !g.writeOutput {
1242 return
1243 }
1244
1245 for _, anno := range remAnno {
1246 *anno.Begin += int32(g.Len())
1247 *anno.End += int32(g.Len())
1248 g.annotations = append(g.annotations, anno)
1249 }
1250 g.Write(rem.Bytes())
1251
1252
1253 fset := token.NewFileSet()
1254 original := g.Bytes()
1255 if g.annotateCode {
1256
1257 original = append([]byte(nil), original...)
1258 }
1259 fileAST, err := parser.ParseFile(fset, "", original, parser.ParseComments)
1260 if err != nil {
1261
1262
1263
1264 var src bytes.Buffer
1265 s := bufio.NewScanner(bytes.NewReader(original))
1266 for line := 1; s.Scan(); line++ {
1267 fmt.Fprintf(&src, "%5d\t%s\n", line, s.Bytes())
1268 }
1269 if serr := s.Err(); serr != nil {
1270 g.Fail("bad Go source code was generated:", err.Error(), "\n"+string(original))
1271 } else {
1272 g.Fail("bad Go source code was generated:", err.Error(), "\n"+src.String())
1273 }
1274 }
1275 ast.SortImports(fset, fileAST)
1276 g.Reset()
1277 err = (&printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}).Fprint(g, fset, fileAST)
1278 if err != nil {
1279 g.Fail("generated Go source code could not be reformatted:", err.Error())
1280 }
1281 if g.annotateCode {
1282 m, err := remap.Compute(original, g.Bytes())
1283 if err != nil {
1284 g.Fail("formatted generated Go source code could not be mapped back to the original code:", err.Error())
1285 }
1286 for _, anno := range g.annotations {
1287 new, ok := m.Find(int(*anno.Begin), int(*anno.End))
1288 if !ok {
1289 g.Fail("span in formatted generated Go source code could not be mapped back to the original code")
1290 }
1291 *anno.Begin = int32(new.Pos)
1292 *anno.End = int32(new.End)
1293 }
1294 }
1295 }
1296
1297
1298 func (g *Generator) generateHeader() {
1299 g.P("// Code generated by protoc-gen-gogo. DO NOT EDIT.")
1300 if g.file.GetOptions().GetDeprecated() {
1301 g.P("// ", *g.file.Name, " is a deprecated file.")
1302 } else {
1303 g.P("// source: ", *g.file.Name)
1304 }
1305 g.P()
1306 g.PrintComments(strconv.Itoa(packagePath))
1307 g.P()
1308 g.P("package ", g.file.packageName)
1309 g.P()
1310 }
1311
1312
1313
1314 var deprecationComment = "// Deprecated: Do not use."
1315
1316
1317
1318
1319
1320 func (g *Generator) PrintComments(path string) bool {
1321 if !g.writeOutput {
1322 return false
1323 }
1324 if c, ok := g.makeComments(path); ok {
1325 g.P(c)
1326 return true
1327 }
1328 return false
1329 }
1330
1331
1332 func (g *Generator) makeComments(path string) (string, bool) {
1333 loc, ok := g.file.comments[path]
1334 if !ok {
1335 return "", false
1336 }
1337 w := new(bytes.Buffer)
1338 nl := ""
1339 for _, line := range strings.Split(strings.TrimSuffix(loc.GetLeadingComments(), "\n"), "\n") {
1340 fmt.Fprintf(w, "%s//%s", nl, line)
1341 nl = "\n"
1342 }
1343 return w.String(), true
1344 }
1345
1346
1347
1348
1349 func (g *Generator) Comments(path string) string {
1350 loc, ok := g.file.comments[path]
1351 if !ok {
1352 return ""
1353 }
1354 text := strings.TrimSuffix(loc.GetLeadingComments(), "\n")
1355 return text
1356 }
1357
1358 func (g *Generator) fileByName(filename string) *FileDescriptor {
1359 return g.allFilesByName[filename]
1360 }
1361
1362
1363 func (g *Generator) weak(i int32) bool {
1364 for _, j := range g.file.WeakDependency {
1365 if j == i {
1366 return true
1367 }
1368 }
1369 return false
1370 }
1371
1372
1373 func (g *Generator) generateImports() {
1374 imports := make(map[GoImportPath]GoPackageName)
1375 for i, s := range g.file.Dependency {
1376 fd := g.fileByName(s)
1377 importPath := fd.importPath
1378
1379 if importPath == g.file.importPath {
1380 continue
1381 }
1382
1383 if g.weak(int32(i)) {
1384 continue
1385 }
1386
1387 if _, ok := imports[importPath]; ok {
1388 continue
1389 }
1390
1391
1392
1393 packageName := g.GoPackageName(importPath)
1394 if _, ok := g.usedPackages[importPath]; !ok {
1395 packageName = "_"
1396 }
1397 imports[importPath] = packageName
1398 }
1399 for importPath := range g.addedImports {
1400 imports[importPath] = g.GoPackageName(importPath)
1401 }
1402
1403
1404
1405 g.P("import (")
1406 g.PrintImport(GoPackageName(g.Pkg["fmt"]), "fmt")
1407 g.PrintImport(GoPackageName(g.Pkg["math"]), "math")
1408 if gogoproto.ImportsGoGoProto(g.file.FileDescriptorProto) {
1409 g.PrintImport(GoPackageName(g.Pkg["proto"]), GoImportPath(g.ImportPrefix)+GoImportPath("github.com/gogo/protobuf/proto"))
1410 if gogoproto.RegistersGolangProto(g.file.FileDescriptorProto) {
1411 g.PrintImport(GoPackageName(g.Pkg["golang_proto"]), GoImportPath(g.ImportPrefix)+GoImportPath("github.com/golang/protobuf/proto"))
1412 }
1413 } else {
1414 g.PrintImport(GoPackageName(g.Pkg["proto"]), GoImportPath(g.ImportPrefix)+GoImportPath("github.com/golang/protobuf/proto"))
1415 }
1416 for importPath, packageName := range imports {
1417 g.P(packageName, " ", GoImportPath(g.ImportPrefix)+importPath)
1418 }
1419
1420 for _, s := range g.customImports {
1421 s1 := strings.Map(badToUnderscore, s)
1422 g.PrintImport(GoPackageName(s1), GoImportPath(s))
1423 }
1424
1425
1426
1427 for _, p := range plugins {
1428 p.GenerateImports(g.file)
1429 }
1430 g.P(")")
1431
1432 g.P("// Reference imports to suppress errors if they are not otherwise used.")
1433 g.P("var _ = ", g.Pkg["proto"], ".Marshal")
1434 if gogoproto.ImportsGoGoProto(g.file.FileDescriptorProto) && gogoproto.RegistersGolangProto(g.file.FileDescriptorProto) {
1435 g.P("var _ = ", g.Pkg["golang_proto"], ".Marshal")
1436 }
1437 g.P("var _ = ", g.Pkg["fmt"], ".Errorf")
1438 g.P("var _ = ", g.Pkg["math"], ".Inf")
1439 for _, cimport := range g.customImports {
1440 if cimport == "time" {
1441 g.P("var _ = time.Kitchen")
1442 break
1443 }
1444 }
1445 g.P()
1446 }
1447
1448 func (g *Generator) generateImported(id *ImportedDescriptor) {
1449 df := id.o.File()
1450 filename := *df.Name
1451 if df.importPath == g.file.importPath {
1452
1453 return
1454 }
1455 if !supportTypeAliases {
1456 g.Fail(fmt.Sprintf("%s: public imports require at least go1.9", filename))
1457 }
1458 g.usedPackages[df.importPath] = true
1459
1460 for _, sym := range df.exported[id.o] {
1461 sym.GenerateAlias(g, filename, g.GoPackageName(df.importPath))
1462 }
1463 g.P()
1464 }
1465
1466
1467 func (g *Generator) generateEnum(enum *EnumDescriptor) {
1468
1469 typeName := enum.alias()
1470
1471 ccTypeName := CamelCaseSlice(typeName)
1472 ccPrefix := enum.prefix()
1473
1474 deprecatedEnum := ""
1475 if enum.GetOptions().GetDeprecated() {
1476 deprecatedEnum = deprecationComment
1477 }
1478
1479 g.PrintComments(enum.path)
1480 if !gogoproto.EnabledGoEnumPrefix(enum.file.FileDescriptorProto, enum.EnumDescriptorProto) {
1481 ccPrefix = ""
1482 }
1483
1484 if gogoproto.HasEnumDecl(enum.file.FileDescriptorProto, enum.EnumDescriptorProto) {
1485 g.P("type ", Annotate(enum.file, enum.path, ccTypeName), " int32", deprecatedEnum)
1486 g.file.addExport(enum, enumSymbol{ccTypeName, enum.proto3()})
1487 g.P("const (")
1488 g.In()
1489 for i, e := range enum.Value {
1490 etorPath := fmt.Sprintf("%s,%d,%d", enum.path, enumValuePath, i)
1491 g.PrintComments(etorPath)
1492
1493 deprecatedValue := ""
1494 if e.GetOptions().GetDeprecated() {
1495 deprecatedValue = deprecationComment
1496 }
1497 name := *e.Name
1498 if gogoproto.IsEnumValueCustomName(e) {
1499 name = gogoproto.GetEnumValueCustomName(e)
1500 }
1501 name = ccPrefix + name
1502
1503 g.P(Annotate(enum.file, etorPath, name), " ", ccTypeName, " = ", e.Number, " ", deprecatedValue)
1504 g.file.addExport(enum, constOrVarSymbol{name, "const", ccTypeName})
1505 }
1506 g.Out()
1507 g.P(")")
1508 }
1509 g.P()
1510 g.P("var ", ccTypeName, "_name = map[int32]string{")
1511 g.In()
1512 generated := make(map[int32]bool)
1513 for _, e := range enum.Value {
1514 duplicate := ""
1515 if _, present := generated[*e.Number]; present {
1516 duplicate = "// Duplicate value: "
1517 }
1518 g.P(duplicate, e.Number, ": ", strconv.Quote(*e.Name), ",")
1519 generated[*e.Number] = true
1520 }
1521 g.Out()
1522 g.P("}")
1523 g.P()
1524 g.P("var ", ccTypeName, "_value = map[string]int32{")
1525 g.In()
1526 for _, e := range enum.Value {
1527 g.P(strconv.Quote(*e.Name), ": ", e.Number, ",")
1528 }
1529 g.Out()
1530 g.P("}")
1531 g.P()
1532
1533 if !enum.proto3() {
1534 g.P("func (x ", ccTypeName, ") Enum() *", ccTypeName, " {")
1535 g.In()
1536 g.P("p := new(", ccTypeName, ")")
1537 g.P("*p = x")
1538 g.P("return p")
1539 g.Out()
1540 g.P("}")
1541 g.P()
1542 }
1543
1544 if gogoproto.IsGoEnumStringer(g.file.FileDescriptorProto, enum.EnumDescriptorProto) {
1545 g.P("func (x ", ccTypeName, ") String() string {")
1546 g.In()
1547 g.P("return ", g.Pkg["proto"], ".EnumName(", ccTypeName, "_name, int32(x))")
1548 g.Out()
1549 g.P("}")
1550 g.P()
1551 }
1552
1553 if !enum.proto3() && !gogoproto.IsGoEnumStringer(g.file.FileDescriptorProto, enum.EnumDescriptorProto) {
1554 g.P("func (x ", ccTypeName, ") MarshalJSON() ([]byte, error) {")
1555 g.In()
1556 g.P("return ", g.Pkg["proto"], ".MarshalJSONEnum(", ccTypeName, "_name, int32(x))")
1557 g.Out()
1558 g.P("}")
1559 g.P()
1560 }
1561 if !enum.proto3() {
1562 g.P("func (x *", ccTypeName, ") UnmarshalJSON(data []byte) error {")
1563 g.In()
1564 g.P("value, err := ", g.Pkg["proto"], ".UnmarshalJSONEnum(", ccTypeName, `_value, data, "`, ccTypeName, `")`)
1565 g.P("if err != nil {")
1566 g.In()
1567 g.P("return err")
1568 g.Out()
1569 g.P("}")
1570 g.P("*x = ", ccTypeName, "(value)")
1571 g.P("return nil")
1572 g.Out()
1573 g.P("}")
1574 g.P()
1575 }
1576
1577 var indexes []string
1578 for m := enum.parent; m != nil; m = m.parent {
1579
1580 indexes = append([]string{strconv.Itoa(m.index)}, indexes...)
1581 }
1582 indexes = append(indexes, strconv.Itoa(enum.index))
1583 g.P("func (", ccTypeName, ") EnumDescriptor() ([]byte, []int) {")
1584 g.In()
1585 g.P("return ", g.file.VarName(), ", []int{", strings.Join(indexes, ", "), "}")
1586 g.Out()
1587 g.P("}")
1588 g.P()
1589 if enum.file.GetPackage() == "google.protobuf" && enum.GetName() == "NullValue" {
1590 g.P("func (", ccTypeName, `) XXX_WellKnownType() string { return "`, enum.GetName(), `" }`)
1591 g.P()
1592 }
1593
1594 g.generateEnumRegistration(enum)
1595 }
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610 func (g *Generator) goTag(message *Descriptor, field *descriptor.FieldDescriptorProto, wiretype string) string {
1611 optrepreq := ""
1612 switch {
1613 case isOptional(field):
1614 optrepreq = "opt"
1615 case isRequired(field):
1616 optrepreq = "req"
1617 case isRepeated(field):
1618 optrepreq = "rep"
1619 }
1620 var defaultValue string
1621 if dv := field.DefaultValue; dv != nil {
1622 defaultValue = *dv
1623
1624 switch *field.Type {
1625 case descriptor.FieldDescriptorProto_TYPE_BOOL:
1626 if defaultValue == "true" {
1627 defaultValue = "1"
1628 } else {
1629 defaultValue = "0"
1630 }
1631 case descriptor.FieldDescriptorProto_TYPE_STRING,
1632 descriptor.FieldDescriptorProto_TYPE_BYTES:
1633
1634 case descriptor.FieldDescriptorProto_TYPE_ENUM:
1635
1636 obj := g.ObjectNamed(field.GetTypeName())
1637 if id, ok := obj.(*ImportedDescriptor); ok {
1638
1639
1640 obj = id.o
1641 }
1642 enum, ok := obj.(*EnumDescriptor)
1643 if !ok {
1644 log.Printf("obj is a %T", obj)
1645 if id, ok := obj.(*ImportedDescriptor); ok {
1646 log.Printf("id.o is a %T", id.o)
1647 }
1648 g.Fail("unknown enum type", CamelCaseSlice(obj.TypeName()))
1649 }
1650 defaultValue = enum.integerValueAsString(defaultValue)
1651 case descriptor.FieldDescriptorProto_TYPE_FLOAT:
1652 if def := defaultValue; def != "inf" && def != "-inf" && def != "nan" {
1653 if f, err := strconv.ParseFloat(defaultValue, 32); err == nil {
1654 defaultValue = fmt.Sprint(float32(f))
1655 }
1656 }
1657 case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
1658 if def := defaultValue; def != "inf" && def != "-inf" && def != "nan" {
1659 if f, err := strconv.ParseFloat(defaultValue, 64); err == nil {
1660 defaultValue = fmt.Sprint(f)
1661 }
1662 }
1663 }
1664 defaultValue = ",def=" + defaultValue
1665 }
1666 enum := ""
1667 if *field.Type == descriptor.FieldDescriptorProto_TYPE_ENUM {
1668
1669
1670 obj := g.ObjectNamed(field.GetTypeName())
1671 if id, ok := obj.(*ImportedDescriptor); ok {
1672 obj = id.o
1673 }
1674 enum = ",enum="
1675 if pkg := obj.File().GetPackage(); pkg != "" {
1676 enum += pkg + "."
1677 }
1678 enum += CamelCaseSlice(obj.TypeName())
1679 }
1680 packed := ""
1681 if (field.Options != nil && field.Options.GetPacked()) ||
1682
1683
1684 (message.proto3() && (field.Options == nil || field.Options.Packed == nil) &&
1685 isRepeated(field) && IsScalar(field)) {
1686 packed = ",packed"
1687 }
1688 fieldName := field.GetName()
1689 name := fieldName
1690 if *field.Type == descriptor.FieldDescriptorProto_TYPE_GROUP {
1691
1692
1693
1694
1695 name = *field.TypeName
1696 if i := strings.LastIndex(name, "."); i >= 0 {
1697 name = name[i+1:]
1698 }
1699 }
1700 if json := field.GetJsonName(); field.Extendee == nil && json != "" && json != name {
1701
1702
1703 name += ",json=" + json
1704 }
1705 name = ",name=" + name
1706
1707 embed := ""
1708 if gogoproto.IsEmbed(field) {
1709 embed = ",embedded=" + fieldName
1710 }
1711
1712 ctype := ""
1713 if gogoproto.IsCustomType(field) {
1714 ctype = ",customtype=" + gogoproto.GetCustomType(field)
1715 }
1716
1717 casttype := ""
1718 if gogoproto.IsCastType(field) {
1719 casttype = ",casttype=" + gogoproto.GetCastType(field)
1720 }
1721
1722 castkey := ""
1723 if gogoproto.IsCastKey(field) {
1724 castkey = ",castkey=" + gogoproto.GetCastKey(field)
1725 }
1726
1727 castvalue := ""
1728 if gogoproto.IsCastValue(field) {
1729 castvalue = ",castvalue=" + gogoproto.GetCastValue(field)
1730
1731 desc := g.ObjectNamed(field.GetTypeName())
1732 if d, ok := desc.(*Descriptor); ok && d.GetOptions().GetMapEntry() {
1733 valueField := d.Field[1]
1734 if valueField.IsMessage() {
1735 castvalue += ",castvaluetype=" + strings.TrimPrefix(valueField.GetTypeName(), ".")
1736 }
1737 }
1738 }
1739
1740 if message.proto3() {
1741 name += ",proto3"
1742 }
1743 oneof := ""
1744 if field.OneofIndex != nil {
1745 oneof = ",oneof"
1746 }
1747 stdtime := ""
1748 if gogoproto.IsStdTime(field) {
1749 stdtime = ",stdtime"
1750 }
1751 stdduration := ""
1752 if gogoproto.IsStdDuration(field) {
1753 stdduration = ",stdduration"
1754 }
1755 wktptr := ""
1756 if gogoproto.IsWktPtr(field) {
1757 wktptr = ",wktptr"
1758 }
1759 return strconv.Quote(fmt.Sprintf("%s,%d,%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
1760 wiretype,
1761 field.GetNumber(),
1762 optrepreq,
1763 packed,
1764 name,
1765 enum,
1766 oneof,
1767 defaultValue,
1768 embed,
1769 ctype,
1770 casttype,
1771 castkey,
1772 castvalue,
1773 stdtime,
1774 stdduration,
1775 wktptr))
1776 }
1777
1778 func needsStar(field *descriptor.FieldDescriptorProto, proto3 bool, allowOneOf bool) bool {
1779 if isRepeated(field) &&
1780 (*field.Type != descriptor.FieldDescriptorProto_TYPE_MESSAGE || gogoproto.IsCustomType(field)) &&
1781 (*field.Type != descriptor.FieldDescriptorProto_TYPE_GROUP) {
1782 return false
1783 }
1784 if *field.Type == descriptor.FieldDescriptorProto_TYPE_BYTES && !gogoproto.IsCustomType(field) {
1785 return false
1786 }
1787 if !gogoproto.IsNullable(field) {
1788 return false
1789 }
1790 if field.OneofIndex != nil && allowOneOf &&
1791 (*field.Type != descriptor.FieldDescriptorProto_TYPE_MESSAGE) &&
1792 (*field.Type != descriptor.FieldDescriptorProto_TYPE_GROUP) {
1793 return false
1794 }
1795 if proto3 &&
1796 (*field.Type != descriptor.FieldDescriptorProto_TYPE_MESSAGE) &&
1797 (*field.Type != descriptor.FieldDescriptorProto_TYPE_GROUP) &&
1798 !gogoproto.IsCustomType(field) {
1799 return false
1800 }
1801 return true
1802 }
1803
1804
1805
1806
1807
1808
1809 func (g *Generator) TypeName(obj Object) string {
1810 return g.DefaultPackageName(obj) + CamelCaseSlice(obj.TypeName())
1811 }
1812
1813
1814 func (g *Generator) GoType(message *Descriptor, field *descriptor.FieldDescriptorProto) (typ string, wire string) {
1815
1816 switch *field.Type {
1817 case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
1818 typ, wire = "float64", "fixed64"
1819 case descriptor.FieldDescriptorProto_TYPE_FLOAT:
1820 typ, wire = "float32", "fixed32"
1821 case descriptor.FieldDescriptorProto_TYPE_INT64:
1822 typ, wire = "int64", "varint"
1823 case descriptor.FieldDescriptorProto_TYPE_UINT64:
1824 typ, wire = "uint64", "varint"
1825 case descriptor.FieldDescriptorProto_TYPE_INT32:
1826 typ, wire = "int32", "varint"
1827 case descriptor.FieldDescriptorProto_TYPE_UINT32:
1828 typ, wire = "uint32", "varint"
1829 case descriptor.FieldDescriptorProto_TYPE_FIXED64:
1830 typ, wire = "uint64", "fixed64"
1831 case descriptor.FieldDescriptorProto_TYPE_FIXED32:
1832 typ, wire = "uint32", "fixed32"
1833 case descriptor.FieldDescriptorProto_TYPE_BOOL:
1834 typ, wire = "bool", "varint"
1835 case descriptor.FieldDescriptorProto_TYPE_STRING:
1836 typ, wire = "string", "bytes"
1837 case descriptor.FieldDescriptorProto_TYPE_GROUP:
1838 desc := g.ObjectNamed(field.GetTypeName())
1839 typ, wire = g.TypeName(desc), "group"
1840 case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
1841 desc := g.ObjectNamed(field.GetTypeName())
1842 typ, wire = g.TypeName(desc), "bytes"
1843 case descriptor.FieldDescriptorProto_TYPE_BYTES:
1844 typ, wire = "[]byte", "bytes"
1845 case descriptor.FieldDescriptorProto_TYPE_ENUM:
1846 desc := g.ObjectNamed(field.GetTypeName())
1847 typ, wire = g.TypeName(desc), "varint"
1848 case descriptor.FieldDescriptorProto_TYPE_SFIXED32:
1849 typ, wire = "int32", "fixed32"
1850 case descriptor.FieldDescriptorProto_TYPE_SFIXED64:
1851 typ, wire = "int64", "fixed64"
1852 case descriptor.FieldDescriptorProto_TYPE_SINT32:
1853 typ, wire = "int32", "zigzag32"
1854 case descriptor.FieldDescriptorProto_TYPE_SINT64:
1855 typ, wire = "int64", "zigzag64"
1856 default:
1857 g.Fail("unknown type for", field.GetName())
1858 }
1859 switch {
1860 case gogoproto.IsCustomType(field) && gogoproto.IsCastType(field):
1861 g.Fail(field.GetName() + " cannot be custom type and cast type")
1862 case gogoproto.IsCustomType(field):
1863 var packageName string
1864 var err error
1865 packageName, typ, err = getCustomType(field)
1866 if err != nil {
1867 g.Fail(err.Error())
1868 }
1869 if len(packageName) > 0 {
1870 g.customImports = append(g.customImports, packageName)
1871 }
1872 case gogoproto.IsCastType(field):
1873 var packageName string
1874 var err error
1875 packageName, typ, err = getCastType(field)
1876 if err != nil {
1877 g.Fail(err.Error())
1878 }
1879 if len(packageName) > 0 {
1880 g.customImports = append(g.customImports, packageName)
1881 }
1882 case gogoproto.IsStdTime(field):
1883 g.customImports = append(g.customImports, "time")
1884 typ = "time.Time"
1885 case gogoproto.IsStdDuration(field):
1886 g.customImports = append(g.customImports, "time")
1887 typ = "time.Duration"
1888 case gogoproto.IsStdDouble(field):
1889 typ = "float64"
1890 case gogoproto.IsStdFloat(field):
1891 typ = "float32"
1892 case gogoproto.IsStdInt64(field):
1893 typ = "int64"
1894 case gogoproto.IsStdUInt64(field):
1895 typ = "uint64"
1896 case gogoproto.IsStdInt32(field):
1897 typ = "int32"
1898 case gogoproto.IsStdUInt32(field):
1899 typ = "uint32"
1900 case gogoproto.IsStdBool(field):
1901 typ = "bool"
1902 case gogoproto.IsStdString(field):
1903 typ = "string"
1904 case gogoproto.IsStdBytes(field):
1905 typ = "[]byte"
1906 }
1907 if needsStar(field, g.file.proto3 && field.Extendee == nil, message != nil && message.allowOneof()) {
1908 typ = "*" + typ
1909 }
1910 if isRepeated(field) {
1911 typ = "[]" + typ
1912 }
1913 return
1914 }
1915
1916
1917 type GoMapDescriptor struct {
1918 GoType string
1919
1920 KeyField *descriptor.FieldDescriptorProto
1921 KeyAliasField *descriptor.FieldDescriptorProto
1922 KeyTag string
1923
1924 ValueField *descriptor.FieldDescriptorProto
1925 ValueAliasField *descriptor.FieldDescriptorProto
1926 ValueTag string
1927 }
1928
1929 func (g *Generator) GoMapType(d *Descriptor, field *descriptor.FieldDescriptorProto) *GoMapDescriptor {
1930 if d == nil {
1931 byName := g.ObjectNamed(field.GetTypeName())
1932 desc, ok := byName.(*Descriptor)
1933 if byName == nil || !ok || !desc.GetOptions().GetMapEntry() {
1934 g.Fail(fmt.Sprintf("field %s is not a map", field.GetTypeName()))
1935 return nil
1936 }
1937 d = desc
1938 }
1939
1940 m := &GoMapDescriptor{
1941 KeyField: d.Field[0],
1942 ValueField: d.Field[1],
1943 }
1944
1945
1946 m.KeyAliasField, m.ValueAliasField = g.GetMapKeyField(field, m.KeyField), g.GetMapValueField(field, m.ValueField)
1947 keyType, keyWire := g.GoType(d, m.KeyAliasField)
1948 valType, valWire := g.GoType(d, m.ValueAliasField)
1949
1950 m.KeyTag, m.ValueTag = g.goTag(d, m.KeyField, keyWire), g.goTag(d, m.ValueField, valWire)
1951
1952 if gogoproto.IsCastType(field) {
1953 var packageName string
1954 var err error
1955 packageName, typ, err := getCastType(field)
1956 if err != nil {
1957 g.Fail(err.Error())
1958 }
1959 if len(packageName) > 0 {
1960 g.customImports = append(g.customImports, packageName)
1961 }
1962 m.GoType = typ
1963 return m
1964 }
1965
1966
1967
1968
1969 keyType = strings.TrimPrefix(keyType, "*")
1970 switch *m.ValueAliasField.Type {
1971 case descriptor.FieldDescriptorProto_TYPE_ENUM:
1972 valType = strings.TrimPrefix(valType, "*")
1973 g.RecordTypeUse(m.ValueAliasField.GetTypeName())
1974 case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
1975 if !gogoproto.IsNullable(m.ValueAliasField) {
1976 valType = strings.TrimPrefix(valType, "*")
1977 }
1978 if !gogoproto.IsStdType(m.ValueAliasField) && !gogoproto.IsCustomType(field) && !gogoproto.IsCastType(field) {
1979 g.RecordTypeUse(m.ValueAliasField.GetTypeName())
1980 }
1981 default:
1982 if gogoproto.IsCustomType(m.ValueAliasField) {
1983 if !gogoproto.IsNullable(m.ValueAliasField) {
1984 valType = strings.TrimPrefix(valType, "*")
1985 }
1986 if !gogoproto.IsStdType(field) {
1987 g.RecordTypeUse(m.ValueAliasField.GetTypeName())
1988 }
1989 } else {
1990 valType = strings.TrimPrefix(valType, "*")
1991 }
1992 }
1993
1994 m.GoType = fmt.Sprintf("map[%s]%s", keyType, valType)
1995 return m
1996 }
1997
1998 func (g *Generator) RecordTypeUse(t string) {
1999 if _, ok := g.typeNameToObject[t]; !ok {
2000 return
2001 }
2002 importPath := g.ObjectNamed(t).GoImportPath()
2003 if importPath == g.outputImportPath {
2004
2005 return
2006 }
2007 g.AddImport(importPath)
2008 g.usedPackages[importPath] = true
2009 }
2010
2011
2012
2013
2014 var methodNames = [...]string{
2015 "Reset",
2016 "String",
2017 "ProtoMessage",
2018 "Marshal",
2019 "Unmarshal",
2020 "ExtensionRangeArray",
2021 "ExtensionMap",
2022 "Descriptor",
2023 "MarshalTo",
2024 "Equal",
2025 "VerboseEqual",
2026 "GoString",
2027 "ProtoSize",
2028 }
2029
2030
2031
2032 var wellKnownTypes = map[string]bool{
2033 "Any": true,
2034 "Duration": true,
2035 "Empty": true,
2036 "Struct": true,
2037 "Timestamp": true,
2038
2039 "Value": true,
2040 "ListValue": true,
2041 "DoubleValue": true,
2042 "FloatValue": true,
2043 "Int64Value": true,
2044 "UInt64Value": true,
2045 "Int32Value": true,
2046 "UInt32Value": true,
2047 "BoolValue": true,
2048 "StringValue": true,
2049 "BytesValue": true,
2050 }
2051
2052
2053
2054 func (g *Generator) getterDefault(field *descriptor.FieldDescriptorProto, goMessageType, goTypeName string) string {
2055 if isRepeated(field) {
2056 return "nil"
2057 }
2058 if def := field.GetDefaultValue(); def != "" {
2059 defaultConstant := g.defaultConstantName(goMessageType, field.GetName())
2060 if *field.Type != descriptor.FieldDescriptorProto_TYPE_BYTES {
2061 return defaultConstant
2062 }
2063 return "append([]byte(nil), " + defaultConstant + "...)"
2064 }
2065 switch *field.Type {
2066 case descriptor.FieldDescriptorProto_TYPE_GROUP,
2067 descriptor.FieldDescriptorProto_TYPE_MESSAGE:
2068 if field.OneofIndex != nil {
2069 return "nil"
2070 } else {
2071 if !gogoproto.IsNullable(field) && (gogoproto.IsStdDuration(field) ||
2072 gogoproto.IsStdDouble(field) || gogoproto.IsStdFloat(field) ||
2073 gogoproto.IsStdInt64(field) || gogoproto.IsStdUInt64(field) ||
2074 gogoproto.IsStdInt32(field) || gogoproto.IsStdUInt32(field)) {
2075 return "0"
2076 } else if !gogoproto.IsNullable(field) && gogoproto.IsStdBool(field) {
2077 return "false"
2078 } else if !gogoproto.IsNullable(field) && gogoproto.IsStdString(field) {
2079 return "\"\""
2080 } else if !gogoproto.IsNullable(field) && gogoproto.IsStdBytes(field) {
2081 return "[]byte{}"
2082 } else {
2083 return goTypeName + "{}"
2084 }
2085 }
2086 case descriptor.FieldDescriptorProto_TYPE_BOOL:
2087 return "false"
2088 case descriptor.FieldDescriptorProto_TYPE_STRING:
2089 return "\"\""
2090 case descriptor.FieldDescriptorProto_TYPE_BYTES:
2091
2092 return "nil"
2093 case descriptor.FieldDescriptorProto_TYPE_ENUM:
2094
2095
2096 obj := g.ObjectNamed(field.GetTypeName())
2097 var enum *EnumDescriptor
2098 if id, ok := obj.(*ImportedDescriptor); ok {
2099
2100 enum, _ = id.o.(*EnumDescriptor)
2101 } else {
2102 enum, _ = obj.(*EnumDescriptor)
2103 }
2104 if enum == nil {
2105 log.Printf("don't know how to generate getter for %s", field.GetName())
2106 return "nil"
2107 }
2108 if len(enum.Value) == 0 {
2109 return "0 // empty enum"
2110 } else {
2111 first := enum.Value[0].GetName()
2112 if gogoproto.IsEnumValueCustomName(enum.Value[0]) {
2113 first = gogoproto.GetEnumValueCustomName(enum.Value[0])
2114 }
2115 if gogoproto.EnabledGoEnumPrefix(enum.file.FileDescriptorProto, enum.EnumDescriptorProto) {
2116 return g.DefaultPackageName(obj) + enum.prefix() + first
2117 } else {
2118 return g.DefaultPackageName(obj) + first
2119 }
2120 }
2121 default:
2122 return "0"
2123 }
2124 }
2125
2126
2127
2128 func (g *Generator) defaultConstantName(goMessageType, protoFieldName string) string {
2129 return "Default_" + goMessageType + "_" + CamelCase(protoFieldName)
2130 }
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145 type msgCtx struct {
2146 goName string
2147 message *Descriptor
2148 }
2149
2150
2151 type fieldCommon struct {
2152 goName string
2153 protoName string
2154 getterName string
2155 goType string
2156 tags string
2157 fullPath string
2158 protoField *descriptor.FieldDescriptorProto
2159 }
2160
2161
2162 func (f *fieldCommon) getProtoName() string {
2163 return f.protoName
2164 }
2165
2166
2167 func (f *fieldCommon) getGoType() string {
2168 return f.goType
2169 }
2170
2171
2172 type simpleField struct {
2173 fieldCommon
2174 protoTypeName string
2175 protoType descriptor.FieldDescriptorProto_Type
2176 deprecated string
2177 getterDef string
2178 protoDef string
2179 comment string
2180 }
2181
2182
2183 func (f *simpleField) decl(g *Generator, mc *msgCtx) {
2184 g.P(f.comment, Annotate(mc.message.file, f.fullPath, f.goName), "\t", f.goType, "\t`", f.tags, "`", f.deprecated)
2185 }
2186
2187
2188 func (f *simpleField) getter(g *Generator, mc *msgCtx) {
2189 oneof := false
2190 if !oneof && !gogoproto.HasGoGetters(g.file.FileDescriptorProto, mc.message.DescriptorProto) {
2191 return
2192 }
2193 if gogoproto.IsEmbed(f.protoField) || gogoproto.IsCustomType(f.protoField) {
2194 return
2195 }
2196 if f.deprecated != "" {
2197 g.P(f.deprecated)
2198 }
2199 g.generateGet(mc, f.protoField, f.protoType, false, f.goName, f.goType, "", "", f.fullPath, f.getterName, f.getterDef)
2200 }
2201
2202
2203 func (f *simpleField) setter(g *Generator, mc *msgCtx) {
2204
2205 }
2206
2207
2208 func (f *simpleField) getProtoDef() string {
2209 return f.protoDef
2210 }
2211
2212
2213 func (f *simpleField) getProtoTypeName() string {
2214 return f.protoTypeName
2215 }
2216
2217
2218 func (f *simpleField) getProtoType() descriptor.FieldDescriptorProto_Type {
2219 return f.protoType
2220 }
2221
2222 func (f *simpleField) getProto() *descriptor.FieldDescriptorProto {
2223 return f.protoField
2224 }
2225
2226
2227 type oneofSubField struct {
2228 fieldCommon
2229 protoTypeName string
2230 protoType descriptor.FieldDescriptorProto_Type
2231 oneofTypeName string
2232 fieldNumber int
2233 getterDef string
2234 protoDef string
2235 deprecated string
2236 }
2237
2238
2239
2240 func (f *oneofSubField) typedNil(g *Generator) {
2241 g.P("(*", f.oneofTypeName, ")(nil),")
2242 }
2243
2244
2245 func (f *oneofSubField) getProtoDef() string {
2246 return f.protoDef
2247 }
2248
2249
2250 func (f *oneofSubField) getProtoTypeName() string {
2251 return f.protoTypeName
2252 }
2253
2254
2255 func (f *oneofSubField) getProtoType() descriptor.FieldDescriptorProto_Type {
2256 return f.protoType
2257 }
2258
2259 func (f *oneofSubField) getProto() *descriptor.FieldDescriptorProto {
2260 return f.protoField
2261 }
2262
2263
2264
2265 type oneofField struct {
2266 fieldCommon
2267 subFields []*oneofSubField
2268 comment string
2269 }
2270
2271
2272 func (f *oneofField) decl(g *Generator, mc *msgCtx) {
2273 comment := f.comment
2274 for _, sf := range f.subFields {
2275 comment += "//\t*" + sf.oneofTypeName + "\n"
2276 }
2277 g.P(comment, Annotate(mc.message.file, f.fullPath, f.goName), " ", f.goType, " `", f.tags, "`")
2278 }
2279
2280
2281
2282 func (f *oneofField) getter(g *Generator, mc *msgCtx) {
2283 oneof := true
2284 if !oneof && !gogoproto.HasGoGetters(g.file.FileDescriptorProto, mc.message.DescriptorProto) {
2285 return
2286 }
2287
2288 for _, sf := range f.subFields {
2289 if gogoproto.IsEmbed(sf.protoField) || gogoproto.IsCustomType(sf.protoField) {
2290 continue
2291 }
2292 if sf.deprecated != "" {
2293 g.P(sf.deprecated)
2294 }
2295 g.generateGet(mc, sf.protoField, sf.protoType, true, sf.goName, sf.goType, f.goName, sf.oneofTypeName, sf.fullPath, sf.getterName, sf.getterDef)
2296 }
2297 }
2298
2299
2300 func (f *oneofField) setter(g *Generator, mc *msgCtx) {
2301
2302 }
2303
2304
2305 type topLevelField interface {
2306 decl(g *Generator, mc *msgCtx)
2307 getter(g *Generator, mc *msgCtx)
2308 setter(g *Generator, mc *msgCtx)
2309 }
2310
2311
2312 type defField interface {
2313 getProtoDef() string
2314 getProtoName() string
2315 getGoType() string
2316 getProtoTypeName() string
2317 getProtoType() descriptor.FieldDescriptorProto_Type
2318 getProto() *descriptor.FieldDescriptorProto
2319 }
2320
2321
2322
2323 func (g *Generator) generateDefaultConstants(mc *msgCtx, topLevelFields []topLevelField) {
2324
2325 dFields := []defField{}
2326 for _, pf := range topLevelFields {
2327 if f, ok := pf.(*oneofField); ok {
2328 for _, osf := range f.subFields {
2329 dFields = append(dFields, osf)
2330 }
2331 continue
2332 }
2333 dFields = append(dFields, pf.(defField))
2334 }
2335 for _, df := range dFields {
2336 def := df.getProtoDef()
2337 if def == "" {
2338 continue
2339 }
2340 if !gogoproto.IsNullable(df.getProto()) {
2341 g.Fail("illegal default value: ", df.getProtoName(), " in ", mc.message.GetName(), " is not nullable and is thus not allowed to have a default value")
2342 }
2343 fieldname := g.defaultConstantName(mc.goName, df.getProtoName())
2344 typename := df.getGoType()
2345 if typename[0] == '*' {
2346 typename = typename[1:]
2347 }
2348 kind := "const "
2349 switch {
2350 case typename == "bool":
2351 case typename == "string":
2352 def = strconv.Quote(def)
2353 case typename == "[]byte":
2354 def = "[]byte(" + strconv.Quote(unescape(def)) + ")"
2355 kind = "var "
2356 case def == "inf", def == "-inf", def == "nan":
2357
2358 switch def {
2359 case "inf":
2360 def = "math.Inf(1)"
2361 case "-inf":
2362 def = "math.Inf(-1)"
2363 case "nan":
2364 def = "math.NaN()"
2365 }
2366 if df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_FLOAT {
2367 def = "float32(" + def + ")"
2368 }
2369 kind = "var "
2370 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_FLOAT:
2371 if f, err := strconv.ParseFloat(def, 32); err == nil {
2372 def = fmt.Sprint(float32(f))
2373 }
2374 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_DOUBLE:
2375 if f, err := strconv.ParseFloat(def, 64); err == nil {
2376 def = fmt.Sprint(f)
2377 }
2378 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_ENUM:
2379
2380 obj := g.ObjectNamed(df.getProtoTypeName())
2381 var enum *EnumDescriptor
2382 if id, ok := obj.(*ImportedDescriptor); ok {
2383
2384 enum, _ = id.o.(*EnumDescriptor)
2385 } else {
2386 enum, _ = obj.(*EnumDescriptor)
2387 }
2388 if enum == nil {
2389 log.Printf("don't know how to generate constant for %s", fieldname)
2390 continue
2391 }
2392
2393
2394 var enumValue *descriptor.EnumValueDescriptorProto
2395 for _, ev := range enum.Value {
2396 if def == ev.GetName() {
2397 enumValue = ev
2398 }
2399 }
2400
2401 if enumValue != nil {
2402 if gogoproto.IsEnumValueCustomName(enumValue) {
2403 def = gogoproto.GetEnumValueCustomName(enumValue)
2404 }
2405 } else {
2406 g.Fail(fmt.Sprintf("could not resolve default enum value for %v.%v", g.DefaultPackageName(obj), def))
2407 }
2408
2409 if gogoproto.EnabledGoEnumPrefix(enum.file.FileDescriptorProto, enum.EnumDescriptorProto) {
2410 def = g.DefaultPackageName(obj) + enum.prefix() + def
2411 } else {
2412 def = g.DefaultPackageName(obj) + def
2413 }
2414 }
2415 g.P(kind, fieldname, " ", typename, " = ", def)
2416 g.file.addExport(mc.message, constOrVarSymbol{fieldname, kind, ""})
2417 }
2418 g.P()
2419 }
2420
2421
2422
2423
2424 func (g *Generator) generateGet(mc *msgCtx, protoField *descriptor.FieldDescriptorProto, protoType descriptor.FieldDescriptorProto_Type,
2425 oneof bool, fname, tname, uname, oneoftname, fullpath, gname, def string) {
2426 star := ""
2427 if (protoType != descriptor.FieldDescriptorProto_TYPE_MESSAGE) &&
2428 (protoType != descriptor.FieldDescriptorProto_TYPE_GROUP) &&
2429 needsStar(protoField, g.file.proto3, mc.message != nil && mc.message.allowOneof()) && tname[0] == '*' {
2430 tname = tname[1:]
2431 star = "*"
2432 }
2433 typeDefaultIsNil := false
2434 switch protoType {
2435 case descriptor.FieldDescriptorProto_TYPE_BYTES:
2436 typeDefaultIsNil = def == "nil"
2437 case descriptor.FieldDescriptorProto_TYPE_GROUP, descriptor.FieldDescriptorProto_TYPE_MESSAGE:
2438 typeDefaultIsNil = gogoproto.IsNullable(protoField)
2439 }
2440 if isRepeated(protoField) {
2441 typeDefaultIsNil = true
2442 }
2443 g.P("func (m *", mc.goName, ") ", Annotate(mc.message.file, fullpath, gname), "() "+tname+" {")
2444 if !oneof && typeDefaultIsNil {
2445
2446
2447 g.P("if m != nil {")
2448 g.In()
2449 g.P("return m." + fname)
2450 g.Out()
2451 g.P("}")
2452 g.P("return nil")
2453 g.Out()
2454 g.P("}")
2455 g.P()
2456 return
2457 }
2458 if !gogoproto.IsNullable(protoField) {
2459 g.P("if m != nil {")
2460 g.In()
2461 g.P("return m." + fname)
2462 g.Out()
2463 g.P("}")
2464 } else if !oneof {
2465 if mc.message.proto3() {
2466 g.P("if m != nil {")
2467 } else {
2468 g.P("if m != nil && m." + fname + " != nil {")
2469 }
2470 g.In()
2471 g.P("return " + star + "m." + fname)
2472 g.Out()
2473 g.P("}")
2474 } else {
2475 uname := uname
2476 tname := oneoftname
2477 g.P("if x, ok := m.Get", uname, "().(*", tname, "); ok {")
2478 g.P("return x.", fname)
2479 g.P("}")
2480 }
2481 g.P("return ", def)
2482 g.Out()
2483 g.P("}")
2484 g.P()
2485 }
2486
2487
2488 func (g *Generator) generateInternalStructFields(mc *msgCtx, topLevelFields []topLevelField) {
2489 if gogoproto.HasUnkeyed(g.file.FileDescriptorProto, mc.message.DescriptorProto) {
2490 g.P("XXX_NoUnkeyedLiteral\tstruct{} `json:\"-\"`")
2491 }
2492 if len(mc.message.ExtensionRange) > 0 {
2493 if gogoproto.HasExtensionsMap(g.file.FileDescriptorProto, mc.message.DescriptorProto) {
2494 messageset := ""
2495 if opts := mc.message.Options; opts != nil && opts.GetMessageSetWireFormat() {
2496 messageset = "protobuf_messageset:\"1\" "
2497 }
2498 g.P(g.Pkg["proto"], ".XXX_InternalExtensions `", messageset, "json:\"-\"`")
2499 } else {
2500 g.P("XXX_extensions\t\t[]byte `protobuf:\"bytes,0,opt\" json:\"-\"`")
2501 }
2502 }
2503 if gogoproto.HasUnrecognized(g.file.FileDescriptorProto, mc.message.DescriptorProto) {
2504 g.P("XXX_unrecognized\t[]byte `json:\"-\"`")
2505 }
2506 if gogoproto.HasSizecache(g.file.FileDescriptorProto, mc.message.DescriptorProto) {
2507 g.P("XXX_sizecache\tint32 `json:\"-\"`")
2508 }
2509 }
2510
2511
2512 func (g *Generator) generateOneofFuncs(mc *msgCtx, topLevelFields []topLevelField) {
2513 ofields := []*oneofField{}
2514 for _, f := range topLevelFields {
2515 if o, ok := f.(*oneofField); ok {
2516 ofields = append(ofields, o)
2517 }
2518 }
2519 if len(ofields) == 0 {
2520 return
2521 }
2522
2523
2524 g.P("// XXX_OneofWrappers is for the internal use of the proto package.")
2525 g.P("func (*", mc.goName, ") XXX_OneofWrappers() []interface{} {")
2526 g.P("return []interface{}{")
2527 for _, of := range ofields {
2528 for _, sf := range of.subFields {
2529 sf.typedNil(g)
2530 }
2531 }
2532 g.P("}")
2533 g.P("}")
2534 g.P()
2535 }
2536
2537 func (g *Generator) generateOneofDecls(mc *msgCtx, topLevelFields []topLevelField) {
2538 ofields := []*oneofField{}
2539 for _, f := range topLevelFields {
2540 if o, ok := f.(*oneofField); ok {
2541 ofields = append(ofields, o)
2542 }
2543 }
2544 if len(ofields) == 0 {
2545 return
2546 }
2547
2548
2549
2550
2551
2552
2553 for _, of := range ofields {
2554 dname := of.goType
2555 g.P("type ", dname, " interface {")
2556 g.In()
2557 g.P(dname, "()")
2558 if gogoproto.HasEqual(g.file.FileDescriptorProto, mc.message.DescriptorProto) {
2559 g.P(`Equal(interface{}) bool`)
2560 }
2561 if gogoproto.HasVerboseEqual(g.file.FileDescriptorProto, mc.message.DescriptorProto) {
2562 g.P(`VerboseEqual(interface{}) error`)
2563 }
2564 if gogoproto.IsMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) ||
2565 gogoproto.IsUnsafeMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) ||
2566 gogoproto.IsStableMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) {
2567 g.P(`MarshalTo([]byte) (int, error)`)
2568 }
2569 if gogoproto.IsSizer(g.file.FileDescriptorProto, mc.message.DescriptorProto) {
2570 g.P(`Size() int`)
2571 }
2572 if gogoproto.IsProtoSizer(g.file.FileDescriptorProto, mc.message.DescriptorProto) {
2573 g.P(`ProtoSize() int`)
2574 }
2575 if gogoproto.HasCompare(g.file.FileDescriptorProto, mc.message.DescriptorProto) {
2576 g.P(`Compare(interface{}) int`)
2577 }
2578 g.Out()
2579 g.P("}")
2580 }
2581 g.P()
2582 for _, of := range ofields {
2583 for i, sf := range of.subFields {
2584 fieldFullPath := fmt.Sprintf("%s,%d,%d", mc.message.path, messageFieldPath, i)
2585 g.P("type ", Annotate(mc.message.file, fieldFullPath, sf.oneofTypeName), " struct{ ", Annotate(mc.message.file, fieldFullPath, sf.goName), " ", sf.goType, " `", sf.tags, "` }")
2586 if !gogoproto.IsStdType(sf.protoField) && !gogoproto.IsCustomType(sf.protoField) && !gogoproto.IsCastType(sf.protoField) {
2587 g.RecordTypeUse(sf.protoField.GetTypeName())
2588 }
2589 }
2590 }
2591 g.P()
2592 for _, of := range ofields {
2593 for _, sf := range of.subFields {
2594 g.P("func (*", sf.oneofTypeName, ") ", of.goType, "() {}")
2595 }
2596 }
2597 g.P()
2598 for _, of := range ofields {
2599 fname := of.goName
2600 g.P("func (m *", mc.goName, ") Get", fname, "() ", of.goType, " {")
2601 g.P("if m != nil { return m.", fname, " }")
2602 g.P("return nil")
2603 g.P("}")
2604 }
2605 g.P()
2606 }
2607
2608
2609 func (g *Generator) generateMessageStruct(mc *msgCtx, topLevelFields []topLevelField) {
2610 comments := g.PrintComments(mc.message.path)
2611
2612
2613 if mc.message.GetOptions().GetDeprecated() {
2614 if comments {
2615
2616
2617 g.P("//")
2618 }
2619 g.P(deprecationComment)
2620 }
2621 g.P("type ", Annotate(mc.message.file, mc.message.path, mc.goName), " struct {")
2622 for _, pf := range topLevelFields {
2623 pf.decl(g, mc)
2624 }
2625 g.generateInternalStructFields(mc, topLevelFields)
2626 g.P("}")
2627 }
2628
2629
2630 func (g *Generator) generateGetters(mc *msgCtx, topLevelFields []topLevelField) {
2631 for _, pf := range topLevelFields {
2632 pf.getter(g, mc)
2633
2634 }
2635 }
2636
2637
2638 func (g *Generator) generateSetters(mc *msgCtx, topLevelFields []topLevelField) {
2639 for _, pf := range topLevelFields {
2640 pf.setter(g, mc)
2641 }
2642 }
2643
2644
2645 func (g *Generator) generateCommonMethods(mc *msgCtx) {
2646
2647 g.P("func (m *", mc.goName, ") Reset() { *m = ", mc.goName, "{} }")
2648 if gogoproto.EnabledGoStringer(g.file.FileDescriptorProto, mc.message.DescriptorProto) {
2649 g.P("func (m *", mc.goName, ") String() string { return ", g.Pkg["proto"], ".CompactTextString(m) }")
2650 }
2651 g.P("func (*", mc.goName, ") ProtoMessage() {}")
2652 var indexes []string
2653 for m := mc.message; m != nil; m = m.parent {
2654 indexes = append([]string{strconv.Itoa(m.index)}, indexes...)
2655 }
2656 g.P("func (*", mc.goName, ") Descriptor() ([]byte, []int) {")
2657 g.P("return ", g.file.VarName(), ", []int{", strings.Join(indexes, ", "), "}")
2658 g.P("}")
2659
2660
2661 if mc.message.file.GetPackage() == "google.protobuf" && wellKnownTypes[mc.message.GetName()] {
2662 g.P("func (*", mc.goName, `) XXX_WellKnownType() string { return "`, mc.message.GetName(), `" }`)
2663 }
2664
2665
2666 if len(mc.message.ExtensionRange) > 0 {
2667 g.P()
2668 g.P("var extRange_", mc.goName, " = []", g.Pkg["proto"], ".ExtensionRange{")
2669 g.In()
2670 for _, r := range mc.message.ExtensionRange {
2671 end := fmt.Sprint(*r.End - 1)
2672 g.P("{Start: ", r.Start, ", End: ", end, "},")
2673 }
2674 g.Out()
2675 g.P("}")
2676 g.P("func (*", mc.goName, ") ExtensionRangeArray() []", g.Pkg["proto"], ".ExtensionRange {")
2677 g.In()
2678 g.P("return extRange_", mc.goName)
2679 g.Out()
2680 g.P("}")
2681 g.P()
2682 if !gogoproto.HasExtensionsMap(g.file.FileDescriptorProto, mc.message.DescriptorProto) {
2683 g.P("func (m *", mc.goName, ") GetExtensions() *[]byte {")
2684 g.In()
2685 g.P("if m.XXX_extensions == nil {")
2686 g.In()
2687 g.P("m.XXX_extensions = make([]byte, 0)")
2688 g.Out()
2689 g.P("}")
2690 g.P("return &m.XXX_extensions")
2691 g.Out()
2692 g.P("}")
2693 }
2694 }
2695
2696
2697
2698
2699
2700
2701
2702
2703 g.P("func (m *", mc.goName, ") XXX_Unmarshal(b []byte) error {")
2704 g.In()
2705 if gogoproto.IsUnmarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) {
2706 g.P("return m.Unmarshal(b)")
2707 } else {
2708 g.P("return xxx_messageInfo_", mc.goName, ".Unmarshal(m, b)")
2709 }
2710 g.Out()
2711 g.P("}")
2712
2713 g.P("func (m *", mc.goName, ") XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {")
2714 g.In()
2715 if gogoproto.IsMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) ||
2716 gogoproto.IsUnsafeMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) {
2717 if gogoproto.IsStableMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) {
2718 g.P("b = b[:cap(b)]")
2719 g.P("n, err := m.MarshalToSizedBuffer(b)")
2720 g.P("if err != nil {")
2721 g.In()
2722 g.P("return nil, err")
2723 g.Out()
2724 g.P("}")
2725 g.P("return b[:n], nil")
2726 } else {
2727 g.P("if deterministic {")
2728 g.In()
2729 g.P("return xxx_messageInfo_", mc.goName, ".Marshal(b, m, deterministic)")
2730 g.P("} else {")
2731 g.In()
2732 g.P("b = b[:cap(b)]")
2733 g.P("n, err := m.MarshalToSizedBuffer(b)")
2734 g.P("if err != nil {")
2735 g.In()
2736 g.P("return nil, err")
2737 g.Out()
2738 g.P("}")
2739 g.Out()
2740 g.P("return b[:n], nil")
2741 g.Out()
2742 g.P("}")
2743 }
2744 } else {
2745 g.P("return xxx_messageInfo_", mc.goName, ".Marshal(b, m, deterministic)")
2746 }
2747 g.Out()
2748 g.P("}")
2749
2750 g.P("func (m *", mc.goName, ") XXX_Merge(src ", g.Pkg["proto"], ".Message) {")
2751 g.In()
2752 g.P("xxx_messageInfo_", mc.goName, ".Merge(m, src)")
2753 g.Out()
2754 g.P("}")
2755
2756 g.P("func (m *", mc.goName, ") XXX_Size() int {")
2757 g.In()
2758 if (gogoproto.IsMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) ||
2759 gogoproto.IsUnsafeMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto)) &&
2760 gogoproto.IsSizer(g.file.FileDescriptorProto, mc.message.DescriptorProto) {
2761 g.P("return m.Size()")
2762 } else if (gogoproto.IsMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) ||
2763 gogoproto.IsUnsafeMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto)) &&
2764 gogoproto.IsProtoSizer(g.file.FileDescriptorProto, mc.message.DescriptorProto) {
2765 g.P("return m.ProtoSize()")
2766 } else {
2767 g.P("return xxx_messageInfo_", mc.goName, ".Size(m)")
2768 }
2769 g.Out()
2770 g.P("}")
2771
2772 g.P("func (m *", mc.goName, ") XXX_DiscardUnknown() {")
2773 g.In()
2774 g.P("xxx_messageInfo_", mc.goName, ".DiscardUnknown(m)")
2775 g.Out()
2776 g.P("}")
2777
2778 g.P("var xxx_messageInfo_", mc.goName, " ", g.Pkg["proto"], ".InternalMessageInfo")
2779 }
2780
2781
2782 func (g *Generator) generateMessage(message *Descriptor) {
2783 topLevelFields := []topLevelField{}
2784 oFields := make(map[int32]*oneofField)
2785
2786 typeName := message.TypeName()
2787
2788 goTypeName := CamelCaseSlice(typeName)
2789
2790 usedNames := make(map[string]bool)
2791 for _, n := range methodNames {
2792 usedNames[n] = true
2793 }
2794 if !gogoproto.IsProtoSizer(message.file.FileDescriptorProto, message.DescriptorProto) {
2795 usedNames["Size"] = true
2796 }
2797
2798
2799
2800
2801 allocNames := func(ns ...string) []string {
2802 Loop:
2803 for {
2804 for _, n := range ns {
2805 if usedNames[n] {
2806 for i := range ns {
2807 ns[i] += "_"
2808 }
2809 continue Loop
2810 }
2811 }
2812 for _, n := range ns {
2813 usedNames[n] = true
2814 }
2815 return ns
2816 }
2817 }
2818
2819 mapFieldTypes := make(map[*descriptor.FieldDescriptorProto]string)
2820
2821 for i, field := range message.Field {
2822
2823
2824
2825
2826
2827 base := CamelCase(*field.Name)
2828 if gogoproto.IsCustomName(field) {
2829 base = gogoproto.GetCustomName(field)
2830 }
2831 ns := allocNames(base, "Get"+base)
2832 fieldName, fieldGetterName := ns[0], ns[1]
2833
2834 typename, wiretype := g.GoType(message, field)
2835 jsonName := *field.Name
2836 jsonTag := jsonName + ",omitempty"
2837 repeatedNativeType := (!field.IsMessage() && !gogoproto.IsCustomType(field) && field.IsRepeated())
2838 if !gogoproto.IsNullable(field) && !repeatedNativeType {
2839 jsonTag = jsonName
2840 }
2841 gogoJsonTag := gogoproto.GetJsonTag(field)
2842 if gogoJsonTag != nil {
2843 jsonTag = *gogoJsonTag
2844 }
2845 gogoMoreTags := gogoproto.GetMoreTags(field)
2846 moreTags := ""
2847 if gogoMoreTags != nil {
2848 moreTags = " " + *gogoMoreTags
2849 }
2850 tag := fmt.Sprintf("protobuf:%s json:%q%s", g.goTag(message, field, wiretype), jsonTag, moreTags)
2851 if *field.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE && gogoproto.IsEmbed(field) {
2852 fieldName = ""
2853 }
2854
2855 oneof := field.OneofIndex != nil && message.allowOneof()
2856 if oneof && oFields[*field.OneofIndex] == nil {
2857 odp := message.OneofDecl[int(*field.OneofIndex)]
2858 base := CamelCase(odp.GetName())
2859 names := allocNames(base, "Get"+base)
2860 fname, gname := names[0], names[1]
2861
2862
2863
2864 oneofFullPath := fmt.Sprintf("%s,%d,%d", message.path, messageOneofPath, *field.OneofIndex)
2865 c, ok := g.makeComments(oneofFullPath)
2866 if ok {
2867 c += "\n//\n"
2868 }
2869 c += "// Types that are valid to be assigned to " + fname + ":\n"
2870
2871
2872
2873 dname := "is" + goTypeName + "_" + fname
2874 oneOftag := `protobuf_oneof:"` + odp.GetName() + `"`
2875 of := oneofField{
2876 fieldCommon: fieldCommon{
2877 goName: fname,
2878 getterName: gname,
2879 goType: dname,
2880 tags: oneOftag,
2881 protoName: odp.GetName(),
2882 fullPath: oneofFullPath,
2883 protoField: field,
2884 },
2885 comment: c,
2886 }
2887 topLevelFields = append(topLevelFields, &of)
2888 oFields[*field.OneofIndex] = &of
2889 }
2890
2891 if *field.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE {
2892 desc := g.ObjectNamed(field.GetTypeName())
2893 if d, ok := desc.(*Descriptor); ok && d.GetOptions().GetMapEntry() {
2894 m := g.GoMapType(d, field)
2895 typename = m.GoType
2896 mapFieldTypes[field] = typename
2897
2898 tag += fmt.Sprintf(" protobuf_key:%s protobuf_val:%s", m.KeyTag, m.ValueTag)
2899 }
2900 }
2901 goTyp, _ := g.GoType(message, field)
2902 fieldDeprecated := ""
2903 if field.GetOptions().GetDeprecated() {
2904 fieldDeprecated = deprecationComment
2905 }
2906 dvalue := g.getterDefault(field, goTypeName, GoTypeToName(goTyp))
2907 if oneof {
2908 tname := goTypeName + "_" + fieldName
2909
2910
2911 for {
2912 ok := true
2913 for _, desc := range message.nested {
2914 if CamelCaseSlice(desc.TypeName()) == tname {
2915 ok = false
2916 break
2917 }
2918 }
2919 for _, enum := range message.enums {
2920 if CamelCaseSlice(enum.TypeName()) == tname {
2921 ok = false
2922 break
2923 }
2924 }
2925 if !ok {
2926 tname += "_"
2927 continue
2928 }
2929 break
2930 }
2931
2932 oneofField := oFields[*field.OneofIndex]
2933 sf := oneofSubField{
2934 fieldCommon: fieldCommon{
2935 goName: fieldName,
2936 getterName: fieldGetterName,
2937 goType: typename,
2938 tags: tag,
2939 protoName: field.GetName(),
2940 fullPath: fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i),
2941 protoField: field,
2942 },
2943 protoTypeName: field.GetTypeName(),
2944 fieldNumber: int(*field.Number),
2945 protoType: *field.Type,
2946 getterDef: dvalue,
2947 protoDef: field.GetDefaultValue(),
2948 oneofTypeName: tname,
2949 deprecated: fieldDeprecated,
2950 }
2951
2952 oneofField.subFields = append(oneofField.subFields, &sf)
2953 if !gogoproto.IsStdType(field) && !gogoproto.IsCustomType(field) && !gogoproto.IsCastType(field) {
2954 g.RecordTypeUse(field.GetTypeName())
2955 }
2956 continue
2957 }
2958
2959 fieldFullPath := fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i)
2960 c, ok := g.makeComments(fieldFullPath)
2961 if ok {
2962 c += "\n"
2963 }
2964 rf := simpleField{
2965 fieldCommon: fieldCommon{
2966 goName: fieldName,
2967 getterName: fieldGetterName,
2968 goType: typename,
2969 tags: tag,
2970 protoName: field.GetName(),
2971 fullPath: fieldFullPath,
2972 protoField: field,
2973 },
2974 protoTypeName: field.GetTypeName(),
2975 protoType: *field.Type,
2976 deprecated: fieldDeprecated,
2977 getterDef: dvalue,
2978 protoDef: field.GetDefaultValue(),
2979 comment: c,
2980 }
2981 var pf topLevelField = &rf
2982
2983 topLevelFields = append(topLevelFields, pf)
2984
2985 if gogoproto.HasTypeDecl(message.file.FileDescriptorProto, message.DescriptorProto) {
2986 if !gogoproto.IsStdType(field) && !gogoproto.IsCustomType(field) && !gogoproto.IsCastType(field) {
2987 g.RecordTypeUse(field.GetTypeName())
2988 }
2989 } else {
2990
2991
2992
2993 for _, mfield := range message.Field {
2994 if !gogoproto.IsStdType(mfield) && !gogoproto.IsCustomType(mfield) && !gogoproto.IsCastType(mfield) {
2995 g.RecordTypeUse(mfield.GetTypeName())
2996 }
2997 }
2998 }
2999 }
3000
3001 mc := &msgCtx{
3002 goName: goTypeName,
3003 message: message,
3004 }
3005
3006 if gogoproto.HasTypeDecl(message.file.FileDescriptorProto, message.DescriptorProto) {
3007 g.generateMessageStruct(mc, topLevelFields)
3008 g.P()
3009 }
3010 g.generateCommonMethods(mc)
3011 g.P()
3012 g.generateDefaultConstants(mc, topLevelFields)
3013 g.P()
3014 g.generateOneofDecls(mc, topLevelFields)
3015 g.P()
3016 g.generateGetters(mc, topLevelFields)
3017 g.P()
3018 g.generateSetters(mc, topLevelFields)
3019 g.P()
3020 g.generateOneofFuncs(mc, topLevelFields)
3021 g.P()
3022
3023 var oneofTypes []string
3024 for _, f := range topLevelFields {
3025 if of, ok := f.(*oneofField); ok {
3026 for _, osf := range of.subFields {
3027 oneofTypes = append(oneofTypes, osf.oneofTypeName)
3028 }
3029 }
3030 }
3031
3032 opts := message.Options
3033 ms := &messageSymbol{
3034 sym: goTypeName,
3035 hasExtensions: len(message.ExtensionRange) > 0,
3036 isMessageSet: opts != nil && opts.GetMessageSetWireFormat(),
3037 oneofTypes: oneofTypes,
3038 }
3039 g.file.addExport(message, ms)
3040
3041 for _, ext := range message.ext {
3042 g.generateExtension(ext)
3043 }
3044
3045 fullName := strings.Join(message.TypeName(), ".")
3046 if g.file.Package != nil {
3047 fullName = *g.file.Package + "." + fullName
3048 }
3049
3050 g.addInitf("%s.RegisterType((*%s)(nil), %q)", g.Pkg["proto"], goTypeName, fullName)
3051 if gogoproto.ImportsGoGoProto(g.file.FileDescriptorProto) && gogoproto.RegistersGolangProto(g.file.FileDescriptorProto) {
3052 g.addInitf("%s.RegisterType((*%s)(nil), %q)", g.Pkg["golang_proto"], goTypeName, fullName)
3053 }
3054 if gogoproto.HasMessageName(g.file.FileDescriptorProto, message.DescriptorProto) {
3055 g.P("func (*", goTypeName, ") XXX_MessageName() string {")
3056 g.In()
3057 g.P("return ", strconv.Quote(fullName))
3058 g.Out()
3059 g.P("}")
3060 }
3061
3062 for _, k := range mapFieldKeys(mapFieldTypes) {
3063 fullName := strings.TrimPrefix(*k.TypeName, ".")
3064 g.addInitf("%s.RegisterMapType((%s)(nil), %q)", g.Pkg["proto"], mapFieldTypes[k], fullName)
3065 if gogoproto.ImportsGoGoProto(g.file.FileDescriptorProto) && gogoproto.RegistersGolangProto(g.file.FileDescriptorProto) {
3066 g.addInitf("%s.RegisterMapType((%s)(nil), %q)", g.Pkg["golang_proto"], mapFieldTypes[k], fullName)
3067 }
3068 }
3069 }
3070
3071 type byTypeName []*descriptor.FieldDescriptorProto
3072
3073 func (a byTypeName) Len() int { return len(a) }
3074 func (a byTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
3075 func (a byTypeName) Less(i, j int) bool { return *a[i].TypeName < *a[j].TypeName }
3076
3077
3078 func mapFieldKeys(m map[*descriptor.FieldDescriptorProto]string) []*descriptor.FieldDescriptorProto {
3079 keys := make([]*descriptor.FieldDescriptorProto, 0, len(m))
3080 for k := range m {
3081 keys = append(keys, k)
3082 }
3083 sort.Sort(byTypeName(keys))
3084 return keys
3085 }
3086
3087 var escapeChars = [256]byte{
3088 'a': '\a', 'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t', 'v': '\v', '\\': '\\', '"': '"', '\'': '\'', '?': '?',
3089 }
3090
3091
3092
3093
3094 func unescape(s string) string {
3095
3096
3097
3098
3099 var out []byte
3100 for len(s) > 0 {
3101
3102 if s[0] != '\\' || len(s) < 2 {
3103 out = append(out, s[0])
3104 s = s[1:]
3105 } else if c := escapeChars[s[1]]; c != 0 {
3106
3107 out = append(out, c)
3108 s = s[2:]
3109 } else if s[1] == 'x' || s[1] == 'X' {
3110
3111 if len(s) < 4 {
3112
3113 out = append(out, s[:2]...)
3114 s = s[2:]
3115 continue
3116 }
3117 v, err := strconv.ParseUint(s[2:4], 16, 8)
3118 if err != nil {
3119 out = append(out, s[:4]...)
3120 } else {
3121 out = append(out, byte(v))
3122 }
3123 s = s[4:]
3124 } else if '0' <= s[1] && s[1] <= '7' {
3125
3126
3127 n := len(s[1:]) - len(strings.TrimLeft(s[1:], "01234567"))
3128 if n > 3 {
3129 n = 3
3130 }
3131 v, err := strconv.ParseUint(s[1:1+n], 8, 8)
3132 if err != nil {
3133 out = append(out, s[:1+n]...)
3134 } else {
3135 out = append(out, byte(v))
3136 }
3137 s = s[1+n:]
3138 } else {
3139
3140 out = append(out, s[0])
3141 s = s[1:]
3142 }
3143 }
3144
3145 return string(out)
3146 }
3147
3148 func (g *Generator) generateExtension(ext *ExtensionDescriptor) {
3149 ccTypeName := ext.DescName()
3150
3151 extObj := g.ObjectNamed(*ext.Extendee)
3152 var extDesc *Descriptor
3153 if id, ok := extObj.(*ImportedDescriptor); ok {
3154
3155
3156 extDesc = id.o.(*Descriptor)
3157 } else {
3158 extDesc = extObj.(*Descriptor)
3159 }
3160 extendedType := "*" + g.TypeName(extObj)
3161 field := ext.FieldDescriptorProto
3162 fieldType, wireType := g.GoType(ext.parent, field)
3163 tag := g.goTag(extDesc, field, wireType)
3164 g.RecordTypeUse(*ext.Extendee)
3165 if n := ext.FieldDescriptorProto.TypeName; n != nil {
3166
3167 g.RecordTypeUse(*n)
3168 }
3169
3170 typeName := ext.TypeName()
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180 if extDesc.GetOptions().GetMessageSetWireFormat() && typeName[len(typeName)-1] == "message_set_extension" {
3181 typeName = typeName[:len(typeName)-1]
3182 }
3183
3184
3185
3186 extName := strings.Join(typeName, ".")
3187 if g.file.Package != nil {
3188 extName = *g.file.Package + "." + extName
3189 }
3190
3191 g.P("var ", ccTypeName, " = &", g.Pkg["proto"], ".ExtensionDesc{")
3192 g.In()
3193 g.P("ExtendedType: (", extendedType, ")(nil),")
3194 g.P("ExtensionType: (", fieldType, ")(nil),")
3195 g.P("Field: ", field.Number, ",")
3196 g.P(`Name: "`, extName, `",`)
3197 g.P("Tag: ", tag, ",")
3198 g.P(`Filename: "`, g.file.GetName(), `",`)
3199
3200 g.Out()
3201 g.P("}")
3202 g.P()
3203
3204 g.addInitf("%s.RegisterExtension(%s)", g.Pkg["proto"], ext.DescName())
3205
3206 g.file.addExport(ext, constOrVarSymbol{ccTypeName, "var", ""})
3207 }
3208
3209 func (g *Generator) generateInitFunction() {
3210 if len(g.init) == 0 {
3211 return
3212 }
3213 g.P("func init() {")
3214 g.In()
3215 for _, l := range g.init {
3216 g.P(l)
3217 }
3218 g.Out()
3219 g.P("}")
3220 g.init = nil
3221 }
3222
3223 func (g *Generator) generateFileDescriptor(file *FileDescriptor) {
3224
3225
3226 pb := proto.Clone(file.FileDescriptorProto).(*descriptor.FileDescriptorProto)
3227 pb.SourceCodeInfo = nil
3228
3229 b, err := proto.Marshal(pb)
3230 if err != nil {
3231 g.Fail(err.Error())
3232 }
3233
3234 var buf bytes.Buffer
3235 w, _ := gzip.NewWriterLevel(&buf, gzip.BestCompression)
3236 w.Write(b)
3237 w.Close()
3238 b = buf.Bytes()
3239
3240 v := file.VarName()
3241 g.P()
3242 g.P("func init() { ", g.Pkg["proto"], ".RegisterFile(", strconv.Quote(*file.Name), ", ", v, ") }")
3243 if gogoproto.ImportsGoGoProto(g.file.FileDescriptorProto) && gogoproto.RegistersGolangProto(g.file.FileDescriptorProto) {
3244 g.P("func init() { ", g.Pkg["golang_proto"], ".RegisterFile(", strconv.Quote(*file.Name), ", ", v, ") }")
3245 }
3246 g.P("var ", v, " = []byte{")
3247 g.In()
3248 g.P("// ", len(b), " bytes of a gzipped FileDescriptorProto")
3249 for len(b) > 0 {
3250 n := 16
3251 if n > len(b) {
3252 n = len(b)
3253 }
3254
3255 s := ""
3256 for _, c := range b[:n] {
3257 s += fmt.Sprintf("0x%02x,", c)
3258 }
3259 g.P(s)
3260
3261 b = b[n:]
3262 }
3263 g.Out()
3264 g.P("}")
3265 }
3266
3267 func (g *Generator) generateEnumRegistration(enum *EnumDescriptor) {
3268
3269 pkg := enum.File().GetPackage()
3270 if pkg != "" {
3271 pkg += "."
3272 }
3273
3274 typeName := enum.TypeName()
3275
3276 ccTypeName := CamelCaseSlice(typeName)
3277 g.addInitf("%s.RegisterEnum(%q, %[3]s_name, %[3]s_value)", g.Pkg["proto"], pkg+ccTypeName, ccTypeName)
3278 if gogoproto.ImportsGoGoProto(g.file.FileDescriptorProto) && gogoproto.RegistersGolangProto(g.file.FileDescriptorProto) {
3279 g.addInitf("%s.RegisterEnum(%q, %[3]s_name, %[3]s_value)", g.Pkg["golang_proto"], pkg+ccTypeName, ccTypeName)
3280 }
3281 }
3282
3283
3284
3285
3286 func isASCIILower(c byte) bool {
3287 return 'a' <= c && c <= 'z'
3288 }
3289
3290
3291 func isASCIIDigit(c byte) bool {
3292 return '0' <= c && c <= '9'
3293 }
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303 func CamelCase(s string) string {
3304 if s == "" {
3305 return ""
3306 }
3307 t := make([]byte, 0, 32)
3308 i := 0
3309 if s[0] == '_' {
3310
3311 t = append(t, 'X')
3312 i++
3313 }
3314
3315
3316
3317
3318 for ; i < len(s); i++ {
3319 c := s[i]
3320 if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) {
3321 continue
3322 }
3323 if isASCIIDigit(c) {
3324 t = append(t, c)
3325 continue
3326 }
3327
3328
3329 if isASCIILower(c) {
3330 c ^= ' '
3331 }
3332 t = append(t, c)
3333
3334 for i+1 < len(s) && isASCIILower(s[i+1]) {
3335 i++
3336 t = append(t, s[i])
3337 }
3338 }
3339 return string(t)
3340 }
3341
3342
3343
3344 func CamelCaseSlice(elem []string) string { return CamelCase(strings.Join(elem, "_")) }
3345
3346
3347 func dottedSlice(elem []string) string { return strings.Join(elem, ".") }
3348
3349
3350 func isOptional(field *descriptor.FieldDescriptorProto) bool {
3351 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_OPTIONAL
3352 }
3353
3354
3355 func isRequired(field *descriptor.FieldDescriptorProto) bool {
3356 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REQUIRED
3357 }
3358
3359
3360 func isRepeated(field *descriptor.FieldDescriptorProto) bool {
3361 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED
3362 }
3363
3364
3365 func IsScalar(field *descriptor.FieldDescriptorProto) bool {
3366 if field.Type == nil {
3367 return false
3368 }
3369 switch *field.Type {
3370 case descriptor.FieldDescriptorProto_TYPE_DOUBLE,
3371 descriptor.FieldDescriptorProto_TYPE_FLOAT,
3372 descriptor.FieldDescriptorProto_TYPE_INT64,
3373 descriptor.FieldDescriptorProto_TYPE_UINT64,
3374 descriptor.FieldDescriptorProto_TYPE_INT32,
3375 descriptor.FieldDescriptorProto_TYPE_FIXED64,
3376 descriptor.FieldDescriptorProto_TYPE_FIXED32,
3377 descriptor.FieldDescriptorProto_TYPE_BOOL,
3378 descriptor.FieldDescriptorProto_TYPE_UINT32,
3379 descriptor.FieldDescriptorProto_TYPE_ENUM,
3380 descriptor.FieldDescriptorProto_TYPE_SFIXED32,
3381 descriptor.FieldDescriptorProto_TYPE_SFIXED64,
3382 descriptor.FieldDescriptorProto_TYPE_SINT32,
3383 descriptor.FieldDescriptorProto_TYPE_SINT64:
3384 return true
3385 default:
3386 return false
3387 }
3388 }
3389
3390
3391
3392
3393 func badToUnderscore(r rune) rune {
3394 if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' {
3395 return r
3396 }
3397 return '_'
3398 }
3399
3400
3401 func baseName(name string) string {
3402
3403 if i := strings.LastIndex(name, "/"); i >= 0 {
3404 name = name[i+1:]
3405 }
3406
3407 if i := strings.LastIndex(name, "."); i >= 0 {
3408 name = name[0:i]
3409 }
3410 return name
3411 }
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421 const (
3422
3423 packagePath = 2
3424 messagePath = 4
3425 enumPath = 5
3426
3427 messageFieldPath = 2
3428 messageMessagePath = 3
3429 messageEnumPath = 4
3430 messageOneofPath = 8
3431
3432 enumValuePath = 2
3433 )
3434
3435 var supportTypeAliases bool
3436
3437 func init() {
3438 for _, tag := range build.Default.ReleaseTags {
3439 if tag == "go1.9" {
3440 supportTypeAliases = true
3441 return
3442 }
3443 }
3444 }
3445
View as plain text