blob: 12ff35b94f1da9942ca60a5907aa580286ad3fef [file] [log] [blame]
Andrea Campanella3614a922021-02-25 12:40:42 +01001// Copyright 2010 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
khenaidooab1f7bd2019-11-14 14:00:27 -05004
Andrea Campanella3614a922021-02-25 12:40:42 +01005// Package generator is deprecated.
6//
7// This package is excluded from the Go protocol buffer compatibility guarantee
8// and may be deleted at some point in the future.
9//
10// Deprecated: Use the "google.golang.org/protobuf/compiler/protogen" package
11// instead to write protoc plugins in Go.
khenaidooab1f7bd2019-11-14 14:00:27 -050012package generator
13
14import (
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
Andrea Campanella3614a922021-02-25 12:40:42 +010042func 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
khenaidooab1f7bd2019-11-14 14:00:27 -050049// generatedCodeVersion indicates a version of the generated code.
50// It is incremented whenever an incompatibility between the generated code and
51// proto package is introduced; the generated code references
52// a constant, proto.ProtoPackageIsVersionN (where N is generatedCodeVersion).
53const generatedCodeVersion = 3
54
55// A Plugin provides functionality to add to the output during Go code generation,
56// such as to produce RPC stubs.
57type Plugin interface {
58 // Name identifies the plugin.
59 Name() string
60 // Init is called once after data structures are built but before
61 // code generation begins.
62 Init(g *Generator)
63 // Generate produces the code generated by the plugin for this file,
64 // except for the imports, by calling the generator's methods P, In, and Out.
65 Generate(file *FileDescriptor)
66 // GenerateImports produces the import declarations for this file.
67 // It is called after Generate.
68 GenerateImports(file *FileDescriptor)
69}
70
71var plugins []Plugin
72
73// RegisterPlugin installs a (second-order) plugin to be run when the Go output is generated.
74// It is typically called during initialization.
75func RegisterPlugin(p Plugin) {
76 plugins = append(plugins, p)
77}
78
79// A GoImportPath is the import path of a Go package. e.g., "google.golang.org/genproto/protobuf".
80type GoImportPath string
81
82func (p GoImportPath) String() string { return strconv.Quote(string(p)) }
83
84// A GoPackageName is the name of a Go package. e.g., "protobuf".
85type GoPackageName string
86
87// Each type we import as a protocol buffer (other than FileDescriptorProto) needs
88// a pointer to the FileDescriptorProto that represents it. These types achieve that
89// wrapping by placing each Proto inside a struct with the pointer to its File. The
90// structs have the same names as their contents, with "Proto" removed.
91// FileDescriptor is used to store the things that it points to.
92
93// The file and package name method are common to messages and enums.
94type common struct {
95 file *FileDescriptor // File this object comes from.
96}
97
98// GoImportPath is the import path of the Go package containing the type.
99func (c *common) GoImportPath() GoImportPath {
100 return c.file.importPath
101}
102
103func (c *common) File() *FileDescriptor { return c.file }
104
105func fileIsProto3(file *descriptor.FileDescriptorProto) bool {
106 return file.GetSyntax() == "proto3"
107}
108
109func (c *common) proto3() bool { return fileIsProto3(c.file.FileDescriptorProto) }
110
111// Descriptor represents a protocol buffer message.
112type Descriptor struct {
113 common
114 *descriptor.DescriptorProto
115 parent *Descriptor // The containing message, if any.
116 nested []*Descriptor // Inner messages, if any.
117 enums []*EnumDescriptor // Inner enums, if any.
118 ext []*ExtensionDescriptor // Extensions, if any.
119 typename []string // Cached typename vector.
120 index int // The index into the container, whether the file or another message.
121 path string // The SourceCodeInfo path as comma-separated integers.
122 group bool
123}
124
125// TypeName returns the elements of the dotted type name.
126// The package name is not part of this name.
127func (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// EnumDescriptor describes an enum. If it's at top level, its parent will be nil.
145// Otherwise it will be the descriptor of the message in which it is defined.
146type EnumDescriptor struct {
147 common
148 *descriptor.EnumDescriptorProto
149 parent *Descriptor // The containing message, if any.
150 typename []string // Cached typename vector.
151 index int // The index into the container, whether the file or a message.
152 path string // The SourceCodeInfo path as comma-separated integers.
153}
154
155// TypeName returns the elements of the dotted type name.
156// The package name is not part of this name.
157func (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// Everything but the last element of the full type name, CamelCased.
175// The values of type Foo.Bar are call Foo_value1... not Foo_Bar_value1... .
176func (e *EnumDescriptor) prefix() string {
177 if e.parent == nil {
178 // If the enum is not part of a message, the prefix is just the type name.
179 return CamelCase(*e.Name) + "_"
180 }
181 typeName := e.TypeName()
182 return CamelCaseSlice(typeName[0:len(typeName)-1]) + "_"
183}
184
185// The integer value of the named constant in this enumerated type.
186func (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// ExtensionDescriptor describes an extension. If it's at top level, its parent will be nil.
197// Otherwise it will be the descriptor of the message in which it is defined.
198type ExtensionDescriptor struct {
199 common
200 *descriptor.FieldDescriptorProto
201 parent *Descriptor // The containing message, if any.
202}
203
204// TypeName returns the elements of the dotted type name.
205// The package name is not part of this name.
206func (e *ExtensionDescriptor) TypeName() (s []string) {
207 name := e.GetName()
208 if e.parent == nil {
209 // top-level extension
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// DescName returns the variable name used for the generated descriptor.
221func (e *ExtensionDescriptor) DescName() string {
222 // The full type name.
223 typeName := e.TypeName()
224 // Each scope of the extension is individually CamelCased, and all are joined with "_" with an "E_" prefix.
225 for i, s := range typeName {
226 typeName[i] = CamelCase(s)
227 }
228 return "E_" + strings.Join(typeName, "_")
229}
230
231// ImportedDescriptor describes a type that has been publicly imported from another file.
232type ImportedDescriptor struct {
233 common
234 o Object
235}
236
237func (id *ImportedDescriptor) TypeName() []string { return id.o.TypeName() }
238
239// FileDescriptor describes an protocol buffer descriptor file (.proto).
240// It includes slices of all the messages and enums defined within it.
241// Those slices are constructed by WrapTypes.
242type FileDescriptor struct {
243 *descriptor.FileDescriptorProto
244 desc []*Descriptor // All the messages defined in this file.
245 enum []*EnumDescriptor // All the enums defined in this file.
246 ext []*ExtensionDescriptor // All the top-level extensions defined in this file.
247 imp []*ImportedDescriptor // All types defined in files publicly imported by this file.
248
249 // Comments, stored as a map of path (comma-separated integers) to the comment.
250 comments map[string]*descriptor.SourceCodeInfo_Location
251
252 // The full list of symbols that are exported,
253 // as a map from the exported object to its symbols.
254 // This is used for supporting public imports.
255 exported map[Object][]symbol
256
257 importPath GoImportPath // Import path of this file's package.
258 packageName GoPackageName // Name of this file's Go package.
259
260 proto3 bool // whether to generate proto3 code for this file
261}
262
263// VarName is the variable name we'll use in the generated code to refer
264// to the compressed bytes of this descriptor. It is not exported, so
265// it is only valid inside the generated package.
266func (d *FileDescriptor) VarName() string {
267 h := sha256.Sum256([]byte(d.GetName()))
268 return fmt.Sprintf("fileDescriptor_%s", hex.EncodeToString(h[:8]))
269}
270
271// goPackageOption interprets the file's go_package option.
272// If there is no go_package, it returns ("", "", false).
273// If there's a simple name, it returns ("", pkg, true).
274// If the option implies an import path, it returns (impPath, pkg, true).
275func (d *FileDescriptor) goPackageOption() (impPath GoImportPath, pkg GoPackageName, ok bool) {
276 opt := d.GetOptions().GetGoPackage()
277 if opt == "" {
278 return "", "", false
279 }
280 // A semicolon-delimited suffix delimits the import path and package name.
281 sc := strings.Index(opt, ";")
282 if sc >= 0 {
283 return GoImportPath(opt[:sc]), cleanPackageName(opt[sc+1:]), true
284 }
285 // The presence of a slash implies there's an import path.
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// goFileName returns the output name for the generated Go file.
294func (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 // Does the file have a "go_package" option?
306 // If it does, it may override the filename.
307 if impPath, _, ok := d.goPackageOption(); ok && impPath != "" {
308 // Replace the existing dirname with the declared import path.
309 _, name = path.Split(name)
310 name = path.Join(string(impPath), name)
311 return name
312 }
313
314 return name
315}
316
317func (d *FileDescriptor) addExport(obj Object, sym symbol) {
318 d.exported[obj] = append(d.exported[obj], sym)
319}
320
321// symbol is an interface representing an exported Go symbol.
322type symbol interface {
323 // GenerateAlias should generate an appropriate alias
324 // for the symbol from the named package.
325 GenerateAlias(g *Generator, filename string, pkg GoPackageName)
326}
327
328type messageSymbol struct {
329 sym string
330 hasExtensions, isMessageSet bool
331 oneofTypes []string
332}
333
334type getterSymbol struct {
335 name string
336 typ string
337 typeName string // canonical name in proto world; empty for proto.Message and similar
338 genType bool // whether typ contains a generated type (message/group/enum)
339}
340
341func (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
349type enumSymbol struct {
350 name string
351 proto3 bool // Whether this came from a proto3 file.
352}
353
354func (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
362type constOrVarSymbol struct {
363 sym string
364 typ string // either "const" or "var"
365 cast string // if non-empty, a type cast is required (used for enums)
366}
367
368func (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// Object is an interface abstracting the abilities shared by enums, messages, extensions and imported objects.
377type Object interface {
378 GoImportPath() GoImportPath
379 TypeName() []string
380 File() *FileDescriptor
381}
382
383// Generator is the type whose methods generate the output, stored in the associated response structure.
384type Generator struct {
385 *bytes.Buffer
386
387 Request *plugin.CodeGeneratorRequest // The input.
388 Response *plugin.CodeGeneratorResponse // The output.
389
390 Param map[string]string // Command-line parameters.
391 PackageImportPath string // Go import path of the package we're generating code for
392 ImportPrefix string // String to prefix to imported package file names.
393 ImportMap map[string]string // Mapping from .proto file name to import path
394
395 Pkg map[string]string // The names under which we import support packages
396
397 outputImportPath GoImportPath // Package we're generating code for.
398 allFiles []*FileDescriptor // All files in the tree
399 allFilesByName map[string]*FileDescriptor // All files by filename.
400 genFiles []*FileDescriptor // Those files we will generate output for.
401 file *FileDescriptor // The file we are compiling now.
402 packageNames map[GoImportPath]GoPackageName // Imported package names in the current file.
403 usedPackages map[GoImportPath]bool // Packages used in current file.
404 usedPackageNames map[GoPackageName]bool // Package names used in the current file.
405 addedImports map[GoImportPath]bool // Additional imports to emit.
406 typeNameToObject map[string]Object // Key is a fully-qualified name in input syntax.
407 init []string // Lines to emit in the init function.
408 indent string
409 pathType pathType // How to generate output filenames.
410 writeOutput bool
411 annotateCode bool // whether to store annotations
412 annotations []*descriptor.GeneratedCodeInfo_Annotation // annotations to store
413}
414
415type pathType int
416
417const (
418 pathTypeImport pathType = iota
419 pathTypeSourceRelative
420)
421
422// New creates a new generator and allocates the request and response protobufs.
423func 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// Error reports a problem, including an error, and exits the program.
432func (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// Fail reports a problem and exits the program.
439func (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// CommandLineParameters breaks the comma-separated list of key=value pairs
446// in the parameter (a member of the request protobuf) into a key/value map.
447// It then sets file name mappings defined by those entries.
448func (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" // Default list of plugin names to enable (empty means all).
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 // Amend the set of plugins.
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// DefaultPackageName returns the package name printed for the object.
504// If its file is in a different package, it returns the package name we're using for this file, plus ".".
505// Otherwise it returns the empty string.
506func (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// GoPackageName returns the name used for a package.
515func (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// AddImport adds a package to the generated file's import section.
529// It returns the name used for the package.
530func (g *Generator) AddImport(importPath GoImportPath) GoPackageName {
531 g.addedImports[importPath] = true
532 return g.GoPackageName(importPath)
533}
534
535var globalPackageNames = map[GoPackageName]bool{
536 "fmt": true,
537 "math": true,
538 "proto": true,
539}
540
541// Create and remember a guaranteed unique package name. Pkg is the candidate name.
542// The FileDescriptor parameter is unused.
543func 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
552var 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
580var 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
622func cleanPackageName(name string) GoPackageName {
623 name = strings.Map(badToUnderscore, name)
624 // Identifier must not be keyword or predeclared identifier: insert _.
625 if isGoKeyword[name] {
626 name = "_" + name
627 }
628 // Identifier must not begin with digit: insert _.
629 if r, _ := utf8.DecodeRuneInString(name); unicode.IsDigit(r) {
630 name = "_" + name
631 }
632 return GoPackageName(name)
633}
634
635// defaultGoPackage returns the package name to use,
636// derived from the import path of the package we're building code for.
637func (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// SetPackageNames sets the package name for this run.
646// The package name must agree across all files being generated.
647// It also defines unique package names for all imported files.
648func (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 // Source file: option go_package = "quux/bar";
660 f.packageName = p
661 } else if p, ok := defaultPackageNames[f.importPath]; ok {
662 // A go_package option in another file in the same package.
663 //
664 // This is a poor choice in general, since every source file should
665 // contain a go_package option. Supported mainly for historical
666 // compatibility.
667 f.packageName = p
668 } else if p := g.defaultGoPackage(); p != "" {
669 // Command-line: import_path=quux/bar.
670 //
671 // The import_path flag sets a package name for files which don't
672 // contain a go_package option.
673 f.packageName = p
674 } else if p := f.GetPackage(); p != "" {
675 // Source file: package quux.bar;
676 f.packageName = cleanPackageName(p)
677 } else {
678 // Source filename.
679 f.packageName = cleanPackageName(baseName(f.GetName()))
680 }
681 }
682
683 // Check that all files have a consistent package name and import path.
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 // Names of support packages. These never vary (if there are conflicts,
694 // we rename the conflicting package), so this could be removed someday.
695 g.Pkg = map[string]string{
696 "fmt": "fmt",
697 "math": "math",
698 "proto": "proto",
699 }
700}
701
702// WrapTypes walks the incoming data, wrapping DescriptorProtos, EnumDescriptorProtos
703// and FileDescriptorProtos into file-referenced objects within the Generator.
704// It also creates the list of files to generate and so should be called before GenerateAllFiles.
705func (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 // The import path may be set in a number of ways.
719 if substitution, ok := g.ImportMap[f.GetName()]; ok {
720 // Command-line: M=foo.proto=quux/bar.
721 //
722 // Explicit mapping of source file to import path.
723 fd.importPath = GoImportPath(substitution)
724 } else if genFileNames[f.GetName()] && g.PackageImportPath != "" {
725 // Command-line: import_path=quux/bar.
726 //
727 // The import_path flag sets the import path for every file that
728 // we generate code for.
729 fd.importPath = GoImportPath(g.PackageImportPath)
730 } else if p, _, _ := fd.goPackageOption(); p != "" {
731 // Source file: option go_package = "quux/bar";
732 //
733 // The go_package option sets the import path. Most users should use this.
734 fd.importPath = p
735 } else {
736 // Source filename.
737 //
738 // Last resort when nothing else is available.
739 fd.importPath = GoImportPath(path.Dir(f.GetName()))
740 }
741 // We must wrap the descriptors before we wrap the enums
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// Scan the descriptors in this file. For each one, build the slice of nested descriptors
766func (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
781func (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// Construct the Descriptor
797func 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 // The only way to distinguish a group from a message is whether
811 // the containing message has a TYPE_GROUP field that matches.
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// Return a slice of all the Descriptors defined within this file
834func 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// Wrap this Descriptor, recursively
843func 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// Construct the EnumDescriptor
853func 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// Return a slice of all the EnumDescriptors defined within this file
869func wrapEnumDescriptors(file *FileDescriptor, descs []*Descriptor) []*EnumDescriptor {
870 sl := make([]*EnumDescriptor, 0, len(file.EnumType)+10)
871 // Top-level enums.
872 for i, enum := range file.EnumType {
873 sl = append(sl, newEnumDescriptor(enum, nil, file, i))
874 }
875 // Enums within messages. Enums within embedded messages appear in the outer-most message.
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// Return a slice of all the top-level ExtensionDescriptors defined within this file.
885func 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// Return a slice of all the types that are publicly imported into this file.
894func 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
913func 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// BuildTypeNameMap builds the map from fully qualified type names to objects.
928// The key names for the map come from the input data, which puts a period at the beginning.
929// It should be called after SetPackageNames and before GenerateAllFiles.
930func (g *Generator) BuildTypeNameMap() {
931 g.typeNameToObject = make(map[string]Object)
932 for _, f := range g.allFiles {
933 // The names in this loop are defined by the proto world, not us, so the
934 // package name may be empty. If so, the dotted package name of X will
935 // be ".X"; otherwise it will be ".pkg.X".
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// ObjectNamed, given a fully-qualified input type name as it appears in the input data,
952// returns the descriptor for the message or enum with that name.
953func (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// AnnotatedAtoms is a list of atoms (as consumed by P) that records the file name and proto AST path from which they originated.
962type AnnotatedAtoms struct {
963 source string
964 path string
965 atoms []interface{}
966}
967
968// Annotate records the file name and proto AST path of a list of atoms
969// so that a later call to P can emit a link from each atom to its origin.
970func Annotate(file *FileDescriptor, path string, atoms ...interface{}) *AnnotatedAtoms {
971 return &AnnotatedAtoms{source: *file.Name, path: path, atoms: atoms}
972}
973
974// printAtom prints the (atomic, non-annotation) argument to the generated output.
975func (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// P prints the arguments to the generated output. It handles strings and int32s, plus
1005// handling indirections because they may be *string, etc. Any inputs of type AnnotatedAtoms may emit
1006// annotations in a .meta file in addition to outputting the atoms themselves (if g.annotateCode
1007// is true).
1008func (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// addInitf stores the given statement to be printed inside the file's init function.
1045// The statement is given as a format specifier and arguments.
1046func (g *Generator) addInitf(stmt string, a ...interface{}) {
1047 g.init = append(g.init, fmt.Sprintf(stmt, a...))
1048}
1049
1050// In Indents the output one tab stop.
1051func (g *Generator) In() { g.indent += "\t" }
1052
1053// Out unindents the output one tab stop.
1054func (g *Generator) Out() {
1055 if len(g.indent) > 0 {
1056 g.indent = g.indent[1:]
1057 }
1058}
1059
1060// GenerateAllFiles generates the output for all the files we're outputting.
1061func (g *Generator) GenerateAllFiles() {
1062 // Initialize the plugins
1063 for _, p := range plugins {
1064 p.Init(g)
1065 }
1066 // Generate the output. The generator runs for every file, even the files
1067 // that we don't generate output for, so that we can collate the full list
1068 // of exported symbols to support public imports.
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 // Store the generated code annotations in text, as the protoc plugin protocol requires that
1088 // strings contain valid UTF-8.
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// Run all the plugins associated with the file.
1098func (g *Generator) runPlugins(file *FileDescriptor) {
1099 for _, p := range plugins {
1100 p.Generate(file)
1101 }
1102}
1103
1104// Fill the response protocol buffer with the generated output for all the files we're
1105// supposed to generate.
1106func (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 // Don't generate virtual messages for maps.
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 // Run the plugins before the imports so we know which imports are necessary.
1143 g.runPlugins(file)
1144
1145 // Generate header and imports last, though they appear first in the output.
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 // Adjust the offsets for annotations displaced by the header and imports.
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 // Reformat generated code and patch annotation locations.
1164 fset := token.NewFileSet()
1165 original := g.Bytes()
1166 if g.annotateCode {
1167 // make a copy independent of g; we'll need it after Reset.
1168 original = append([]byte(nil), original...)
1169 }
1170 fileAST, err := parser.ParseFile(fset, "", original, parser.ParseComments)
1171 if err != nil {
1172 // Print out the bad code with line numbers.
1173 // This should never happen in practice, but it can while changing generated code,
1174 // so consider this a debugging aid.
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// Generate the header, including package definition
1205func (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// deprecationComment is the standard comment added to deprecated
1220// messages, fields, enums, and enum values.
1221var deprecationComment = "// Deprecated: Do not use."
1222
1223// PrintComments prints any comments from the source .proto file.
1224// The path is a comma-separated list of integers.
1225// It returns an indication of whether any comments were printed.
1226// See descriptor.proto for its format.
1227func (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// makeComments generates the comment string for the field, no "\n" at the end
1239func (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
1253func (g *Generator) fileByName(filename string) *FileDescriptor {
1254 return g.allFilesByName[filename]
1255}
1256
1257// weak returns whether the ith import of the current file is a weak import.
1258func (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// Generate the imports
1268func (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 // Do not import our own package.
1274 if importPath == g.file.importPath {
1275 continue
1276 }
1277 // Do not import weak imports.
1278 if g.weak(int32(i)) {
1279 continue
1280 }
1281 // Do not import a package twice.
1282 if _, ok := imports[importPath]; ok {
1283 continue
1284 }
1285 // We need to import all the dependencies, even if we don't reference them,
1286 // because other code and tools depend on having the full transitive closure
1287 // of protocol buffer types in the binary.
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 // We almost always need a proto import. Rather than computing when we
1298 // do, which is tricky when there's a plugin, just import it and
1299 // reference it later. The same argument applies to the fmt and math packages.
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 // TODO: may need to worry about uniqueness across plugins
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
1321func (g *Generator) generateImported(id *ImportedDescriptor) {
1322 df := id.o.File()
1323 filename := *df.Name
1324 if df.importPath == g.file.importPath {
1325 // Don't generate type aliases for files in the same Go package as this one.
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// Generate the enum definitions for this EnumDescriptor.
1341func (g *Generator) generateEnum(enum *EnumDescriptor) {
1342 // The full type name
1343 typeName := enum.TypeName()
1344 // The full type name, CamelCased.
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) // avoid duplicate values
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 // XXX: skip groups?
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// The tag is a string like "varint,2,opt,name=fieldname,def=7" that
1435// identifies details of the field for the protocol buffer marshaling and unmarshaling
1436// code. The fields are:
1437// wire encoding
1438// protocol tag number
1439// opt,req,rep for optional, required, or repeated
1440// packed whether the encoding is "packed" (optional; repeated primitives only)
1441// name= the original declared name
1442// enum= the name of the enum type if it is an enum-typed field.
1443// proto3 if this field is in a proto3 message
1444// def= string representation of the default value, if any.
1445// The default value must be in a representation that can be used at run-time
1446// to generate the default value. Thus bools become 0 and 1, for instance.
1447func (g *Generator) goTag(message *Descriptor, field *descriptor.FieldDescriptorProto, wiretype string) string {
1448 optrepreq := ""
1449 switch {
1450 case isOptional(field):
1451 optrepreq = "opt"
1452 case isRequired(field):
1453 optrepreq = "req"
1454 case isRepeated(field):
1455 optrepreq = "rep"
1456 }
1457 var defaultValue string
1458 if dv := field.DefaultValue; dv != nil { // set means an explicit default
1459 defaultValue = *dv
1460 // Some types need tweaking.
1461 switch *field.Type {
1462 case descriptor.FieldDescriptorProto_TYPE_BOOL:
1463 if defaultValue == "true" {
1464 defaultValue = "1"
1465 } else {
1466 defaultValue = "0"
1467 }
1468 case descriptor.FieldDescriptorProto_TYPE_STRING,
1469 descriptor.FieldDescriptorProto_TYPE_BYTES:
1470 // Nothing to do. Quoting is done for the whole tag.
1471 case descriptor.FieldDescriptorProto_TYPE_ENUM:
1472 // For enums we need to provide the integer constant.
1473 obj := g.ObjectNamed(field.GetTypeName())
1474 if id, ok := obj.(*ImportedDescriptor); ok {
1475 // It is an enum that was publicly imported.
1476 // We need the underlying type.
1477 obj = id.o
1478 }
1479 enum, ok := obj.(*EnumDescriptor)
1480 if !ok {
1481 log.Printf("obj is a %T", obj)
1482 if id, ok := obj.(*ImportedDescriptor); ok {
1483 log.Printf("id.o is a %T", id.o)
1484 }
1485 g.Fail("unknown enum type", CamelCaseSlice(obj.TypeName()))
1486 }
1487 defaultValue = enum.integerValueAsString(defaultValue)
1488 case descriptor.FieldDescriptorProto_TYPE_FLOAT:
1489 if def := defaultValue; def != "inf" && def != "-inf" && def != "nan" {
1490 if f, err := strconv.ParseFloat(defaultValue, 32); err == nil {
1491 defaultValue = fmt.Sprint(float32(f))
1492 }
1493 }
1494 case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
1495 if def := defaultValue; def != "inf" && def != "-inf" && def != "nan" {
1496 if f, err := strconv.ParseFloat(defaultValue, 64); err == nil {
1497 defaultValue = fmt.Sprint(f)
1498 }
1499 }
1500 }
1501 defaultValue = ",def=" + defaultValue
1502 }
1503 enum := ""
1504 if *field.Type == descriptor.FieldDescriptorProto_TYPE_ENUM {
1505 // We avoid using obj.GoPackageName(), because we want to use the
1506 // original (proto-world) package name.
1507 obj := g.ObjectNamed(field.GetTypeName())
1508 if id, ok := obj.(*ImportedDescriptor); ok {
1509 obj = id.o
1510 }
1511 enum = ",enum="
1512 if pkg := obj.File().GetPackage(); pkg != "" {
1513 enum += pkg + "."
1514 }
1515 enum += CamelCaseSlice(obj.TypeName())
1516 }
1517 packed := ""
1518 if (field.Options != nil && field.Options.GetPacked()) ||
1519 // Per https://developers.google.com/protocol-buffers/docs/proto3#simple:
1520 // "In proto3, repeated fields of scalar numeric types use packed encoding by default."
1521 (message.proto3() && (field.Options == nil || field.Options.Packed == nil) &&
1522 isRepeated(field) && isScalar(field)) {
1523 packed = ",packed"
1524 }
1525 fieldName := field.GetName()
1526 name := fieldName
1527 if *field.Type == descriptor.FieldDescriptorProto_TYPE_GROUP {
1528 // We must use the type name for groups instead of
1529 // the field name to preserve capitalization.
1530 // type_name in FieldDescriptorProto is fully-qualified,
1531 // but we only want the local part.
1532 name = *field.TypeName
1533 if i := strings.LastIndex(name, "."); i >= 0 {
1534 name = name[i+1:]
1535 }
1536 }
1537 if json := field.GetJsonName(); field.Extendee == nil && json != "" && json != name {
1538 // TODO: escaping might be needed, in which case
1539 // perhaps this should be in its own "json" tag.
1540 name += ",json=" + json
1541 }
1542 name = ",name=" + name
1543 if message.proto3() {
1544 name += ",proto3"
1545 }
1546 oneof := ""
1547 if field.OneofIndex != nil {
1548 oneof = ",oneof"
1549 }
1550 return strconv.Quote(fmt.Sprintf("%s,%d,%s%s%s%s%s%s",
1551 wiretype,
1552 field.GetNumber(),
1553 optrepreq,
1554 packed,
1555 name,
1556 enum,
1557 oneof,
1558 defaultValue))
1559}
1560
1561func needsStar(typ descriptor.FieldDescriptorProto_Type) bool {
1562 switch typ {
1563 case descriptor.FieldDescriptorProto_TYPE_GROUP:
1564 return false
1565 case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
1566 return false
1567 case descriptor.FieldDescriptorProto_TYPE_BYTES:
1568 return false
1569 }
1570 return true
1571}
1572
1573// TypeName is the printed name appropriate for an item. If the object is in the current file,
1574// TypeName drops the package name and underscores the rest.
1575// Otherwise the object is from another package; and the result is the underscored
1576// package name followed by the item name.
1577// The result always has an initial capital.
1578func (g *Generator) TypeName(obj Object) string {
1579 return g.DefaultPackageName(obj) + CamelCaseSlice(obj.TypeName())
1580}
1581
1582// GoType returns a string representing the type name, and the wire type
1583func (g *Generator) GoType(message *Descriptor, field *descriptor.FieldDescriptorProto) (typ string, wire string) {
1584 // TODO: Options.
1585 switch *field.Type {
1586 case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
1587 typ, wire = "float64", "fixed64"
1588 case descriptor.FieldDescriptorProto_TYPE_FLOAT:
1589 typ, wire = "float32", "fixed32"
1590 case descriptor.FieldDescriptorProto_TYPE_INT64:
1591 typ, wire = "int64", "varint"
1592 case descriptor.FieldDescriptorProto_TYPE_UINT64:
1593 typ, wire = "uint64", "varint"
1594 case descriptor.FieldDescriptorProto_TYPE_INT32:
1595 typ, wire = "int32", "varint"
1596 case descriptor.FieldDescriptorProto_TYPE_UINT32:
1597 typ, wire = "uint32", "varint"
1598 case descriptor.FieldDescriptorProto_TYPE_FIXED64:
1599 typ, wire = "uint64", "fixed64"
1600 case descriptor.FieldDescriptorProto_TYPE_FIXED32:
1601 typ, wire = "uint32", "fixed32"
1602 case descriptor.FieldDescriptorProto_TYPE_BOOL:
1603 typ, wire = "bool", "varint"
1604 case descriptor.FieldDescriptorProto_TYPE_STRING:
1605 typ, wire = "string", "bytes"
1606 case descriptor.FieldDescriptorProto_TYPE_GROUP:
1607 desc := g.ObjectNamed(field.GetTypeName())
1608 typ, wire = "*"+g.TypeName(desc), "group"
1609 case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
1610 desc := g.ObjectNamed(field.GetTypeName())
1611 typ, wire = "*"+g.TypeName(desc), "bytes"
1612 case descriptor.FieldDescriptorProto_TYPE_BYTES:
1613 typ, wire = "[]byte", "bytes"
1614 case descriptor.FieldDescriptorProto_TYPE_ENUM:
1615 desc := g.ObjectNamed(field.GetTypeName())
1616 typ, wire = g.TypeName(desc), "varint"
1617 case descriptor.FieldDescriptorProto_TYPE_SFIXED32:
1618 typ, wire = "int32", "fixed32"
1619 case descriptor.FieldDescriptorProto_TYPE_SFIXED64:
1620 typ, wire = "int64", "fixed64"
1621 case descriptor.FieldDescriptorProto_TYPE_SINT32:
1622 typ, wire = "int32", "zigzag32"
1623 case descriptor.FieldDescriptorProto_TYPE_SINT64:
1624 typ, wire = "int64", "zigzag64"
1625 default:
1626 g.Fail("unknown type for", field.GetName())
1627 }
1628 if isRepeated(field) {
1629 typ = "[]" + typ
1630 } else if message != nil && message.proto3() {
1631 return
1632 } else if field.OneofIndex != nil && message != nil {
1633 return
1634 } else if needsStar(*field.Type) {
1635 typ = "*" + typ
1636 }
1637 return
1638}
1639
1640func (g *Generator) RecordTypeUse(t string) {
1641 if _, ok := g.typeNameToObject[t]; !ok {
1642 return
1643 }
1644 importPath := g.ObjectNamed(t).GoImportPath()
1645 if importPath == g.outputImportPath {
1646 // Don't record use of objects in our package.
1647 return
1648 }
1649 g.AddImport(importPath)
1650 g.usedPackages[importPath] = true
1651}
1652
1653// Method names that may be generated. Fields with these names get an
1654// underscore appended. Any change to this set is a potential incompatible
1655// API change because it changes generated field names.
1656var methodNames = [...]string{
1657 "Reset",
1658 "String",
1659 "ProtoMessage",
1660 "Marshal",
1661 "Unmarshal",
1662 "ExtensionRangeArray",
1663 "ExtensionMap",
1664 "Descriptor",
1665}
1666
1667// Names of messages in the `google.protobuf` package for which
1668// we will generate XXX_WellKnownType methods.
1669var wellKnownTypes = map[string]bool{
1670 "Any": true,
1671 "Duration": true,
1672 "Empty": true,
1673 "Struct": true,
1674 "Timestamp": true,
1675
1676 "Value": true,
1677 "ListValue": true,
1678 "DoubleValue": true,
1679 "FloatValue": true,
1680 "Int64Value": true,
1681 "UInt64Value": true,
1682 "Int32Value": true,
1683 "UInt32Value": true,
1684 "BoolValue": true,
1685 "StringValue": true,
1686 "BytesValue": true,
1687}
1688
1689// getterDefault finds the default value for the field to return from a getter,
1690// regardless of if it's a built in default or explicit from the source. Returns e.g. "nil", `""`, "Default_MessageType_FieldName"
1691func (g *Generator) getterDefault(field *descriptor.FieldDescriptorProto, goMessageType string) string {
1692 if isRepeated(field) {
1693 return "nil"
1694 }
1695 if def := field.GetDefaultValue(); def != "" {
1696 defaultConstant := g.defaultConstantName(goMessageType, field.GetName())
1697 if *field.Type != descriptor.FieldDescriptorProto_TYPE_BYTES {
1698 return defaultConstant
1699 }
1700 return "append([]byte(nil), " + defaultConstant + "...)"
1701 }
1702 switch *field.Type {
1703 case descriptor.FieldDescriptorProto_TYPE_BOOL:
1704 return "false"
1705 case descriptor.FieldDescriptorProto_TYPE_STRING:
1706 return `""`
1707 case descriptor.FieldDescriptorProto_TYPE_GROUP, descriptor.FieldDescriptorProto_TYPE_MESSAGE, descriptor.FieldDescriptorProto_TYPE_BYTES:
1708 return "nil"
1709 case descriptor.FieldDescriptorProto_TYPE_ENUM:
1710 obj := g.ObjectNamed(field.GetTypeName())
1711 var enum *EnumDescriptor
1712 if id, ok := obj.(*ImportedDescriptor); ok {
1713 // The enum type has been publicly imported.
1714 enum, _ = id.o.(*EnumDescriptor)
1715 } else {
1716 enum, _ = obj.(*EnumDescriptor)
1717 }
1718 if enum == nil {
1719 log.Printf("don't know how to generate getter for %s", field.GetName())
1720 return "nil"
1721 }
1722 if len(enum.Value) == 0 {
1723 return "0 // empty enum"
1724 }
1725 first := enum.Value[0].GetName()
1726 return g.DefaultPackageName(obj) + enum.prefix() + first
1727 default:
1728 return "0"
1729 }
1730}
1731
1732// defaultConstantName builds the name of the default constant from the message
1733// type name and the untouched field name, e.g. "Default_MessageType_FieldName"
1734func (g *Generator) defaultConstantName(goMessageType, protoFieldName string) string {
1735 return "Default_" + goMessageType + "_" + CamelCase(protoFieldName)
1736}
1737
1738// The different types of fields in a message and how to actually print them
1739// Most of the logic for generateMessage is in the methods of these types.
1740//
1741// Note that the content of the field is irrelevant, a simpleField can contain
1742// anything from a scalar to a group (which is just a message).
1743//
1744// Extension fields (and message sets) are however handled separately.
1745//
1746// simpleField - a field that is neiter weak nor oneof, possibly repeated
1747// oneofField - field containing list of subfields:
1748// - oneofSubField - a field within the oneof
1749
1750// msgCtx contains the context for the generator functions.
1751type msgCtx struct {
1752 goName string // Go struct name of the message, e.g. MessageName
1753 message *Descriptor // The descriptor for the message
1754}
1755
1756// fieldCommon contains data common to all types of fields.
1757type fieldCommon struct {
1758 goName string // Go name of field, e.g. "FieldName" or "Descriptor_"
1759 protoName string // Name of field in proto language, e.g. "field_name" or "descriptor"
1760 getterName string // Name of the getter, e.g. "GetFieldName" or "GetDescriptor_"
1761 goType string // The Go type as a string, e.g. "*int32" or "*OtherMessage"
1762 tags string // The tag string/annotation for the type, e.g. `protobuf:"varint,8,opt,name=region_id,json=regionId"`
1763 fullPath string // The full path of the field as used by Annotate etc, e.g. "4,0,2,0"
1764}
1765
1766// getProtoName gets the proto name of a field, e.g. "field_name" or "descriptor".
1767func (f *fieldCommon) getProtoName() string {
1768 return f.protoName
1769}
1770
1771// getGoType returns the go type of the field as a string, e.g. "*int32".
1772func (f *fieldCommon) getGoType() string {
1773 return f.goType
1774}
1775
1776// simpleField is not weak, not a oneof, not an extension. Can be required, optional or repeated.
1777type simpleField struct {
1778 fieldCommon
1779 protoTypeName string // Proto type name, empty if primitive, e.g. ".google.protobuf.Duration"
1780 protoType descriptor.FieldDescriptorProto_Type // Actual type enum value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64
1781 deprecated string // Deprecation comment, if any, e.g. "// Deprecated: Do not use."
1782 getterDef string // Default for getters, e.g. "nil", `""` or "Default_MessageType_FieldName"
1783 protoDef string // Default value as defined in the proto file, e.g "yoshi" or "5"
1784 comment string // The full comment for the field, e.g. "// Useful information"
1785}
1786
1787// decl prints the declaration of the field in the struct (if any).
1788func (f *simpleField) decl(g *Generator, mc *msgCtx) {
1789 g.P(f.comment, Annotate(mc.message.file, f.fullPath, f.goName), "\t", f.goType, "\t`", f.tags, "`", f.deprecated)
1790}
1791
1792// getter prints the getter for the field.
1793func (f *simpleField) getter(g *Generator, mc *msgCtx) {
1794 star := ""
1795 tname := f.goType
1796 if needsStar(f.protoType) && tname[0] == '*' {
1797 tname = tname[1:]
1798 star = "*"
1799 }
1800 if f.deprecated != "" {
1801 g.P(f.deprecated)
1802 }
1803 g.P("func (m *", mc.goName, ") ", Annotate(mc.message.file, f.fullPath, f.getterName), "() "+tname+" {")
1804 if f.getterDef == "nil" { // Simpler getter
1805 g.P("if m != nil {")
1806 g.P("return m." + f.goName)
1807 g.P("}")
1808 g.P("return nil")
1809 g.P("}")
1810 g.P()
1811 return
1812 }
1813 if mc.message.proto3() {
1814 g.P("if m != nil {")
1815 } else {
1816 g.P("if m != nil && m." + f.goName + " != nil {")
1817 }
1818 g.P("return " + star + "m." + f.goName)
1819 g.P("}")
1820 g.P("return ", f.getterDef)
1821 g.P("}")
1822 g.P()
1823}
1824
1825// setter prints the setter method of the field.
1826func (f *simpleField) setter(g *Generator, mc *msgCtx) {
1827 // No setter for regular fields yet
1828}
1829
1830// getProtoDef returns the default value explicitly stated in the proto file, e.g "yoshi" or "5".
1831func (f *simpleField) getProtoDef() string {
1832 return f.protoDef
1833}
1834
1835// getProtoTypeName returns the protobuf type name for the field as returned by field.GetTypeName(), e.g. ".google.protobuf.Duration".
1836func (f *simpleField) getProtoTypeName() string {
1837 return f.protoTypeName
1838}
1839
1840// getProtoType returns the *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64.
1841func (f *simpleField) getProtoType() descriptor.FieldDescriptorProto_Type {
1842 return f.protoType
1843}
1844
1845// oneofSubFields are kept slize held by each oneofField. They do not appear in the top level slize of fields for the message.
1846type oneofSubField struct {
1847 fieldCommon
1848 protoTypeName string // Proto type name, empty if primitive, e.g. ".google.protobuf.Duration"
1849 protoType descriptor.FieldDescriptorProto_Type // Actual type enum value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64
1850 oneofTypeName string // Type name of the enclosing struct, e.g. "MessageName_FieldName"
1851 fieldNumber int // Actual field number, as defined in proto, e.g. 12
1852 getterDef string // Default for getters, e.g. "nil", `""` or "Default_MessageType_FieldName"
1853 protoDef string // Default value as defined in the proto file, e.g "yoshi" or "5"
1854 deprecated string // Deprecation comment, if any.
1855}
1856
1857// typedNil prints a nil casted to the pointer to this field.
1858// - for XXX_OneofWrappers
1859func (f *oneofSubField) typedNil(g *Generator) {
1860 g.P("(*", f.oneofTypeName, ")(nil),")
1861}
1862
1863// getProtoDef returns the default value explicitly stated in the proto file, e.g "yoshi" or "5".
1864func (f *oneofSubField) getProtoDef() string {
1865 return f.protoDef
1866}
1867
1868// getProtoTypeName returns the protobuf type name for the field as returned by field.GetTypeName(), e.g. ".google.protobuf.Duration".
1869func (f *oneofSubField) getProtoTypeName() string {
1870 return f.protoTypeName
1871}
1872
1873// getProtoType returns the *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64.
1874func (f *oneofSubField) getProtoType() descriptor.FieldDescriptorProto_Type {
1875 return f.protoType
1876}
1877
1878// oneofField represents the oneof on top level.
1879// The alternative fields within the oneof are represented by oneofSubField.
1880type oneofField struct {
1881 fieldCommon
1882 subFields []*oneofSubField // All the possible oneof fields
1883 comment string // The full comment for the field, e.g. "// Types that are valid to be assigned to MyOneof:\n\\"
1884}
1885
1886// decl prints the declaration of the field in the struct (if any).
1887func (f *oneofField) decl(g *Generator, mc *msgCtx) {
1888 comment := f.comment
1889 for _, sf := range f.subFields {
1890 comment += "//\t*" + sf.oneofTypeName + "\n"
1891 }
1892 g.P(comment, Annotate(mc.message.file, f.fullPath, f.goName), " ", f.goType, " `", f.tags, "`")
1893}
1894
1895// getter for a oneof field will print additional discriminators and interfaces for the oneof,
1896// also it prints all the getters for the sub fields.
1897func (f *oneofField) getter(g *Generator, mc *msgCtx) {
1898 // The discriminator type
1899 g.P("type ", f.goType, " interface {")
1900 g.P(f.goType, "()")
1901 g.P("}")
1902 g.P()
1903 // The subField types, fulfilling the discriminator type contract
1904 for _, sf := range f.subFields {
1905 g.P("type ", Annotate(mc.message.file, sf.fullPath, sf.oneofTypeName), " struct {")
1906 g.P(Annotate(mc.message.file, sf.fullPath, sf.goName), " ", sf.goType, " `", sf.tags, "`")
1907 g.P("}")
1908 g.P()
1909 }
1910 for _, sf := range f.subFields {
1911 g.P("func (*", sf.oneofTypeName, ") ", f.goType, "() {}")
1912 g.P()
1913 }
1914 // Getter for the oneof field
1915 g.P("func (m *", mc.goName, ") ", Annotate(mc.message.file, f.fullPath, f.getterName), "() ", f.goType, " {")
1916 g.P("if m != nil { return m.", f.goName, " }")
1917 g.P("return nil")
1918 g.P("}")
1919 g.P()
1920 // Getters for each oneof
1921 for _, sf := range f.subFields {
1922 if sf.deprecated != "" {
1923 g.P(sf.deprecated)
1924 }
1925 g.P("func (m *", mc.goName, ") ", Annotate(mc.message.file, sf.fullPath, sf.getterName), "() "+sf.goType+" {")
1926 g.P("if x, ok := m.", f.getterName, "().(*", sf.oneofTypeName, "); ok {")
1927 g.P("return x.", sf.goName)
1928 g.P("}")
1929 g.P("return ", sf.getterDef)
1930 g.P("}")
1931 g.P()
1932 }
1933}
1934
1935// setter prints the setter method of the field.
1936func (f *oneofField) setter(g *Generator, mc *msgCtx) {
1937 // No setters for oneof yet
1938}
1939
1940// topLevelField interface implemented by all types of fields on the top level (not oneofSubField).
1941type topLevelField interface {
1942 decl(g *Generator, mc *msgCtx) // print declaration within the struct
1943 getter(g *Generator, mc *msgCtx) // print getter
1944 setter(g *Generator, mc *msgCtx) // print setter if applicable
1945}
1946
1947// defField interface implemented by all types of fields that can have defaults (not oneofField, but instead oneofSubField).
1948type defField interface {
1949 getProtoDef() string // default value explicitly stated in the proto file, e.g "yoshi" or "5"
1950 getProtoName() string // proto name of a field, e.g. "field_name" or "descriptor"
1951 getGoType() string // go type of the field as a string, e.g. "*int32"
1952 getProtoTypeName() string // protobuf type name for the field, e.g. ".google.protobuf.Duration"
1953 getProtoType() descriptor.FieldDescriptorProto_Type // *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64
1954}
1955
1956// generateDefaultConstants adds constants for default values if needed, which is only if the default value is.
1957// explicit in the proto.
1958func (g *Generator) generateDefaultConstants(mc *msgCtx, topLevelFields []topLevelField) {
1959 // Collect fields that can have defaults
1960 dFields := []defField{}
1961 for _, pf := range topLevelFields {
1962 if f, ok := pf.(*oneofField); ok {
1963 for _, osf := range f.subFields {
1964 dFields = append(dFields, osf)
1965 }
1966 continue
1967 }
1968 dFields = append(dFields, pf.(defField))
1969 }
1970 for _, df := range dFields {
1971 def := df.getProtoDef()
1972 if def == "" {
1973 continue
1974 }
1975 fieldname := g.defaultConstantName(mc.goName, df.getProtoName())
1976 typename := df.getGoType()
1977 if typename[0] == '*' {
1978 typename = typename[1:]
1979 }
1980 kind := "const "
1981 switch {
1982 case typename == "bool":
1983 case typename == "string":
1984 def = strconv.Quote(def)
1985 case typename == "[]byte":
1986 def = "[]byte(" + strconv.Quote(unescape(def)) + ")"
1987 kind = "var "
1988 case def == "inf", def == "-inf", def == "nan":
1989 // These names are known to, and defined by, the protocol language.
1990 switch def {
1991 case "inf":
1992 def = "math.Inf(1)"
1993 case "-inf":
1994 def = "math.Inf(-1)"
1995 case "nan":
1996 def = "math.NaN()"
1997 }
1998 if df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_FLOAT {
1999 def = "float32(" + def + ")"
2000 }
2001 kind = "var "
2002 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_FLOAT:
2003 if f, err := strconv.ParseFloat(def, 32); err == nil {
2004 def = fmt.Sprint(float32(f))
2005 }
2006 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_DOUBLE:
2007 if f, err := strconv.ParseFloat(def, 64); err == nil {
2008 def = fmt.Sprint(f)
2009 }
2010 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_ENUM:
2011 // Must be an enum. Need to construct the prefixed name.
2012 obj := g.ObjectNamed(df.getProtoTypeName())
2013 var enum *EnumDescriptor
2014 if id, ok := obj.(*ImportedDescriptor); ok {
2015 // The enum type has been publicly imported.
2016 enum, _ = id.o.(*EnumDescriptor)
2017 } else {
2018 enum, _ = obj.(*EnumDescriptor)
2019 }
2020 if enum == nil {
2021 log.Printf("don't know how to generate constant for %s", fieldname)
2022 continue
2023 }
2024 def = g.DefaultPackageName(obj) + enum.prefix() + def
2025 }
2026 g.P(kind, fieldname, " ", typename, " = ", def)
2027 g.file.addExport(mc.message, constOrVarSymbol{fieldname, kind, ""})
2028 }
2029 g.P()
2030}
2031
2032// generateInternalStructFields just adds the XXX_<something> fields to the message struct.
2033func (g *Generator) generateInternalStructFields(mc *msgCtx, topLevelFields []topLevelField) {
2034 g.P("XXX_NoUnkeyedLiteral\tstruct{} `json:\"-\"`") // prevent unkeyed struct literals
2035 if len(mc.message.ExtensionRange) > 0 {
2036 messageset := ""
2037 if opts := mc.message.Options; opts != nil && opts.GetMessageSetWireFormat() {
2038 messageset = "protobuf_messageset:\"1\" "
2039 }
2040 g.P(g.Pkg["proto"], ".XXX_InternalExtensions `", messageset, "json:\"-\"`")
2041 }
2042 g.P("XXX_unrecognized\t[]byte `json:\"-\"`")
2043 g.P("XXX_sizecache\tint32 `json:\"-\"`")
2044
2045}
2046
2047// generateOneofFuncs adds all the utility functions for oneof, including marshalling, unmarshalling and sizer.
2048func (g *Generator) generateOneofFuncs(mc *msgCtx, topLevelFields []topLevelField) {
2049 ofields := []*oneofField{}
2050 for _, f := range topLevelFields {
2051 if o, ok := f.(*oneofField); ok {
2052 ofields = append(ofields, o)
2053 }
2054 }
2055 if len(ofields) == 0 {
2056 return
2057 }
2058
2059 // OneofFuncs
2060 g.P("// XXX_OneofWrappers is for the internal use of the proto package.")
2061 g.P("func (*", mc.goName, ") XXX_OneofWrappers() []interface{} {")
2062 g.P("return []interface{}{")
2063 for _, of := range ofields {
2064 for _, sf := range of.subFields {
2065 sf.typedNil(g)
2066 }
2067 }
2068 g.P("}")
2069 g.P("}")
2070 g.P()
2071}
2072
2073// generateMessageStruct adds the actual struct with it's members (but not methods) to the output.
2074func (g *Generator) generateMessageStruct(mc *msgCtx, topLevelFields []topLevelField) {
2075 comments := g.PrintComments(mc.message.path)
2076
2077 // Guarantee deprecation comments appear after user-provided comments.
2078 if mc.message.GetOptions().GetDeprecated() {
2079 if comments {
2080 // Convention: Separate deprecation comments from original
2081 // comments with an empty line.
2082 g.P("//")
2083 }
2084 g.P(deprecationComment)
2085 }
2086
2087 g.P("type ", Annotate(mc.message.file, mc.message.path, mc.goName), " struct {")
2088 for _, pf := range topLevelFields {
2089 pf.decl(g, mc)
2090 }
2091 g.generateInternalStructFields(mc, topLevelFields)
2092 g.P("}")
2093}
2094
2095// generateGetters adds getters for all fields, including oneofs and weak fields when applicable.
2096func (g *Generator) generateGetters(mc *msgCtx, topLevelFields []topLevelField) {
2097 for _, pf := range topLevelFields {
2098 pf.getter(g, mc)
2099 }
2100}
2101
2102// generateSetters add setters for all fields, including oneofs and weak fields when applicable.
2103func (g *Generator) generateSetters(mc *msgCtx, topLevelFields []topLevelField) {
2104 for _, pf := range topLevelFields {
2105 pf.setter(g, mc)
2106 }
2107}
2108
2109// generateCommonMethods adds methods to the message that are not on a per field basis.
2110func (g *Generator) generateCommonMethods(mc *msgCtx) {
2111 // Reset, String and ProtoMessage methods.
2112 g.P("func (m *", mc.goName, ") Reset() { *m = ", mc.goName, "{} }")
2113 g.P("func (m *", mc.goName, ") String() string { return ", g.Pkg["proto"], ".CompactTextString(m) }")
2114 g.P("func (*", mc.goName, ") ProtoMessage() {}")
2115 var indexes []string
2116 for m := mc.message; m != nil; m = m.parent {
2117 indexes = append([]string{strconv.Itoa(m.index)}, indexes...)
2118 }
2119 g.P("func (*", mc.goName, ") Descriptor() ([]byte, []int) {")
2120 g.P("return ", g.file.VarName(), ", []int{", strings.Join(indexes, ", "), "}")
2121 g.P("}")
2122 g.P()
2123 // TODO: Revisit the decision to use a XXX_WellKnownType method
2124 // if we change proto.MessageName to work with multiple equivalents.
2125 if mc.message.file.GetPackage() == "google.protobuf" && wellKnownTypes[mc.message.GetName()] {
2126 g.P("func (*", mc.goName, `) XXX_WellKnownType() string { return "`, mc.message.GetName(), `" }`)
2127 g.P()
2128 }
2129
2130 // Extension support methods
2131 if len(mc.message.ExtensionRange) > 0 {
2132 g.P()
2133 g.P("var extRange_", mc.goName, " = []", g.Pkg["proto"], ".ExtensionRange{")
2134 for _, r := range mc.message.ExtensionRange {
2135 end := fmt.Sprint(*r.End - 1) // make range inclusive on both ends
2136 g.P("{Start: ", r.Start, ", End: ", end, "},")
2137 }
2138 g.P("}")
2139 g.P("func (*", mc.goName, ") ExtensionRangeArray() []", g.Pkg["proto"], ".ExtensionRange {")
2140 g.P("return extRange_", mc.goName)
2141 g.P("}")
2142 g.P()
2143 }
2144
2145 // TODO: It does not scale to keep adding another method for every
2146 // operation on protos that we want to switch over to using the
2147 // table-driven approach. Instead, we should only add a single method
2148 // that allows getting access to the *InternalMessageInfo struct and then
2149 // calling Unmarshal, Marshal, Merge, Size, and Discard directly on that.
2150
2151 // Wrapper for table-driven marshaling and unmarshaling.
2152 g.P("func (m *", mc.goName, ") XXX_Unmarshal(b []byte) error {")
2153 g.P("return xxx_messageInfo_", mc.goName, ".Unmarshal(m, b)")
2154 g.P("}")
2155
2156 g.P("func (m *", mc.goName, ") XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {")
2157 g.P("return xxx_messageInfo_", mc.goName, ".Marshal(b, m, deterministic)")
2158 g.P("}")
2159
2160 g.P("func (m *", mc.goName, ") XXX_Merge(src ", g.Pkg["proto"], ".Message) {")
2161 g.P("xxx_messageInfo_", mc.goName, ".Merge(m, src)")
2162 g.P("}")
2163
2164 g.P("func (m *", mc.goName, ") XXX_Size() int {") // avoid name clash with "Size" field in some message
2165 g.P("return xxx_messageInfo_", mc.goName, ".Size(m)")
2166 g.P("}")
2167
2168 g.P("func (m *", mc.goName, ") XXX_DiscardUnknown() {")
2169 g.P("xxx_messageInfo_", mc.goName, ".DiscardUnknown(m)")
2170 g.P("}")
2171
2172 g.P("var xxx_messageInfo_", mc.goName, " ", g.Pkg["proto"], ".InternalMessageInfo")
2173 g.P()
2174}
2175
2176// Generate the type, methods and default constant definitions for this Descriptor.
2177func (g *Generator) generateMessage(message *Descriptor) {
2178 topLevelFields := []topLevelField{}
2179 oFields := make(map[int32]*oneofField)
2180 // The full type name
2181 typeName := message.TypeName()
2182 // The full type name, CamelCased.
2183 goTypeName := CamelCaseSlice(typeName)
2184
2185 usedNames := make(map[string]bool)
2186 for _, n := range methodNames {
2187 usedNames[n] = true
2188 }
2189
2190 // allocNames finds a conflict-free variation of the given strings,
2191 // consistently mutating their suffixes.
2192 // It returns the same number of strings.
2193 allocNames := func(ns ...string) []string {
2194 Loop:
2195 for {
2196 for _, n := range ns {
2197 if usedNames[n] {
2198 for i := range ns {
2199 ns[i] += "_"
2200 }
2201 continue Loop
2202 }
2203 }
2204 for _, n := range ns {
2205 usedNames[n] = true
2206 }
2207 return ns
2208 }
2209 }
2210
2211 mapFieldTypes := make(map[*descriptor.FieldDescriptorProto]string) // keep track of the map fields to be added later
2212
2213 // Build a structure more suitable for generating the text in one pass
2214 for i, field := range message.Field {
2215 // Allocate the getter and the field at the same time so name
2216 // collisions create field/method consistent names.
2217 // TODO: This allocation occurs based on the order of the fields
2218 // in the proto file, meaning that a change in the field
2219 // ordering can change generated Method/Field names.
2220 base := CamelCase(*field.Name)
2221 ns := allocNames(base, "Get"+base)
2222 fieldName, fieldGetterName := ns[0], ns[1]
2223 typename, wiretype := g.GoType(message, field)
2224 jsonName := *field.Name
2225 tag := fmt.Sprintf("protobuf:%s json:%q", g.goTag(message, field, wiretype), jsonName+",omitempty")
2226
2227 oneof := field.OneofIndex != nil
2228 if oneof && oFields[*field.OneofIndex] == nil {
2229 odp := message.OneofDecl[int(*field.OneofIndex)]
2230 base := CamelCase(odp.GetName())
Andrea Campanella3614a922021-02-25 12:40:42 +01002231 names := allocNames(base, "Get"+base)
2232 fname, gname := names[0], names[1]
khenaidooab1f7bd2019-11-14 14:00:27 -05002233
2234 // This is the first field of a oneof we haven't seen before.
2235 // Generate the union field.
2236 oneofFullPath := fmt.Sprintf("%s,%d,%d", message.path, messageOneofPath, *field.OneofIndex)
2237 c, ok := g.makeComments(oneofFullPath)
2238 if ok {
2239 c += "\n//\n"
2240 }
2241 c += "// Types that are valid to be assigned to " + fname + ":\n"
2242 // Generate the rest of this comment later,
2243 // when we've computed any disambiguation.
2244
2245 dname := "is" + goTypeName + "_" + fname
2246 tag := `protobuf_oneof:"` + odp.GetName() + `"`
2247 of := oneofField{
2248 fieldCommon: fieldCommon{
2249 goName: fname,
Andrea Campanella3614a922021-02-25 12:40:42 +01002250 getterName: gname,
khenaidooab1f7bd2019-11-14 14:00:27 -05002251 goType: dname,
2252 tags: tag,
2253 protoName: odp.GetName(),
2254 fullPath: oneofFullPath,
2255 },
2256 comment: c,
2257 }
2258 topLevelFields = append(topLevelFields, &of)
2259 oFields[*field.OneofIndex] = &of
2260 }
2261
2262 if *field.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE {
2263 desc := g.ObjectNamed(field.GetTypeName())
2264 if d, ok := desc.(*Descriptor); ok && d.GetOptions().GetMapEntry() {
2265 // Figure out the Go types and tags for the key and value types.
2266 keyField, valField := d.Field[0], d.Field[1]
2267 keyType, keyWire := g.GoType(d, keyField)
2268 valType, valWire := g.GoType(d, valField)
2269 keyTag, valTag := g.goTag(d, keyField, keyWire), g.goTag(d, valField, valWire)
2270
2271 // We don't use stars, except for message-typed values.
2272 // Message and enum types are the only two possibly foreign types used in maps,
2273 // so record their use. They are not permitted as map keys.
2274 keyType = strings.TrimPrefix(keyType, "*")
2275 switch *valField.Type {
2276 case descriptor.FieldDescriptorProto_TYPE_ENUM:
2277 valType = strings.TrimPrefix(valType, "*")
2278 g.RecordTypeUse(valField.GetTypeName())
2279 case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
2280 g.RecordTypeUse(valField.GetTypeName())
2281 default:
2282 valType = strings.TrimPrefix(valType, "*")
2283 }
2284
2285 typename = fmt.Sprintf("map[%s]%s", keyType, valType)
2286 mapFieldTypes[field] = typename // record for the getter generation
2287
2288 tag += fmt.Sprintf(" protobuf_key:%s protobuf_val:%s", keyTag, valTag)
2289 }
2290 }
2291
2292 fieldDeprecated := ""
2293 if field.GetOptions().GetDeprecated() {
2294 fieldDeprecated = deprecationComment
2295 }
2296
2297 dvalue := g.getterDefault(field, goTypeName)
2298 if oneof {
2299 tname := goTypeName + "_" + fieldName
2300 // It is possible for this to collide with a message or enum
2301 // nested in this message. Check for collisions.
2302 for {
2303 ok := true
2304 for _, desc := range message.nested {
2305 if CamelCaseSlice(desc.TypeName()) == tname {
2306 ok = false
2307 break
2308 }
2309 }
2310 for _, enum := range message.enums {
2311 if CamelCaseSlice(enum.TypeName()) == tname {
2312 ok = false
2313 break
2314 }
2315 }
2316 if !ok {
2317 tname += "_"
2318 continue
2319 }
2320 break
2321 }
2322
2323 oneofField := oFields[*field.OneofIndex]
2324 tag := "protobuf:" + g.goTag(message, field, wiretype)
2325 sf := oneofSubField{
2326 fieldCommon: fieldCommon{
2327 goName: fieldName,
2328 getterName: fieldGetterName,
2329 goType: typename,
2330 tags: tag,
2331 protoName: field.GetName(),
2332 fullPath: fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i),
2333 },
2334 protoTypeName: field.GetTypeName(),
2335 fieldNumber: int(*field.Number),
2336 protoType: *field.Type,
2337 getterDef: dvalue,
2338 protoDef: field.GetDefaultValue(),
2339 oneofTypeName: tname,
2340 deprecated: fieldDeprecated,
2341 }
2342 oneofField.subFields = append(oneofField.subFields, &sf)
2343 g.RecordTypeUse(field.GetTypeName())
2344 continue
2345 }
2346
2347 fieldFullPath := fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i)
2348 c, ok := g.makeComments(fieldFullPath)
2349 if ok {
2350 c += "\n"
2351 }
2352 rf := simpleField{
2353 fieldCommon: fieldCommon{
2354 goName: fieldName,
2355 getterName: fieldGetterName,
2356 goType: typename,
2357 tags: tag,
2358 protoName: field.GetName(),
2359 fullPath: fieldFullPath,
2360 },
2361 protoTypeName: field.GetTypeName(),
2362 protoType: *field.Type,
2363 deprecated: fieldDeprecated,
2364 getterDef: dvalue,
2365 protoDef: field.GetDefaultValue(),
2366 comment: c,
2367 }
2368 var pf topLevelField = &rf
2369
2370 topLevelFields = append(topLevelFields, pf)
2371 g.RecordTypeUse(field.GetTypeName())
2372 }
2373
2374 mc := &msgCtx{
2375 goName: goTypeName,
2376 message: message,
2377 }
2378
2379 g.generateMessageStruct(mc, topLevelFields)
2380 g.P()
2381 g.generateCommonMethods(mc)
2382 g.P()
2383 g.generateDefaultConstants(mc, topLevelFields)
2384 g.P()
2385 g.generateGetters(mc, topLevelFields)
2386 g.P()
2387 g.generateSetters(mc, topLevelFields)
2388 g.P()
2389 g.generateOneofFuncs(mc, topLevelFields)
2390 g.P()
2391
2392 var oneofTypes []string
2393 for _, f := range topLevelFields {
2394 if of, ok := f.(*oneofField); ok {
2395 for _, osf := range of.subFields {
2396 oneofTypes = append(oneofTypes, osf.oneofTypeName)
2397 }
2398 }
2399 }
2400
2401 opts := message.Options
2402 ms := &messageSymbol{
2403 sym: goTypeName,
2404 hasExtensions: len(message.ExtensionRange) > 0,
2405 isMessageSet: opts != nil && opts.GetMessageSetWireFormat(),
2406 oneofTypes: oneofTypes,
2407 }
2408 g.file.addExport(message, ms)
2409
2410 for _, ext := range message.ext {
2411 g.generateExtension(ext)
2412 }
2413
2414 fullName := strings.Join(message.TypeName(), ".")
2415 if g.file.Package != nil {
2416 fullName = *g.file.Package + "." + fullName
2417 }
2418
2419 g.addInitf("%s.RegisterType((*%s)(nil), %q)", g.Pkg["proto"], goTypeName, fullName)
2420 // Register types for native map types.
2421 for _, k := range mapFieldKeys(mapFieldTypes) {
2422 fullName := strings.TrimPrefix(*k.TypeName, ".")
2423 g.addInitf("%s.RegisterMapType((%s)(nil), %q)", g.Pkg["proto"], mapFieldTypes[k], fullName)
2424 }
2425
2426}
2427
2428type byTypeName []*descriptor.FieldDescriptorProto
2429
2430func (a byTypeName) Len() int { return len(a) }
2431func (a byTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
2432func (a byTypeName) Less(i, j int) bool { return *a[i].TypeName < *a[j].TypeName }
2433
2434// mapFieldKeys returns the keys of m in a consistent order.
2435func mapFieldKeys(m map[*descriptor.FieldDescriptorProto]string) []*descriptor.FieldDescriptorProto {
2436 keys := make([]*descriptor.FieldDescriptorProto, 0, len(m))
2437 for k := range m {
2438 keys = append(keys, k)
2439 }
2440 sort.Sort(byTypeName(keys))
2441 return keys
2442}
2443
2444var escapeChars = [256]byte{
2445 'a': '\a', 'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t', 'v': '\v', '\\': '\\', '"': '"', '\'': '\'', '?': '?',
2446}
2447
2448// unescape reverses the "C" escaping that protoc does for default values of bytes fields.
2449// It is best effort in that it effectively ignores malformed input. Seemingly invalid escape
2450// sequences are conveyed, unmodified, into the decoded result.
2451func unescape(s string) string {
2452 // NB: Sadly, we can't use strconv.Unquote because protoc will escape both
2453 // single and double quotes, but strconv.Unquote only allows one or the
2454 // other (based on actual surrounding quotes of its input argument).
2455
2456 var out []byte
2457 for len(s) > 0 {
2458 // regular character, or too short to be valid escape
2459 if s[0] != '\\' || len(s) < 2 {
2460 out = append(out, s[0])
2461 s = s[1:]
2462 } else if c := escapeChars[s[1]]; c != 0 {
2463 // escape sequence
2464 out = append(out, c)
2465 s = s[2:]
2466 } else if s[1] == 'x' || s[1] == 'X' {
2467 // hex escape, e.g. "\x80
2468 if len(s) < 4 {
2469 // too short to be valid
2470 out = append(out, s[:2]...)
2471 s = s[2:]
2472 continue
2473 }
2474 v, err := strconv.ParseUint(s[2:4], 16, 8)
2475 if err != nil {
2476 out = append(out, s[:4]...)
2477 } else {
2478 out = append(out, byte(v))
2479 }
2480 s = s[4:]
2481 } else if '0' <= s[1] && s[1] <= '7' {
2482 // octal escape, can vary from 1 to 3 octal digits; e.g., "\0" "\40" or "\164"
2483 // so consume up to 2 more bytes or up to end-of-string
2484 n := len(s[1:]) - len(strings.TrimLeft(s[1:], "01234567"))
2485 if n > 3 {
2486 n = 3
2487 }
2488 v, err := strconv.ParseUint(s[1:1+n], 8, 8)
2489 if err != nil {
2490 out = append(out, s[:1+n]...)
2491 } else {
2492 out = append(out, byte(v))
2493 }
2494 s = s[1+n:]
2495 } else {
2496 // bad escape, just propagate the slash as-is
2497 out = append(out, s[0])
2498 s = s[1:]
2499 }
2500 }
2501
2502 return string(out)
2503}
2504
2505func (g *Generator) generateExtension(ext *ExtensionDescriptor) {
2506 ccTypeName := ext.DescName()
2507
2508 extObj := g.ObjectNamed(*ext.Extendee)
2509 var extDesc *Descriptor
2510 if id, ok := extObj.(*ImportedDescriptor); ok {
2511 // This is extending a publicly imported message.
2512 // We need the underlying type for goTag.
2513 extDesc = id.o.(*Descriptor)
2514 } else {
2515 extDesc = extObj.(*Descriptor)
2516 }
2517 extendedType := "*" + g.TypeName(extObj) // always use the original
2518 field := ext.FieldDescriptorProto
2519 fieldType, wireType := g.GoType(ext.parent, field)
2520 tag := g.goTag(extDesc, field, wireType)
2521 g.RecordTypeUse(*ext.Extendee)
2522 if n := ext.FieldDescriptorProto.TypeName; n != nil {
2523 // foreign extension type
2524 g.RecordTypeUse(*n)
2525 }
2526
2527 typeName := ext.TypeName()
2528
2529 // Special case for proto2 message sets: If this extension is extending
2530 // proto2.bridge.MessageSet, and its final name component is "message_set_extension",
2531 // then drop that last component.
2532 //
2533 // TODO: This should be implemented in the text formatter rather than the generator.
2534 // In addition, the situation for when to apply this special case is implemented
2535 // differently in other languages:
2536 // https://github.com/google/protobuf/blob/aff10976/src/google/protobuf/text_format.cc#L1560
2537 if extDesc.GetOptions().GetMessageSetWireFormat() && typeName[len(typeName)-1] == "message_set_extension" {
2538 typeName = typeName[:len(typeName)-1]
2539 }
2540
2541 // For text formatting, the package must be exactly what the .proto file declares,
2542 // ignoring overrides such as the go_package option, and with no dot/underscore mapping.
2543 extName := strings.Join(typeName, ".")
2544 if g.file.Package != nil {
2545 extName = *g.file.Package + "." + extName
2546 }
2547
2548 g.P("var ", ccTypeName, " = &", g.Pkg["proto"], ".ExtensionDesc{")
2549 g.P("ExtendedType: (", extendedType, ")(nil),")
2550 g.P("ExtensionType: (", fieldType, ")(nil),")
2551 g.P("Field: ", field.Number, ",")
2552 g.P(`Name: "`, extName, `",`)
2553 g.P("Tag: ", tag, ",")
2554 g.P(`Filename: "`, g.file.GetName(), `",`)
2555
2556 g.P("}")
2557 g.P()
2558
2559 g.addInitf("%s.RegisterExtension(%s)", g.Pkg["proto"], ext.DescName())
2560
2561 g.file.addExport(ext, constOrVarSymbol{ccTypeName, "var", ""})
2562}
2563
2564func (g *Generator) generateInitFunction() {
2565 if len(g.init) == 0 {
2566 return
2567 }
2568 g.P("func init() {")
2569 for _, l := range g.init {
2570 g.P(l)
2571 }
2572 g.P("}")
2573 g.init = nil
2574}
2575
2576func (g *Generator) generateFileDescriptor(file *FileDescriptor) {
2577 // Make a copy and trim source_code_info data.
2578 // TODO: Trim this more when we know exactly what we need.
2579 pb := proto.Clone(file.FileDescriptorProto).(*descriptor.FileDescriptorProto)
2580 pb.SourceCodeInfo = nil
2581
2582 b, err := proto.Marshal(pb)
2583 if err != nil {
2584 g.Fail(err.Error())
2585 }
2586
2587 var buf bytes.Buffer
2588 w, _ := gzip.NewWriterLevel(&buf, gzip.BestCompression)
2589 w.Write(b)
2590 w.Close()
2591 b = buf.Bytes()
2592
2593 v := file.VarName()
2594 g.P()
2595 g.P("func init() { ", g.Pkg["proto"], ".RegisterFile(", strconv.Quote(*file.Name), ", ", v, ") }")
2596 g.P("var ", v, " = []byte{")
2597 g.P("// ", len(b), " bytes of a gzipped FileDescriptorProto")
2598 for len(b) > 0 {
2599 n := 16
2600 if n > len(b) {
2601 n = len(b)
2602 }
2603
2604 s := ""
2605 for _, c := range b[:n] {
2606 s += fmt.Sprintf("0x%02x,", c)
2607 }
2608 g.P(s)
2609
2610 b = b[n:]
2611 }
2612 g.P("}")
2613}
2614
2615func (g *Generator) generateEnumRegistration(enum *EnumDescriptor) {
2616 // // We always print the full (proto-world) package name here.
2617 pkg := enum.File().GetPackage()
2618 if pkg != "" {
2619 pkg += "."
2620 }
2621 // The full type name
2622 typeName := enum.TypeName()
2623 // The full type name, CamelCased.
2624 ccTypeName := CamelCaseSlice(typeName)
2625 g.addInitf("%s.RegisterEnum(%q, %[3]s_name, %[3]s_value)", g.Pkg["proto"], pkg+ccTypeName, ccTypeName)
2626}
2627
2628// And now lots of helper functions.
2629
2630// Is c an ASCII lower-case letter?
2631func isASCIILower(c byte) bool {
2632 return 'a' <= c && c <= 'z'
2633}
2634
2635// Is c an ASCII digit?
2636func isASCIIDigit(c byte) bool {
2637 return '0' <= c && c <= '9'
2638}
2639
2640// CamelCase returns the CamelCased name.
2641// If there is an interior underscore followed by a lower case letter,
2642// drop the underscore and convert the letter to upper case.
2643// There is a remote possibility of this rewrite causing a name collision,
2644// but it's so remote we're prepared to pretend it's nonexistent - since the
2645// C++ generator lowercases names, it's extremely unlikely to have two fields
2646// with different capitalizations.
2647// In short, _my_field_name_2 becomes XMyFieldName_2.
2648func CamelCase(s string) string {
2649 if s == "" {
2650 return ""
2651 }
2652 t := make([]byte, 0, 32)
2653 i := 0
2654 if s[0] == '_' {
2655 // Need a capital letter; drop the '_'.
2656 t = append(t, 'X')
2657 i++
2658 }
2659 // Invariant: if the next letter is lower case, it must be converted
2660 // to upper case.
2661 // That is, we process a word at a time, where words are marked by _ or
2662 // upper case letter. Digits are treated as words.
2663 for ; i < len(s); i++ {
2664 c := s[i]
2665 if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) {
2666 continue // Skip the underscore in s.
2667 }
2668 if isASCIIDigit(c) {
2669 t = append(t, c)
2670 continue
2671 }
2672 // Assume we have a letter now - if not, it's a bogus identifier.
2673 // The next word is a sequence of characters that must start upper case.
2674 if isASCIILower(c) {
2675 c ^= ' ' // Make it a capital letter.
2676 }
2677 t = append(t, c) // Guaranteed not lower case.
2678 // Accept lower case sequence that follows.
2679 for i+1 < len(s) && isASCIILower(s[i+1]) {
2680 i++
2681 t = append(t, s[i])
2682 }
2683 }
2684 return string(t)
2685}
2686
2687// CamelCaseSlice is like CamelCase, but the argument is a slice of strings to
2688// be joined with "_".
2689func CamelCaseSlice(elem []string) string { return CamelCase(strings.Join(elem, "_")) }
2690
2691// dottedSlice turns a sliced name into a dotted name.
2692func dottedSlice(elem []string) string { return strings.Join(elem, ".") }
2693
2694// Is this field optional?
2695func isOptional(field *descriptor.FieldDescriptorProto) bool {
2696 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_OPTIONAL
2697}
2698
2699// Is this field required?
2700func isRequired(field *descriptor.FieldDescriptorProto) bool {
2701 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REQUIRED
2702}
2703
2704// Is this field repeated?
2705func isRepeated(field *descriptor.FieldDescriptorProto) bool {
2706 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED
2707}
2708
2709// Is this field a scalar numeric type?
2710func isScalar(field *descriptor.FieldDescriptorProto) bool {
2711 if field.Type == nil {
2712 return false
2713 }
2714 switch *field.Type {
2715 case descriptor.FieldDescriptorProto_TYPE_DOUBLE,
2716 descriptor.FieldDescriptorProto_TYPE_FLOAT,
2717 descriptor.FieldDescriptorProto_TYPE_INT64,
2718 descriptor.FieldDescriptorProto_TYPE_UINT64,
2719 descriptor.FieldDescriptorProto_TYPE_INT32,
2720 descriptor.FieldDescriptorProto_TYPE_FIXED64,
2721 descriptor.FieldDescriptorProto_TYPE_FIXED32,
2722 descriptor.FieldDescriptorProto_TYPE_BOOL,
2723 descriptor.FieldDescriptorProto_TYPE_UINT32,
2724 descriptor.FieldDescriptorProto_TYPE_ENUM,
2725 descriptor.FieldDescriptorProto_TYPE_SFIXED32,
2726 descriptor.FieldDescriptorProto_TYPE_SFIXED64,
2727 descriptor.FieldDescriptorProto_TYPE_SINT32,
2728 descriptor.FieldDescriptorProto_TYPE_SINT64:
2729 return true
2730 default:
2731 return false
2732 }
2733}
2734
2735// badToUnderscore is the mapping function used to generate Go names from package names,
2736// which can be dotted in the input .proto file. It replaces non-identifier characters such as
2737// dot or dash with underscore.
2738func badToUnderscore(r rune) rune {
2739 if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' {
2740 return r
2741 }
2742 return '_'
2743}
2744
2745// baseName returns the last path element of the name, with the last dotted suffix removed.
2746func baseName(name string) string {
2747 // First, find the last element
2748 if i := strings.LastIndex(name, "/"); i >= 0 {
2749 name = name[i+1:]
2750 }
2751 // Now drop the suffix
2752 if i := strings.LastIndex(name, "."); i >= 0 {
2753 name = name[0:i]
2754 }
2755 return name
2756}
2757
2758// The SourceCodeInfo message describes the location of elements of a parsed
2759// .proto file by way of a "path", which is a sequence of integers that
2760// describe the route from a FileDescriptorProto to the relevant submessage.
2761// The path alternates between a field number of a repeated field, and an index
2762// into that repeated field. The constants below define the field numbers that
2763// are used.
2764//
2765// See descriptor.proto for more information about this.
2766const (
2767 // tag numbers in FileDescriptorProto
2768 packagePath = 2 // package
2769 messagePath = 4 // message_type
2770 enumPath = 5 // enum_type
2771 // tag numbers in DescriptorProto
2772 messageFieldPath = 2 // field
2773 messageMessagePath = 3 // nested_type
2774 messageEnumPath = 4 // enum_type
2775 messageOneofPath = 8 // oneof_decl
2776 // tag numbers in EnumDescriptorProto
2777 enumValuePath = 2 // value
2778)
2779
2780var supportTypeAliases bool
2781
2782func init() {
2783 for _, tag := range build.Default.ReleaseTags {
2784 if tag == "go1.9" {
2785 supportTypeAliases = true
2786 return
2787 }
2788 }
2789}