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