blob: c13a9f1e6379c344bdc1214c069b16265c4b6ee5 [file] [log] [blame]
khenaidooac637102019-01-14 15:44:34 -05001// Go support for Protocol Buffers - Google's data interchange format
2//
3// Copyright 2010 The Go Authors. All rights reserved.
4// https://github.com/golang/protobuf
5//
6// Redistribution and use in source and binary forms, with or without
7// modification, are permitted provided that the following conditions are
8// met:
9//
10// * Redistributions of source code must retain the above copyright
11// notice, this list of conditions and the following disclaimer.
12// * Redistributions in binary form must reproduce the above
13// copyright notice, this list of conditions and the following disclaimer
14// in the documentation and/or other materials provided with the
15// distribution.
16// * Neither the name of Google Inc. nor the names of its
17// contributors may be used to endorse or promote products derived from
18// this software without specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32/*
33 The code generator for the plugin for the Google protocol buffer compiler.
34 It generates Go code from the protocol buffer description files read by the
35 main routine.
36*/
37package generator
38
39import (
40 "bufio"
41 "bytes"
42 "compress/gzip"
43 "crypto/sha256"
44 "encoding/hex"
45 "fmt"
46 "go/build"
47 "go/parser"
48 "go/printer"
49 "go/token"
50 "log"
51 "os"
52 "path"
53 "sort"
54 "strconv"
55 "strings"
56 "unicode"
57 "unicode/utf8"
58
59 "github.com/golang/protobuf/proto"
60 "github.com/golang/protobuf/protoc-gen-go/generator/internal/remap"
61
62 "github.com/golang/protobuf/protoc-gen-go/descriptor"
63 plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
64)
65
66// generatedCodeVersion indicates a version of the generated code.
67// It is incremented whenever an incompatibility between the generated code and
68// proto package is introduced; the generated code references
69// a constant, proto.ProtoPackageIsVersionN (where N is generatedCodeVersion).
70const generatedCodeVersion = 2
71
72// A Plugin provides functionality to add to the output during Go code generation,
73// such as to produce RPC stubs.
74type Plugin interface {
75 // Name identifies the plugin.
76 Name() string
77 // Init is called once after data structures are built but before
78 // code generation begins.
79 Init(g *Generator)
80 // Generate produces the code generated by the plugin for this file,
81 // except for the imports, by calling the generator's methods P, In, and Out.
82 Generate(file *FileDescriptor)
83 // GenerateImports produces the import declarations for this file.
84 // It is called after Generate.
85 GenerateImports(file *FileDescriptor)
86}
87
88var plugins []Plugin
89
90// RegisterPlugin installs a (second-order) plugin to be run when the Go output is generated.
91// It is typically called during initialization.
92func RegisterPlugin(p Plugin) {
93 plugins = append(plugins, p)
94}
95
96// A GoImportPath is the import path of a Go package. e.g., "google.golang.org/genproto/protobuf".
97type GoImportPath string
98
99func (p GoImportPath) String() string { return strconv.Quote(string(p)) }
100
101// A GoPackageName is the name of a Go package. e.g., "protobuf".
102type GoPackageName string
103
104// Each type we import as a protocol buffer (other than FileDescriptorProto) needs
105// a pointer to the FileDescriptorProto that represents it. These types achieve that
106// wrapping by placing each Proto inside a struct with the pointer to its File. The
107// structs have the same names as their contents, with "Proto" removed.
108// FileDescriptor is used to store the things that it points to.
109
110// The file and package name method are common to messages and enums.
111type common struct {
112 file *FileDescriptor // File this object comes from.
113}
114
115// GoImportPath is the import path of the Go package containing the type.
116func (c *common) GoImportPath() GoImportPath {
117 return c.file.importPath
118}
119
120func (c *common) File() *FileDescriptor { return c.file }
121
122func fileIsProto3(file *descriptor.FileDescriptorProto) bool {
123 return file.GetSyntax() == "proto3"
124}
125
126func (c *common) proto3() bool { return fileIsProto3(c.file.FileDescriptorProto) }
127
128// Descriptor represents a protocol buffer message.
129type Descriptor struct {
130 common
131 *descriptor.DescriptorProto
132 parent *Descriptor // The containing message, if any.
133 nested []*Descriptor // Inner messages, if any.
134 enums []*EnumDescriptor // Inner enums, if any.
135 ext []*ExtensionDescriptor // Extensions, if any.
136 typename []string // Cached typename vector.
137 index int // The index into the container, whether the file or another message.
138 path string // The SourceCodeInfo path as comma-separated integers.
139 group bool
140}
141
142// TypeName returns the elements of the dotted type name.
143// The package name is not part of this name.
144func (d *Descriptor) TypeName() []string {
145 if d.typename != nil {
146 return d.typename
147 }
148 n := 0
149 for parent := d; parent != nil; parent = parent.parent {
150 n++
151 }
152 s := make([]string, n)
153 for parent := d; parent != nil; parent = parent.parent {
154 n--
155 s[n] = parent.GetName()
156 }
157 d.typename = s
158 return s
159}
160
161// EnumDescriptor describes an enum. If it's at top level, its parent will be nil.
162// Otherwise it will be the descriptor of the message in which it is defined.
163type EnumDescriptor struct {
164 common
165 *descriptor.EnumDescriptorProto
166 parent *Descriptor // The containing message, if any.
167 typename []string // Cached typename vector.
168 index int // The index into the container, whether the file or a message.
169 path string // The SourceCodeInfo path as comma-separated integers.
170}
171
172// TypeName returns the elements of the dotted type name.
173// The package name is not part of this name.
174func (e *EnumDescriptor) TypeName() (s []string) {
175 if e.typename != nil {
176 return e.typename
177 }
178 name := e.GetName()
179 if e.parent == nil {
180 s = make([]string, 1)
181 } else {
182 pname := e.parent.TypeName()
183 s = make([]string, len(pname)+1)
184 copy(s, pname)
185 }
186 s[len(s)-1] = name
187 e.typename = s
188 return s
189}
190
191// Everything but the last element of the full type name, CamelCased.
192// The values of type Foo.Bar are call Foo_value1... not Foo_Bar_value1... .
193func (e *EnumDescriptor) prefix() string {
194 if e.parent == nil {
195 // If the enum is not part of a message, the prefix is just the type name.
196 return CamelCase(*e.Name) + "_"
197 }
198 typeName := e.TypeName()
199 return CamelCaseSlice(typeName[0:len(typeName)-1]) + "_"
200}
201
202// The integer value of the named constant in this enumerated type.
203func (e *EnumDescriptor) integerValueAsString(name string) string {
204 for _, c := range e.Value {
205 if c.GetName() == name {
206 return fmt.Sprint(c.GetNumber())
207 }
208 }
209 log.Fatal("cannot find value for enum constant")
210 return ""
211}
212
213// ExtensionDescriptor describes an extension. If it's at top level, its parent will be nil.
214// Otherwise it will be the descriptor of the message in which it is defined.
215type ExtensionDescriptor struct {
216 common
217 *descriptor.FieldDescriptorProto
218 parent *Descriptor // The containing message, if any.
219}
220
221// TypeName returns the elements of the dotted type name.
222// The package name is not part of this name.
223func (e *ExtensionDescriptor) TypeName() (s []string) {
224 name := e.GetName()
225 if e.parent == nil {
226 // top-level extension
227 s = make([]string, 1)
228 } else {
229 pname := e.parent.TypeName()
230 s = make([]string, len(pname)+1)
231 copy(s, pname)
232 }
233 s[len(s)-1] = name
234 return s
235}
236
237// DescName returns the variable name used for the generated descriptor.
238func (e *ExtensionDescriptor) DescName() string {
239 // The full type name.
240 typeName := e.TypeName()
241 // Each scope of the extension is individually CamelCased, and all are joined with "_" with an "E_" prefix.
242 for i, s := range typeName {
243 typeName[i] = CamelCase(s)
244 }
245 return "E_" + strings.Join(typeName, "_")
246}
247
248// ImportedDescriptor describes a type that has been publicly imported from another file.
249type ImportedDescriptor struct {
250 common
251 o Object
252}
253
254func (id *ImportedDescriptor) TypeName() []string { return id.o.TypeName() }
255
256// FileDescriptor describes an protocol buffer descriptor file (.proto).
257// It includes slices of all the messages and enums defined within it.
258// Those slices are constructed by WrapTypes.
259type FileDescriptor struct {
260 *descriptor.FileDescriptorProto
261 desc []*Descriptor // All the messages defined in this file.
262 enum []*EnumDescriptor // All the enums defined in this file.
263 ext []*ExtensionDescriptor // All the top-level extensions defined in this file.
264 imp []*ImportedDescriptor // All types defined in files publicly imported by this file.
265
266 // Comments, stored as a map of path (comma-separated integers) to the comment.
267 comments map[string]*descriptor.SourceCodeInfo_Location
268
269 // The full list of symbols that are exported,
270 // as a map from the exported object to its symbols.
271 // This is used for supporting public imports.
272 exported map[Object][]symbol
273
274 fingerprint string // Fingerprint of this file's contents.
275 importPath GoImportPath // Import path of this file's package.
276 packageName GoPackageName // Name of this file's Go package.
277
278 proto3 bool // whether to generate proto3 code for this file
279}
280
281// VarName is the variable name we'll use in the generated code to refer
282// to the compressed bytes of this descriptor. It is not exported, so
283// it is only valid inside the generated package.
284func (d *FileDescriptor) VarName() string {
285 name := strings.Map(badToUnderscore, baseName(d.GetName()))
286 return fmt.Sprintf("fileDescriptor_%s_%s", name, d.fingerprint)
287}
288
289// goPackageOption interprets the file's go_package option.
290// If there is no go_package, it returns ("", "", false).
291// If there's a simple name, it returns ("", pkg, true).
292// If the option implies an import path, it returns (impPath, pkg, true).
293func (d *FileDescriptor) goPackageOption() (impPath GoImportPath, pkg GoPackageName, ok bool) {
294 opt := d.GetOptions().GetGoPackage()
295 if opt == "" {
296 return "", "", false
297 }
298 // A semicolon-delimited suffix delimits the import path and package name.
299 sc := strings.Index(opt, ";")
300 if sc >= 0 {
301 return GoImportPath(opt[:sc]), cleanPackageName(opt[sc+1:]), true
302 }
303 // The presence of a slash implies there's an import path.
304 slash := strings.LastIndex(opt, "/")
305 if slash >= 0 {
306 return GoImportPath(opt), cleanPackageName(opt[slash+1:]), true
307 }
308 return "", cleanPackageName(opt), true
309}
310
311// goFileName returns the output name for the generated Go file.
312func (d *FileDescriptor) goFileName(pathType pathType) string {
313 name := *d.Name
314 if ext := path.Ext(name); ext == ".proto" || ext == ".protodevel" {
315 name = name[:len(name)-len(ext)]
316 }
317 name += ".pb.go"
318
319 if pathType == pathTypeSourceRelative {
320 return name
321 }
322
323 // Does the file have a "go_package" option?
324 // If it does, it may override the filename.
325 if impPath, _, ok := d.goPackageOption(); ok && impPath != "" {
326 // Replace the existing dirname with the declared import path.
327 _, name = path.Split(name)
328 name = path.Join(string(impPath), name)
329 return name
330 }
331
332 return name
333}
334
335func (d *FileDescriptor) addExport(obj Object, sym symbol) {
336 d.exported[obj] = append(d.exported[obj], sym)
337}
338
339// symbol is an interface representing an exported Go symbol.
340type symbol interface {
341 // GenerateAlias should generate an appropriate alias
342 // for the symbol from the named package.
343 GenerateAlias(g *Generator, pkg GoPackageName)
344}
345
346type messageSymbol struct {
347 sym string
348 hasExtensions, isMessageSet bool
349 oneofTypes []string
350}
351
352type getterSymbol struct {
353 name string
354 typ string
355 typeName string // canonical name in proto world; empty for proto.Message and similar
356 genType bool // whether typ contains a generated type (message/group/enum)
357}
358
359func (ms *messageSymbol) GenerateAlias(g *Generator, pkg GoPackageName) {
360 g.P("type ", ms.sym, " = ", pkg, ".", ms.sym)
361 for _, name := range ms.oneofTypes {
362 g.P("type ", name, " = ", pkg, ".", name)
363 }
364}
365
366type enumSymbol struct {
367 name string
368 proto3 bool // Whether this came from a proto3 file.
369}
370
371func (es enumSymbol) GenerateAlias(g *Generator, pkg GoPackageName) {
372 s := es.name
373 g.P("type ", s, " = ", pkg, ".", s)
374 g.P("var ", s, "_name = ", pkg, ".", s, "_name")
375 g.P("var ", s, "_value = ", pkg, ".", s, "_value")
376}
377
378type constOrVarSymbol struct {
379 sym string
380 typ string // either "const" or "var"
381 cast string // if non-empty, a type cast is required (used for enums)
382}
383
384func (cs constOrVarSymbol) GenerateAlias(g *Generator, pkg GoPackageName) {
385 v := string(pkg) + "." + cs.sym
386 if cs.cast != "" {
387 v = cs.cast + "(" + v + ")"
388 }
389 g.P(cs.typ, " ", cs.sym, " = ", v)
390}
391
392// Object is an interface abstracting the abilities shared by enums, messages, extensions and imported objects.
393type Object interface {
394 GoImportPath() GoImportPath
395 TypeName() []string
396 File() *FileDescriptor
397}
398
399// Generator is the type whose methods generate the output, stored in the associated response structure.
400type Generator struct {
401 *bytes.Buffer
402
403 Request *plugin.CodeGeneratorRequest // The input.
404 Response *plugin.CodeGeneratorResponse // The output.
405
406 Param map[string]string // Command-line parameters.
407 PackageImportPath string // Go import path of the package we're generating code for
408 ImportPrefix string // String to prefix to imported package file names.
409 ImportMap map[string]string // Mapping from .proto file name to import path
410
411 Pkg map[string]string // The names under which we import support packages
412
413 outputImportPath GoImportPath // Package we're generating code for.
414 allFiles []*FileDescriptor // All files in the tree
415 allFilesByName map[string]*FileDescriptor // All files by filename.
416 genFiles []*FileDescriptor // Those files we will generate output for.
417 file *FileDescriptor // The file we are compiling now.
418 packageNames map[GoImportPath]GoPackageName // Imported package names in the current file.
419 usedPackages map[GoImportPath]bool // Packages used in current file.
420 usedPackageNames map[GoPackageName]bool // Package names used in the current file.
421 typeNameToObject map[string]Object // Key is a fully-qualified name in input syntax.
422 init []string // Lines to emit in the init function.
423 indent string
424 pathType pathType // How to generate output filenames.
425 writeOutput bool
426 annotateCode bool // whether to store annotations
427 annotations []*descriptor.GeneratedCodeInfo_Annotation // annotations to store
428}
429
430type pathType int
431
432const (
433 pathTypeImport pathType = iota
434 pathTypeSourceRelative
435)
436
437// New creates a new generator and allocates the request and response protobufs.
438func New() *Generator {
439 g := new(Generator)
440 g.Buffer = new(bytes.Buffer)
441 g.Request = new(plugin.CodeGeneratorRequest)
442 g.Response = new(plugin.CodeGeneratorResponse)
443 return g
444}
445
446// Error reports a problem, including an error, and exits the program.
447func (g *Generator) Error(err error, msgs ...string) {
448 s := strings.Join(msgs, " ") + ":" + err.Error()
449 log.Print("protoc-gen-go: error:", s)
450 os.Exit(1)
451}
452
453// Fail reports a problem and exits the program.
454func (g *Generator) Fail(msgs ...string) {
455 s := strings.Join(msgs, " ")
456 log.Print("protoc-gen-go: error:", s)
457 os.Exit(1)
458}
459
460// CommandLineParameters breaks the comma-separated list of key=value pairs
461// in the parameter (a member of the request protobuf) into a key/value map.
462// It then sets file name mappings defined by those entries.
463func (g *Generator) CommandLineParameters(parameter string) {
464 g.Param = make(map[string]string)
465 for _, p := range strings.Split(parameter, ",") {
466 if i := strings.Index(p, "="); i < 0 {
467 g.Param[p] = ""
468 } else {
469 g.Param[p[0:i]] = p[i+1:]
470 }
471 }
472
473 g.ImportMap = make(map[string]string)
474 pluginList := "none" // Default list of plugin names to enable (empty means all).
475 for k, v := range g.Param {
476 switch k {
477 case "import_prefix":
478 g.ImportPrefix = v
479 case "import_path":
480 g.PackageImportPath = v
481 case "paths":
482 switch v {
483 case "import":
484 g.pathType = pathTypeImport
485 case "source_relative":
486 g.pathType = pathTypeSourceRelative
487 default:
488 g.Fail(fmt.Sprintf(`Unknown path type %q: want "import" or "source_relative".`, v))
489 }
490 case "plugins":
491 pluginList = v
492 case "annotate_code":
493 if v == "true" {
494 g.annotateCode = true
495 }
496 default:
497 if len(k) > 0 && k[0] == 'M' {
498 g.ImportMap[k[1:]] = v
499 }
500 }
501 }
502 if pluginList != "" {
503 // Amend the set of plugins.
504 enabled := make(map[string]bool)
505 for _, name := range strings.Split(pluginList, "+") {
506 enabled[name] = true
507 }
508 var nplugins []Plugin
509 for _, p := range plugins {
510 if enabled[p.Name()] {
511 nplugins = append(nplugins, p)
512 }
513 }
514 plugins = nplugins
515 }
516}
517
518// DefaultPackageName returns the package name printed for the object.
519// If its file is in a different package, it returns the package name we're using for this file, plus ".".
520// Otherwise it returns the empty string.
521func (g *Generator) DefaultPackageName(obj Object) string {
522 importPath := obj.GoImportPath()
523 if importPath == g.outputImportPath {
524 return ""
525 }
526 return string(g.GoPackageName(importPath)) + "."
527}
528
529// GoPackageName returns the name used for a package.
530func (g *Generator) GoPackageName(importPath GoImportPath) GoPackageName {
531 if name, ok := g.packageNames[importPath]; ok {
532 return name
533 }
534 name := cleanPackageName(baseName(string(importPath)))
535 for i, orig := 1, name; g.usedPackageNames[name]; i++ {
536 name = orig + GoPackageName(strconv.Itoa(i))
537 }
538 g.packageNames[importPath] = name
539 g.usedPackageNames[name] = true
540 return name
541}
542
543var globalPackageNames = map[GoPackageName]bool{
544 "fmt": true,
545 "math": true,
546 "proto": true,
547}
548
549// Create and remember a guaranteed unique package name. Pkg is the candidate name.
550// The FileDescriptor parameter is unused.
551func RegisterUniquePackageName(pkg string, f *FileDescriptor) string {
552 name := cleanPackageName(pkg)
553 for i, orig := 1, name; globalPackageNames[name]; i++ {
554 name = orig + GoPackageName(strconv.Itoa(i))
555 }
556 globalPackageNames[name] = true
557 return string(name)
558}
559
560var isGoKeyword = map[string]bool{
561 "break": true,
562 "case": true,
563 "chan": true,
564 "const": true,
565 "continue": true,
566 "default": true,
567 "else": true,
568 "defer": true,
569 "fallthrough": true,
570 "for": true,
571 "func": true,
572 "go": true,
573 "goto": true,
574 "if": true,
575 "import": true,
576 "interface": true,
577 "map": true,
578 "package": true,
579 "range": true,
580 "return": true,
581 "select": true,
582 "struct": true,
583 "switch": true,
584 "type": true,
585 "var": true,
586}
587
588func cleanPackageName(name string) GoPackageName {
589 name = strings.Map(badToUnderscore, name)
590 // Identifier must not be keyword: insert _.
591 if isGoKeyword[name] {
592 name = "_" + name
593 }
594 // Identifier must not begin with digit: insert _.
595 if r, _ := utf8.DecodeRuneInString(name); unicode.IsDigit(r) {
596 name = "_" + name
597 }
598 return GoPackageName(name)
599}
600
601// defaultGoPackage returns the package name to use,
602// derived from the import path of the package we're building code for.
603func (g *Generator) defaultGoPackage() GoPackageName {
604 p := g.PackageImportPath
605 if i := strings.LastIndex(p, "/"); i >= 0 {
606 p = p[i+1:]
607 }
608 return cleanPackageName(p)
609}
610
611// SetPackageNames sets the package name for this run.
612// The package name must agree across all files being generated.
613// It also defines unique package names for all imported files.
614func (g *Generator) SetPackageNames() {
615 g.outputImportPath = g.genFiles[0].importPath
616
617 defaultPackageNames := make(map[GoImportPath]GoPackageName)
618 for _, f := range g.genFiles {
619 if _, p, ok := f.goPackageOption(); ok {
620 defaultPackageNames[f.importPath] = p
621 }
622 }
623 for _, f := range g.genFiles {
624 if _, p, ok := f.goPackageOption(); ok {
625 // Source file: option go_package = "quux/bar";
626 f.packageName = p
627 } else if p, ok := defaultPackageNames[f.importPath]; ok {
628 // A go_package option in another file in the same package.
629 //
630 // This is a poor choice in general, since every source file should
631 // contain a go_package option. Supported mainly for historical
632 // compatibility.
633 f.packageName = p
634 } else if p := g.defaultGoPackage(); p != "" {
635 // Command-line: import_path=quux/bar.
636 //
637 // The import_path flag sets a package name for files which don't
638 // contain a go_package option.
639 f.packageName = p
640 } else if p := f.GetPackage(); p != "" {
641 // Source file: package quux.bar;
642 f.packageName = cleanPackageName(p)
643 } else {
644 // Source filename.
645 f.packageName = cleanPackageName(baseName(f.GetName()))
646 }
647 }
648
649 // Check that all files have a consistent package name and import path.
650 for _, f := range g.genFiles[1:] {
651 if a, b := g.genFiles[0].importPath, f.importPath; a != b {
652 g.Fail(fmt.Sprintf("inconsistent package import paths: %v, %v", a, b))
653 }
654 if a, b := g.genFiles[0].packageName, f.packageName; a != b {
655 g.Fail(fmt.Sprintf("inconsistent package names: %v, %v", a, b))
656 }
657 }
658
659 // Names of support packages. These never vary (if there are conflicts,
660 // we rename the conflicting package), so this could be removed someday.
661 g.Pkg = map[string]string{
662 "fmt": "fmt",
663 "math": "math",
664 "proto": "proto",
665 }
666}
667
668// WrapTypes walks the incoming data, wrapping DescriptorProtos, EnumDescriptorProtos
669// and FileDescriptorProtos into file-referenced objects within the Generator.
670// It also creates the list of files to generate and so should be called before GenerateAllFiles.
671func (g *Generator) WrapTypes() {
672 g.allFiles = make([]*FileDescriptor, 0, len(g.Request.ProtoFile))
673 g.allFilesByName = make(map[string]*FileDescriptor, len(g.allFiles))
674 genFileNames := make(map[string]bool)
675 for _, n := range g.Request.FileToGenerate {
676 genFileNames[n] = true
677 }
678 for _, f := range g.Request.ProtoFile {
679 fd := &FileDescriptor{
680 FileDescriptorProto: f,
681 exported: make(map[Object][]symbol),
682 proto3: fileIsProto3(f),
683 }
684 // The import path may be set in a number of ways.
685 if substitution, ok := g.ImportMap[f.GetName()]; ok {
686 // Command-line: M=foo.proto=quux/bar.
687 //
688 // Explicit mapping of source file to import path.
689 fd.importPath = GoImportPath(substitution)
690 } else if genFileNames[f.GetName()] && g.PackageImportPath != "" {
691 // Command-line: import_path=quux/bar.
692 //
693 // The import_path flag sets the import path for every file that
694 // we generate code for.
695 fd.importPath = GoImportPath(g.PackageImportPath)
696 } else if p, _, _ := fd.goPackageOption(); p != "" {
697 // Source file: option go_package = "quux/bar";
698 //
699 // The go_package option sets the import path. Most users should use this.
700 fd.importPath = p
701 } else {
702 // Source filename.
703 //
704 // Last resort when nothing else is available.
705 fd.importPath = GoImportPath(path.Dir(f.GetName()))
706 }
707 // We must wrap the descriptors before we wrap the enums
708 fd.desc = wrapDescriptors(fd)
709 g.buildNestedDescriptors(fd.desc)
710 fd.enum = wrapEnumDescriptors(fd, fd.desc)
711 g.buildNestedEnums(fd.desc, fd.enum)
712 fd.ext = wrapExtensions(fd)
713 extractComments(fd)
714 g.allFiles = append(g.allFiles, fd)
715 g.allFilesByName[f.GetName()] = fd
716 }
717 for _, fd := range g.allFiles {
718 fd.imp = wrapImported(fd, g)
719 }
720
721 g.genFiles = make([]*FileDescriptor, 0, len(g.Request.FileToGenerate))
722 for _, fileName := range g.Request.FileToGenerate {
723 fd := g.allFilesByName[fileName]
724 if fd == nil {
725 g.Fail("could not find file named", fileName)
726 }
727 fingerprint, err := fingerprintProto(fd.FileDescriptorProto)
728 if err != nil {
729 g.Error(err)
730 }
731 fd.fingerprint = fingerprint
732 g.genFiles = append(g.genFiles, fd)
733 }
734}
735
736// fingerprintProto returns a fingerprint for a message.
737// The fingerprint is intended to prevent conflicts between generated fileds,
738// not to provide cryptographic security.
739func fingerprintProto(m proto.Message) (string, error) {
740 b, err := proto.Marshal(m)
741 if err != nil {
742 return "", err
743 }
744 h := sha256.Sum256(b)
745 return hex.EncodeToString(h[:8]), nil
746}
747
748// Scan the descriptors in this file. For each one, build the slice of nested descriptors
749func (g *Generator) buildNestedDescriptors(descs []*Descriptor) {
750 for _, desc := range descs {
751 if len(desc.NestedType) != 0 {
752 for _, nest := range descs {
753 if nest.parent == desc {
754 desc.nested = append(desc.nested, nest)
755 }
756 }
757 if len(desc.nested) != len(desc.NestedType) {
758 g.Fail("internal error: nesting failure for", desc.GetName())
759 }
760 }
761 }
762}
763
764func (g *Generator) buildNestedEnums(descs []*Descriptor, enums []*EnumDescriptor) {
765 for _, desc := range descs {
766 if len(desc.EnumType) != 0 {
767 for _, enum := range enums {
768 if enum.parent == desc {
769 desc.enums = append(desc.enums, enum)
770 }
771 }
772 if len(desc.enums) != len(desc.EnumType) {
773 g.Fail("internal error: enum nesting failure for", desc.GetName())
774 }
775 }
776 }
777}
778
779// Construct the Descriptor
780func newDescriptor(desc *descriptor.DescriptorProto, parent *Descriptor, file *FileDescriptor, index int) *Descriptor {
781 d := &Descriptor{
782 common: common{file},
783 DescriptorProto: desc,
784 parent: parent,
785 index: index,
786 }
787 if parent == nil {
788 d.path = fmt.Sprintf("%d,%d", messagePath, index)
789 } else {
790 d.path = fmt.Sprintf("%s,%d,%d", parent.path, messageMessagePath, index)
791 }
792
793 // The only way to distinguish a group from a message is whether
794 // the containing message has a TYPE_GROUP field that matches.
795 if parent != nil {
796 parts := d.TypeName()
797 if file.Package != nil {
798 parts = append([]string{*file.Package}, parts...)
799 }
800 exp := "." + strings.Join(parts, ".")
801 for _, field := range parent.Field {
802 if field.GetType() == descriptor.FieldDescriptorProto_TYPE_GROUP && field.GetTypeName() == exp {
803 d.group = true
804 break
805 }
806 }
807 }
808
809 for _, field := range desc.Extension {
810 d.ext = append(d.ext, &ExtensionDescriptor{common{file}, field, d})
811 }
812
813 return d
814}
815
816// Return a slice of all the Descriptors defined within this file
817func wrapDescriptors(file *FileDescriptor) []*Descriptor {
818 sl := make([]*Descriptor, 0, len(file.MessageType)+10)
819 for i, desc := range file.MessageType {
820 sl = wrapThisDescriptor(sl, desc, nil, file, i)
821 }
822 return sl
823}
824
825// Wrap this Descriptor, recursively
826func wrapThisDescriptor(sl []*Descriptor, desc *descriptor.DescriptorProto, parent *Descriptor, file *FileDescriptor, index int) []*Descriptor {
827 sl = append(sl, newDescriptor(desc, parent, file, index))
828 me := sl[len(sl)-1]
829 for i, nested := range desc.NestedType {
830 sl = wrapThisDescriptor(sl, nested, me, file, i)
831 }
832 return sl
833}
834
835// Construct the EnumDescriptor
836func newEnumDescriptor(desc *descriptor.EnumDescriptorProto, parent *Descriptor, file *FileDescriptor, index int) *EnumDescriptor {
837 ed := &EnumDescriptor{
838 common: common{file},
839 EnumDescriptorProto: desc,
840 parent: parent,
841 index: index,
842 }
843 if parent == nil {
844 ed.path = fmt.Sprintf("%d,%d", enumPath, index)
845 } else {
846 ed.path = fmt.Sprintf("%s,%d,%d", parent.path, messageEnumPath, index)
847 }
848 return ed
849}
850
851// Return a slice of all the EnumDescriptors defined within this file
852func wrapEnumDescriptors(file *FileDescriptor, descs []*Descriptor) []*EnumDescriptor {
853 sl := make([]*EnumDescriptor, 0, len(file.EnumType)+10)
854 // Top-level enums.
855 for i, enum := range file.EnumType {
856 sl = append(sl, newEnumDescriptor(enum, nil, file, i))
857 }
858 // Enums within messages. Enums within embedded messages appear in the outer-most message.
859 for _, nested := range descs {
860 for i, enum := range nested.EnumType {
861 sl = append(sl, newEnumDescriptor(enum, nested, file, i))
862 }
863 }
864 return sl
865}
866
867// Return a slice of all the top-level ExtensionDescriptors defined within this file.
868func wrapExtensions(file *FileDescriptor) []*ExtensionDescriptor {
869 var sl []*ExtensionDescriptor
870 for _, field := range file.Extension {
871 sl = append(sl, &ExtensionDescriptor{common{file}, field, nil})
872 }
873 return sl
874}
875
876// Return a slice of all the types that are publicly imported into this file.
877func wrapImported(file *FileDescriptor, g *Generator) (sl []*ImportedDescriptor) {
878 for _, index := range file.PublicDependency {
879 df := g.fileByName(file.Dependency[index])
880 for _, d := range df.desc {
881 if d.GetOptions().GetMapEntry() {
882 continue
883 }
884 sl = append(sl, &ImportedDescriptor{common{file}, d})
885 }
886 for _, e := range df.enum {
887 sl = append(sl, &ImportedDescriptor{common{file}, e})
888 }
889 for _, ext := range df.ext {
890 sl = append(sl, &ImportedDescriptor{common{file}, ext})
891 }
892 }
893 return
894}
895
896func extractComments(file *FileDescriptor) {
897 file.comments = make(map[string]*descriptor.SourceCodeInfo_Location)
898 for _, loc := range file.GetSourceCodeInfo().GetLocation() {
899 if loc.LeadingComments == nil {
900 continue
901 }
902 var p []string
903 for _, n := range loc.Path {
904 p = append(p, strconv.Itoa(int(n)))
905 }
906 file.comments[strings.Join(p, ",")] = loc
907 }
908}
909
910// BuildTypeNameMap builds the map from fully qualified type names to objects.
911// The key names for the map come from the input data, which puts a period at the beginning.
912// It should be called after SetPackageNames and before GenerateAllFiles.
913func (g *Generator) BuildTypeNameMap() {
914 g.typeNameToObject = make(map[string]Object)
915 for _, f := range g.allFiles {
916 // The names in this loop are defined by the proto world, not us, so the
917 // package name may be empty. If so, the dotted package name of X will
918 // be ".X"; otherwise it will be ".pkg.X".
919 dottedPkg := "." + f.GetPackage()
920 if dottedPkg != "." {
921 dottedPkg += "."
922 }
923 for _, enum := range f.enum {
924 name := dottedPkg + dottedSlice(enum.TypeName())
925 g.typeNameToObject[name] = enum
926 }
927 for _, desc := range f.desc {
928 name := dottedPkg + dottedSlice(desc.TypeName())
929 g.typeNameToObject[name] = desc
930 }
931 }
932}
933
934// ObjectNamed, given a fully-qualified input type name as it appears in the input data,
935// returns the descriptor for the message or enum with that name.
936func (g *Generator) ObjectNamed(typeName string) Object {
937 o, ok := g.typeNameToObject[typeName]
938 if !ok {
939 g.Fail("can't find object with type", typeName)
940 }
941
942 // If the file of this object isn't a direct dependency of the current file,
943 // or in the current file, then this object has been publicly imported into
944 // a dependency of the current file.
945 // We should return the ImportedDescriptor object for it instead.
946 direct := *o.File().Name == *g.file.Name
947 if !direct {
948 for _, dep := range g.file.Dependency {
949 if *g.fileByName(dep).Name == *o.File().Name {
950 direct = true
951 break
952 }
953 }
954 }
955 if !direct {
956 found := false
957 Loop:
958 for _, dep := range g.file.Dependency {
959 df := g.fileByName(*g.fileByName(dep).Name)
960 for _, td := range df.imp {
961 if td.o == o {
962 // Found it!
963 o = td
964 found = true
965 break Loop
966 }
967 }
968 }
969 if !found {
970 log.Printf("protoc-gen-go: WARNING: failed finding publicly imported dependency for %v, used in %v", typeName, *g.file.Name)
971 }
972 }
973
974 return o
975}
976
977// AnnotatedAtoms is a list of atoms (as consumed by P) that records the file name and proto AST path from which they originated.
978type AnnotatedAtoms struct {
979 source string
980 path string
981 atoms []interface{}
982}
983
984// Annotate records the file name and proto AST path of a list of atoms
985// so that a later call to P can emit a link from each atom to its origin.
986func Annotate(file *FileDescriptor, path string, atoms ...interface{}) *AnnotatedAtoms {
987 return &AnnotatedAtoms{source: *file.Name, path: path, atoms: atoms}
988}
989
990// printAtom prints the (atomic, non-annotation) argument to the generated output.
991func (g *Generator) printAtom(v interface{}) {
992 switch v := v.(type) {
993 case string:
994 g.WriteString(v)
995 case *string:
996 g.WriteString(*v)
997 case bool:
998 fmt.Fprint(g, v)
999 case *bool:
1000 fmt.Fprint(g, *v)
1001 case int:
1002 fmt.Fprint(g, v)
1003 case *int32:
1004 fmt.Fprint(g, *v)
1005 case *int64:
1006 fmt.Fprint(g, *v)
1007 case float64:
1008 fmt.Fprint(g, v)
1009 case *float64:
1010 fmt.Fprint(g, *v)
1011 case GoPackageName:
1012 g.WriteString(string(v))
1013 case GoImportPath:
1014 g.WriteString(strconv.Quote(string(v)))
1015 default:
1016 g.Fail(fmt.Sprintf("unknown type in printer: %T", v))
1017 }
1018}
1019
1020// P prints the arguments to the generated output. It handles strings and int32s, plus
1021// handling indirections because they may be *string, etc. Any inputs of type AnnotatedAtoms may emit
1022// annotations in a .meta file in addition to outputting the atoms themselves (if g.annotateCode
1023// is true).
1024func (g *Generator) P(str ...interface{}) {
1025 if !g.writeOutput {
1026 return
1027 }
1028 g.WriteString(g.indent)
1029 for _, v := range str {
1030 switch v := v.(type) {
1031 case *AnnotatedAtoms:
1032 begin := int32(g.Len())
1033 for _, v := range v.atoms {
1034 g.printAtom(v)
1035 }
1036 if g.annotateCode {
1037 end := int32(g.Len())
1038 var path []int32
1039 for _, token := range strings.Split(v.path, ",") {
1040 val, err := strconv.ParseInt(token, 10, 32)
1041 if err != nil {
1042 g.Fail("could not parse proto AST path: ", err.Error())
1043 }
1044 path = append(path, int32(val))
1045 }
1046 g.annotations = append(g.annotations, &descriptor.GeneratedCodeInfo_Annotation{
1047 Path: path,
1048 SourceFile: &v.source,
1049 Begin: &begin,
1050 End: &end,
1051 })
1052 }
1053 default:
1054 g.printAtom(v)
1055 }
1056 }
1057 g.WriteByte('\n')
1058}
1059
1060// addInitf stores the given statement to be printed inside the file's init function.
1061// The statement is given as a format specifier and arguments.
1062func (g *Generator) addInitf(stmt string, a ...interface{}) {
1063 g.init = append(g.init, fmt.Sprintf(stmt, a...))
1064}
1065
1066// In Indents the output one tab stop.
1067func (g *Generator) In() { g.indent += "\t" }
1068
1069// Out unindents the output one tab stop.
1070func (g *Generator) Out() {
1071 if len(g.indent) > 0 {
1072 g.indent = g.indent[1:]
1073 }
1074}
1075
1076// GenerateAllFiles generates the output for all the files we're outputting.
1077func (g *Generator) GenerateAllFiles() {
1078 // Initialize the plugins
1079 for _, p := range plugins {
1080 p.Init(g)
1081 }
1082 // Generate the output. The generator runs for every file, even the files
1083 // that we don't generate output for, so that we can collate the full list
1084 // of exported symbols to support public imports.
1085 genFileMap := make(map[*FileDescriptor]bool, len(g.genFiles))
1086 for _, file := range g.genFiles {
1087 genFileMap[file] = true
1088 }
1089 for _, file := range g.allFiles {
1090 g.Reset()
1091 g.annotations = nil
1092 g.writeOutput = genFileMap[file]
1093 g.generate(file)
1094 if !g.writeOutput {
1095 continue
1096 }
1097 fname := file.goFileName(g.pathType)
1098 g.Response.File = append(g.Response.File, &plugin.CodeGeneratorResponse_File{
1099 Name: proto.String(fname),
1100 Content: proto.String(g.String()),
1101 })
1102 if g.annotateCode {
1103 // Store the generated code annotations in text, as the protoc plugin protocol requires that
1104 // strings contain valid UTF-8.
1105 g.Response.File = append(g.Response.File, &plugin.CodeGeneratorResponse_File{
1106 Name: proto.String(file.goFileName(g.pathType) + ".meta"),
1107 Content: proto.String(proto.CompactTextString(&descriptor.GeneratedCodeInfo{Annotation: g.annotations})),
1108 })
1109 }
1110 }
1111}
1112
1113// Run all the plugins associated with the file.
1114func (g *Generator) runPlugins(file *FileDescriptor) {
1115 for _, p := range plugins {
1116 p.Generate(file)
1117 }
1118}
1119
1120// Fill the response protocol buffer with the generated output for all the files we're
1121// supposed to generate.
1122func (g *Generator) generate(file *FileDescriptor) {
1123 g.file = file
1124 g.usedPackages = make(map[GoImportPath]bool)
1125 g.packageNames = make(map[GoImportPath]GoPackageName)
1126 g.usedPackageNames = make(map[GoPackageName]bool)
1127 for name := range globalPackageNames {
1128 g.usedPackageNames[name] = true
1129 }
1130
1131 g.P("// This is a compile-time assertion to ensure that this generated file")
1132 g.P("// is compatible with the proto package it is being compiled against.")
1133 g.P("// A compilation error at this line likely means your copy of the")
1134 g.P("// proto package needs to be updated.")
1135 g.P("const _ = ", g.Pkg["proto"], ".ProtoPackageIsVersion", generatedCodeVersion, " // please upgrade the proto package")
1136 g.P()
1137
1138 for _, td := range g.file.imp {
1139 g.generateImported(td)
1140 }
1141 for _, enum := range g.file.enum {
1142 g.generateEnum(enum)
1143 }
1144 for _, desc := range g.file.desc {
1145 // Don't generate virtual messages for maps.
1146 if desc.GetOptions().GetMapEntry() {
1147 continue
1148 }
1149 g.generateMessage(desc)
1150 }
1151 for _, ext := range g.file.ext {
1152 g.generateExtension(ext)
1153 }
1154 g.generateInitFunction()
1155
1156 // Run the plugins before the imports so we know which imports are necessary.
1157 g.runPlugins(file)
1158
1159 g.generateFileDescriptor(file)
1160
1161 // Generate header and imports last, though they appear first in the output.
1162 rem := g.Buffer
1163 remAnno := g.annotations
1164 g.Buffer = new(bytes.Buffer)
1165 g.annotations = nil
1166 g.generateHeader()
1167 g.generateImports()
1168 if !g.writeOutput {
1169 return
1170 }
1171 // Adjust the offsets for annotations displaced by the header and imports.
1172 for _, anno := range remAnno {
1173 *anno.Begin += int32(g.Len())
1174 *anno.End += int32(g.Len())
1175 g.annotations = append(g.annotations, anno)
1176 }
1177 g.Write(rem.Bytes())
1178
1179 // Reformat generated code and patch annotation locations.
1180 fset := token.NewFileSet()
1181 original := g.Bytes()
1182 if g.annotateCode {
1183 // make a copy independent of g; we'll need it after Reset.
1184 original = append([]byte(nil), original...)
1185 }
1186 ast, err := parser.ParseFile(fset, "", original, parser.ParseComments)
1187 if err != nil {
1188 // Print out the bad code with line numbers.
1189 // This should never happen in practice, but it can while changing generated code,
1190 // so consider this a debugging aid.
1191 var src bytes.Buffer
1192 s := bufio.NewScanner(bytes.NewReader(original))
1193 for line := 1; s.Scan(); line++ {
1194 fmt.Fprintf(&src, "%5d\t%s\n", line, s.Bytes())
1195 }
1196 g.Fail("bad Go source code was generated:", err.Error(), "\n"+src.String())
1197 }
1198 g.Reset()
1199 err = (&printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}).Fprint(g, fset, ast)
1200 if err != nil {
1201 g.Fail("generated Go source code could not be reformatted:", err.Error())
1202 }
1203 if g.annotateCode {
1204 m, err := remap.Compute(original, g.Bytes())
1205 if err != nil {
1206 g.Fail("formatted generated Go source code could not be mapped back to the original code:", err.Error())
1207 }
1208 for _, anno := range g.annotations {
1209 new, ok := m.Find(int(*anno.Begin), int(*anno.End))
1210 if !ok {
1211 g.Fail("span in formatted generated Go source code could not be mapped back to the original code")
1212 }
1213 *anno.Begin = int32(new.Pos)
1214 *anno.End = int32(new.End)
1215 }
1216 }
1217}
1218
1219// Generate the header, including package definition
1220func (g *Generator) generateHeader() {
1221 g.P("// Code generated by protoc-gen-go. DO NOT EDIT.")
1222 if g.file.GetOptions().GetDeprecated() {
1223 g.P("// ", g.file.Name, " is a deprecated file.")
1224 } else {
1225 g.P("// source: ", g.file.Name)
1226 }
1227 g.P()
1228
1229 importPath, _, _ := g.file.goPackageOption()
1230 if importPath == "" {
1231 g.P("package ", g.file.packageName)
1232 } else {
1233 g.P("package ", g.file.packageName, " // import ", GoImportPath(g.ImportPrefix)+importPath)
1234 }
1235 g.P()
1236
1237 if loc, ok := g.file.comments[strconv.Itoa(packagePath)]; ok {
1238 g.P("/*")
1239 // not using g.PrintComments because this is a /* */ comment block.
1240 text := strings.TrimSuffix(loc.GetLeadingComments(), "\n")
1241 for _, line := range strings.Split(text, "\n") {
1242 line = strings.TrimPrefix(line, " ")
1243 // ensure we don't escape from the block comment
1244 line = strings.Replace(line, "*/", "* /", -1)
1245 g.P(line)
1246 }
1247 g.P("*/")
1248 g.P()
1249 }
1250}
1251
1252// deprecationComment is the standard comment added to deprecated
1253// messages, fields, enums, and enum values.
1254var deprecationComment = "// Deprecated: Do not use."
1255
1256// PrintComments prints any comments from the source .proto file.
1257// The path is a comma-separated list of integers.
1258// It returns an indication of whether any comments were printed.
1259// See descriptor.proto for its format.
1260func (g *Generator) PrintComments(path string) bool {
1261 if !g.writeOutput {
1262 return false
1263 }
1264 if c, ok := g.makeComments(path); ok {
1265 g.P(c)
1266 return true
1267 }
1268 return false
1269}
1270
1271// makeComments generates the comment string for the field, no "\n" at the end
1272func (g *Generator) makeComments(path string) (string, bool) {
1273 loc, ok := g.file.comments[path]
1274 if !ok {
1275 return "", false
1276 }
1277 w := new(bytes.Buffer)
1278 nl := ""
1279 for _, line := range strings.Split(strings.TrimSuffix(loc.GetLeadingComments(), "\n"), "\n") {
1280 fmt.Fprintf(w, "%s// %s", nl, strings.TrimPrefix(line, " "))
1281 nl = "\n"
1282 }
1283 return w.String(), true
1284}
1285
1286func (g *Generator) fileByName(filename string) *FileDescriptor {
1287 return g.allFilesByName[filename]
1288}
1289
1290// weak returns whether the ith import of the current file is a weak import.
1291func (g *Generator) weak(i int32) bool {
1292 for _, j := range g.file.WeakDependency {
1293 if j == i {
1294 return true
1295 }
1296 }
1297 return false
1298}
1299
1300// Generate the imports
1301func (g *Generator) generateImports() {
1302 // We almost always need a proto import. Rather than computing when we
1303 // do, which is tricky when there's a plugin, just import it and
1304 // reference it later. The same argument applies to the fmt and math packages.
1305 g.P("import "+g.Pkg["proto"]+" ", GoImportPath(g.ImportPrefix)+"github.com/golang/protobuf/proto")
1306 g.P("import " + g.Pkg["fmt"] + ` "fmt"`)
1307 g.P("import " + g.Pkg["math"] + ` "math"`)
1308 var (
1309 imports = make(map[GoImportPath]bool)
1310 strongImports = make(map[GoImportPath]bool)
1311 importPaths []string
1312 )
1313 for i, s := range g.file.Dependency {
1314 fd := g.fileByName(s)
1315 importPath := fd.importPath
1316 // Do not import our own package.
1317 if importPath == g.file.importPath {
1318 continue
1319 }
1320 if !imports[importPath] {
1321 importPaths = append(importPaths, string(importPath))
1322 }
1323 imports[importPath] = true
1324 if !g.weak(int32(i)) {
1325 strongImports[importPath] = true
1326 }
1327 }
1328 sort.Strings(importPaths)
1329 for i := range importPaths {
1330 importPath := GoImportPath(importPaths[i])
1331 packageName := g.GoPackageName(importPath)
1332 fullPath := GoImportPath(g.ImportPrefix) + importPath
1333 // Skip weak imports.
1334 if !strongImports[importPath] {
1335 g.P("// skipping weak import ", packageName, " ", fullPath)
1336 continue
1337 }
1338 // We need to import all the dependencies, even if we don't reference them,
1339 // because other code and tools depend on having the full transitive closure
1340 // of protocol buffer types in the binary.
1341 if _, ok := g.usedPackages[importPath]; !ok {
1342 packageName = "_"
1343 }
1344 g.P("import ", packageName, " ", fullPath)
1345 }
1346 g.P()
1347 // TODO: may need to worry about uniqueness across plugins
1348 for _, p := range plugins {
1349 p.GenerateImports(g.file)
1350 g.P()
1351 }
1352 g.P("// Reference imports to suppress errors if they are not otherwise used.")
1353 g.P("var _ = ", g.Pkg["proto"], ".Marshal")
1354 g.P("var _ = ", g.Pkg["fmt"], ".Errorf")
1355 g.P("var _ = ", g.Pkg["math"], ".Inf")
1356 g.P()
1357}
1358
1359func (g *Generator) generateImported(id *ImportedDescriptor) {
1360 tn := id.TypeName()
1361 sn := tn[len(tn)-1]
1362 df := id.o.File()
1363 filename := *df.Name
1364 if df.importPath == g.file.importPath {
1365 // Don't generate type aliases for files in the same Go package as this one.
1366 g.P("// Ignoring public import of ", sn, " from ", filename)
1367 g.P()
1368 return
1369 }
1370 if !supportTypeAliases {
1371 g.Fail(fmt.Sprintf("%s: public imports require at least go1.9", filename))
1372 }
1373 g.P("// ", sn, " from public import ", filename)
1374 g.usedPackages[df.importPath] = true
1375
1376 for _, sym := range df.exported[id.o] {
1377 sym.GenerateAlias(g, g.GoPackageName(df.importPath))
1378 }
1379
1380 g.P()
1381}
1382
1383// Generate the enum definitions for this EnumDescriptor.
1384func (g *Generator) generateEnum(enum *EnumDescriptor) {
1385 // The full type name
1386 typeName := enum.TypeName()
1387 // The full type name, CamelCased.
1388 ccTypeName := CamelCaseSlice(typeName)
1389 ccPrefix := enum.prefix()
1390
1391 deprecatedEnum := ""
1392 if enum.GetOptions().GetDeprecated() {
1393 deprecatedEnum = deprecationComment
1394 }
1395 g.PrintComments(enum.path)
1396 g.P("type ", Annotate(enum.file, enum.path, ccTypeName), " int32", deprecatedEnum)
1397 g.file.addExport(enum, enumSymbol{ccTypeName, enum.proto3()})
1398 g.P("const (")
1399 for i, e := range enum.Value {
1400 etorPath := fmt.Sprintf("%s,%d,%d", enum.path, enumValuePath, i)
1401 g.PrintComments(etorPath)
1402
1403 deprecatedValue := ""
1404 if e.GetOptions().GetDeprecated() {
1405 deprecatedValue = deprecationComment
1406 }
1407
1408 name := ccPrefix + *e.Name
1409 g.P(Annotate(enum.file, etorPath, name), " ", ccTypeName, " = ", e.Number, " ", deprecatedValue)
1410 g.file.addExport(enum, constOrVarSymbol{name, "const", ccTypeName})
1411 }
1412 g.P(")")
1413 g.P("var ", ccTypeName, "_name = map[int32]string{")
1414 generated := make(map[int32]bool) // avoid duplicate values
1415 for _, e := range enum.Value {
1416 duplicate := ""
1417 if _, present := generated[*e.Number]; present {
1418 duplicate = "// Duplicate value: "
1419 }
1420 g.P(duplicate, e.Number, ": ", strconv.Quote(*e.Name), ",")
1421 generated[*e.Number] = true
1422 }
1423 g.P("}")
1424 g.P("var ", ccTypeName, "_value = map[string]int32{")
1425 for _, e := range enum.Value {
1426 g.P(strconv.Quote(*e.Name), ": ", e.Number, ",")
1427 }
1428 g.P("}")
1429
1430 if !enum.proto3() {
1431 g.P("func (x ", ccTypeName, ") Enum() *", ccTypeName, " {")
1432 g.P("p := new(", ccTypeName, ")")
1433 g.P("*p = x")
1434 g.P("return p")
1435 g.P("}")
1436 }
1437
1438 g.P("func (x ", ccTypeName, ") String() string {")
1439 g.P("return ", g.Pkg["proto"], ".EnumName(", ccTypeName, "_name, int32(x))")
1440 g.P("}")
1441
1442 if !enum.proto3() {
1443 g.P("func (x *", ccTypeName, ") UnmarshalJSON(data []byte) error {")
1444 g.P("value, err := ", g.Pkg["proto"], ".UnmarshalJSONEnum(", ccTypeName, `_value, data, "`, ccTypeName, `")`)
1445 g.P("if err != nil {")
1446 g.P("return err")
1447 g.P("}")
1448 g.P("*x = ", ccTypeName, "(value)")
1449 g.P("return nil")
1450 g.P("}")
1451 }
1452
1453 var indexes []string
1454 for m := enum.parent; m != nil; m = m.parent {
1455 // XXX: skip groups?
1456 indexes = append([]string{strconv.Itoa(m.index)}, indexes...)
1457 }
1458 indexes = append(indexes, strconv.Itoa(enum.index))
1459 g.P("func (", ccTypeName, ") EnumDescriptor() ([]byte, []int) {")
1460 g.P("return ", g.file.VarName(), ", []int{", strings.Join(indexes, ", "), "}")
1461 g.P("}")
1462 if enum.file.GetPackage() == "google.protobuf" && enum.GetName() == "NullValue" {
1463 g.P("func (", ccTypeName, `) XXX_WellKnownType() string { return "`, enum.GetName(), `" }`)
1464 }
1465
1466 g.P()
1467}
1468
1469// The tag is a string like "varint,2,opt,name=fieldname,def=7" that
1470// identifies details of the field for the protocol buffer marshaling and unmarshaling
1471// code. The fields are:
1472// wire encoding
1473// protocol tag number
1474// opt,req,rep for optional, required, or repeated
1475// packed whether the encoding is "packed" (optional; repeated primitives only)
1476// name= the original declared name
1477// enum= the name of the enum type if it is an enum-typed field.
1478// proto3 if this field is in a proto3 message
1479// def= string representation of the default value, if any.
1480// The default value must be in a representation that can be used at run-time
1481// to generate the default value. Thus bools become 0 and 1, for instance.
1482func (g *Generator) goTag(message *Descriptor, field *descriptor.FieldDescriptorProto, wiretype string) string {
1483 optrepreq := ""
1484 switch {
1485 case isOptional(field):
1486 optrepreq = "opt"
1487 case isRequired(field):
1488 optrepreq = "req"
1489 case isRepeated(field):
1490 optrepreq = "rep"
1491 }
1492 var defaultValue string
1493 if dv := field.DefaultValue; dv != nil { // set means an explicit default
1494 defaultValue = *dv
1495 // Some types need tweaking.
1496 switch *field.Type {
1497 case descriptor.FieldDescriptorProto_TYPE_BOOL:
1498 if defaultValue == "true" {
1499 defaultValue = "1"
1500 } else {
1501 defaultValue = "0"
1502 }
1503 case descriptor.FieldDescriptorProto_TYPE_STRING,
1504 descriptor.FieldDescriptorProto_TYPE_BYTES:
1505 // Nothing to do. Quoting is done for the whole tag.
1506 case descriptor.FieldDescriptorProto_TYPE_ENUM:
1507 // For enums we need to provide the integer constant.
1508 obj := g.ObjectNamed(field.GetTypeName())
1509 if id, ok := obj.(*ImportedDescriptor); ok {
1510 // It is an enum that was publicly imported.
1511 // We need the underlying type.
1512 obj = id.o
1513 }
1514 enum, ok := obj.(*EnumDescriptor)
1515 if !ok {
1516 log.Printf("obj is a %T", obj)
1517 if id, ok := obj.(*ImportedDescriptor); ok {
1518 log.Printf("id.o is a %T", id.o)
1519 }
1520 g.Fail("unknown enum type", CamelCaseSlice(obj.TypeName()))
1521 }
1522 defaultValue = enum.integerValueAsString(defaultValue)
1523 }
1524 defaultValue = ",def=" + defaultValue
1525 }
1526 enum := ""
1527 if *field.Type == descriptor.FieldDescriptorProto_TYPE_ENUM {
1528 // We avoid using obj.GoPackageName(), because we want to use the
1529 // original (proto-world) package name.
1530 obj := g.ObjectNamed(field.GetTypeName())
1531 if id, ok := obj.(*ImportedDescriptor); ok {
1532 obj = id.o
1533 }
1534 enum = ",enum="
1535 if pkg := obj.File().GetPackage(); pkg != "" {
1536 enum += pkg + "."
1537 }
1538 enum += CamelCaseSlice(obj.TypeName())
1539 }
1540 packed := ""
1541 if (field.Options != nil && field.Options.GetPacked()) ||
1542 // Per https://developers.google.com/protocol-buffers/docs/proto3#simple:
1543 // "In proto3, repeated fields of scalar numeric types use packed encoding by default."
1544 (message.proto3() && (field.Options == nil || field.Options.Packed == nil) &&
1545 isRepeated(field) && isScalar(field)) {
1546 packed = ",packed"
1547 }
1548 fieldName := field.GetName()
1549 name := fieldName
1550 if *field.Type == descriptor.FieldDescriptorProto_TYPE_GROUP {
1551 // We must use the type name for groups instead of
1552 // the field name to preserve capitalization.
1553 // type_name in FieldDescriptorProto is fully-qualified,
1554 // but we only want the local part.
1555 name = *field.TypeName
1556 if i := strings.LastIndex(name, "."); i >= 0 {
1557 name = name[i+1:]
1558 }
1559 }
1560 if json := field.GetJsonName(); json != "" && json != name {
1561 // TODO: escaping might be needed, in which case
1562 // perhaps this should be in its own "json" tag.
1563 name += ",json=" + json
1564 }
1565 name = ",name=" + name
1566 if message.proto3() {
1567 name += ",proto3"
1568 }
1569 oneof := ""
1570 if field.OneofIndex != nil {
1571 oneof = ",oneof"
1572 }
1573 return strconv.Quote(fmt.Sprintf("%s,%d,%s%s%s%s%s%s",
1574 wiretype,
1575 field.GetNumber(),
1576 optrepreq,
1577 packed,
1578 name,
1579 enum,
1580 oneof,
1581 defaultValue))
1582}
1583
1584func needsStar(typ descriptor.FieldDescriptorProto_Type) bool {
1585 switch typ {
1586 case descriptor.FieldDescriptorProto_TYPE_GROUP:
1587 return false
1588 case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
1589 return false
1590 case descriptor.FieldDescriptorProto_TYPE_BYTES:
1591 return false
1592 }
1593 return true
1594}
1595
1596// TypeName is the printed name appropriate for an item. If the object is in the current file,
1597// TypeName drops the package name and underscores the rest.
1598// Otherwise the object is from another package; and the result is the underscored
1599// package name followed by the item name.
1600// The result always has an initial capital.
1601func (g *Generator) TypeName(obj Object) string {
1602 return g.DefaultPackageName(obj) + CamelCaseSlice(obj.TypeName())
1603}
1604
1605// GoType returns a string representing the type name, and the wire type
1606func (g *Generator) GoType(message *Descriptor, field *descriptor.FieldDescriptorProto) (typ string, wire string) {
1607 // TODO: Options.
1608 switch *field.Type {
1609 case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
1610 typ, wire = "float64", "fixed64"
1611 case descriptor.FieldDescriptorProto_TYPE_FLOAT:
1612 typ, wire = "float32", "fixed32"
1613 case descriptor.FieldDescriptorProto_TYPE_INT64:
1614 typ, wire = "int64", "varint"
1615 case descriptor.FieldDescriptorProto_TYPE_UINT64:
1616 typ, wire = "uint64", "varint"
1617 case descriptor.FieldDescriptorProto_TYPE_INT32:
1618 typ, wire = "int32", "varint"
1619 case descriptor.FieldDescriptorProto_TYPE_UINT32:
1620 typ, wire = "uint32", "varint"
1621 case descriptor.FieldDescriptorProto_TYPE_FIXED64:
1622 typ, wire = "uint64", "fixed64"
1623 case descriptor.FieldDescriptorProto_TYPE_FIXED32:
1624 typ, wire = "uint32", "fixed32"
1625 case descriptor.FieldDescriptorProto_TYPE_BOOL:
1626 typ, wire = "bool", "varint"
1627 case descriptor.FieldDescriptorProto_TYPE_STRING:
1628 typ, wire = "string", "bytes"
1629 case descriptor.FieldDescriptorProto_TYPE_GROUP:
1630 desc := g.ObjectNamed(field.GetTypeName())
1631 typ, wire = "*"+g.TypeName(desc), "group"
1632 case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
1633 desc := g.ObjectNamed(field.GetTypeName())
1634 typ, wire = "*"+g.TypeName(desc), "bytes"
1635 case descriptor.FieldDescriptorProto_TYPE_BYTES:
1636 typ, wire = "[]byte", "bytes"
1637 case descriptor.FieldDescriptorProto_TYPE_ENUM:
1638 desc := g.ObjectNamed(field.GetTypeName())
1639 typ, wire = g.TypeName(desc), "varint"
1640 case descriptor.FieldDescriptorProto_TYPE_SFIXED32:
1641 typ, wire = "int32", "fixed32"
1642 case descriptor.FieldDescriptorProto_TYPE_SFIXED64:
1643 typ, wire = "int64", "fixed64"
1644 case descriptor.FieldDescriptorProto_TYPE_SINT32:
1645 typ, wire = "int32", "zigzag32"
1646 case descriptor.FieldDescriptorProto_TYPE_SINT64:
1647 typ, wire = "int64", "zigzag64"
1648 default:
1649 g.Fail("unknown type for", field.GetName())
1650 }
1651 if isRepeated(field) {
1652 typ = "[]" + typ
1653 } else if message != nil && message.proto3() {
1654 return
1655 } else if field.OneofIndex != nil && message != nil {
1656 return
1657 } else if needsStar(*field.Type) {
1658 typ = "*" + typ
1659 }
1660 return
1661}
1662
1663func (g *Generator) RecordTypeUse(t string) {
1664 if _, ok := g.typeNameToObject[t]; ok {
1665 // Call ObjectNamed to get the true object to record the use.
1666 obj := g.ObjectNamed(t)
1667 g.usedPackages[obj.GoImportPath()] = true
1668 }
1669}
1670
1671// Method names that may be generated. Fields with these names get an
1672// underscore appended. Any change to this set is a potential incompatible
1673// API change because it changes generated field names.
1674var methodNames = [...]string{
1675 "Reset",
1676 "String",
1677 "ProtoMessage",
1678 "Marshal",
1679 "Unmarshal",
1680 "ExtensionRangeArray",
1681 "ExtensionMap",
1682 "Descriptor",
1683}
1684
1685// Names of messages in the `google.protobuf` package for which
1686// we will generate XXX_WellKnownType methods.
1687var wellKnownTypes = map[string]bool{
1688 "Any": true,
1689 "Duration": true,
1690 "Empty": true,
1691 "Struct": true,
1692 "Timestamp": true,
1693
1694 "Value": true,
1695 "ListValue": true,
1696 "DoubleValue": true,
1697 "FloatValue": true,
1698 "Int64Value": true,
1699 "UInt64Value": true,
1700 "Int32Value": true,
1701 "UInt32Value": true,
1702 "BoolValue": true,
1703 "StringValue": true,
1704 "BytesValue": true,
1705}
1706
1707// getterDefault finds the default value for the field to return from a getter,
1708// regardless of if it's a built in default or explicit from the source. Returns e.g. "nil", `""`, "Default_MessageType_FieldName"
1709func (g *Generator) getterDefault(field *descriptor.FieldDescriptorProto, goMessageType string) string {
1710 if isRepeated(field) {
1711 return "nil"
1712 }
1713 if def := field.GetDefaultValue(); def != "" {
1714 defaultConstant := g.defaultConstantName(goMessageType, field.GetName())
1715 if *field.Type != descriptor.FieldDescriptorProto_TYPE_BYTES {
1716 return defaultConstant
1717 }
1718 return "append([]byte(nil), " + defaultConstant + "...)"
1719 }
1720 switch *field.Type {
1721 case descriptor.FieldDescriptorProto_TYPE_BOOL:
1722 return "false"
1723 case descriptor.FieldDescriptorProto_TYPE_STRING:
1724 return `""`
1725 case descriptor.FieldDescriptorProto_TYPE_GROUP, descriptor.FieldDescriptorProto_TYPE_MESSAGE, descriptor.FieldDescriptorProto_TYPE_BYTES:
1726 return "nil"
1727 case descriptor.FieldDescriptorProto_TYPE_ENUM:
1728 obj := g.ObjectNamed(field.GetTypeName())
1729 var enum *EnumDescriptor
1730 if id, ok := obj.(*ImportedDescriptor); ok {
1731 // The enum type has been publicly imported.
1732 enum, _ = id.o.(*EnumDescriptor)
1733 } else {
1734 enum, _ = obj.(*EnumDescriptor)
1735 }
1736 if enum == nil {
1737 log.Printf("don't know how to generate getter for %s", field.GetName())
1738 return "nil"
1739 }
1740 if len(enum.Value) == 0 {
1741 return "0 // empty enum"
1742 }
1743 first := enum.Value[0].GetName()
1744 return g.DefaultPackageName(obj) + enum.prefix() + first
1745 default:
1746 return "0"
1747 }
1748}
1749
1750// defaultConstantName builds the name of the default constant from the message
1751// type name and the untouched field name, e.g. "Default_MessageType_FieldName"
1752func (g *Generator) defaultConstantName(goMessageType, protoFieldName string) string {
1753 return "Default_" + goMessageType + "_" + CamelCase(protoFieldName)
1754}
1755
1756// The different types of fields in a message and how to actually print them
1757// Most of the logic for generateMessage is in the methods of these types.
1758//
1759// Note that the content of the field is irrelevant, a simpleField can contain
1760// anything from a scalar to a group (which is just a message).
1761//
1762// Extension fields (and message sets) are however handled separately.
1763//
1764// simpleField - a field that is neiter weak nor oneof, possibly repeated
1765// oneofField - field containing list of subfields:
1766// - oneofSubField - a field within the oneof
1767
1768// msgCtx contais the context for the generator functions.
1769type msgCtx struct {
1770 goName string // Go struct name of the message, e.g. MessageName
1771 message *Descriptor // The descriptor for the message
1772}
1773
1774// fieldCommon contains data common to all types of fields.
1775type fieldCommon struct {
1776 goName string // Go name of field, e.g. "FieldName" or "Descriptor_"
1777 protoName string // Name of field in proto language, e.g. "field_name" or "descriptor"
1778 getterName string // Name of the getter, e.g. "GetFieldName" or "GetDescriptor_"
1779 goType string // The Go type as a string, e.g. "*int32" or "*OtherMessage"
1780 tags string // The tag string/annotation for the type, e.g. `protobuf:"varint,8,opt,name=region_id,json=regionId"`
1781 fullPath string // The full path of the field as used by Annotate etc, e.g. "4,0,2,0"
1782}
1783
1784// getProtoName gets the proto name of a field, e.g. "field_name" or "descriptor".
1785func (f *fieldCommon) getProtoName() string {
1786 return f.protoName
1787}
1788
1789// getGoType returns the go type of the field as a string, e.g. "*int32".
1790func (f *fieldCommon) getGoType() string {
1791 return f.goType
1792}
1793
1794// simpleField is not weak, not a oneof, not an extension. Can be required, optional or repeated.
1795type simpleField struct {
1796 fieldCommon
1797 protoTypeName string // Proto type name, empty if primitive, e.g. ".google.protobuf.Duration"
1798 protoType descriptor.FieldDescriptorProto_Type // Actual type enum value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64
1799 deprecated string // Deprecation comment, if any, e.g. "// Deprecated: Do not use."
1800 getterDef string // Default for getters, e.g. "nil", `""` or "Default_MessageType_FieldName"
1801 protoDef string // Default value as defined in the proto file, e.g "yoshi" or "5"
1802 comment string // The full comment for the field, e.g. "// Useful information"
1803}
1804
1805// decl prints the declaration of the field in the struct (if any).
1806func (f *simpleField) decl(g *Generator, mc *msgCtx) {
1807 g.P(f.comment, Annotate(mc.message.file, f.fullPath, f.goName), "\t", f.goType, "\t`", f.tags, "`", f.deprecated)
1808}
1809
1810// getter prints the getter for the field.
1811func (f *simpleField) getter(g *Generator, mc *msgCtx) {
1812 star := ""
1813 tname := f.goType
1814 if needsStar(f.protoType) && tname[0] == '*' {
1815 tname = tname[1:]
1816 star = "*"
1817 }
1818 if f.deprecated != "" {
1819 g.P(f.deprecated)
1820 }
1821 g.P("func (m *", mc.goName, ") ", Annotate(mc.message.file, f.fullPath, f.getterName), "() "+tname+" {")
1822 if f.getterDef == "nil" { // Simpler getter
1823 g.P("if m != nil {")
1824 g.P("return m." + f.goName)
1825 g.P("}")
1826 g.P("return nil")
1827 g.P("}")
1828 g.P()
1829 return
1830 }
1831 if mc.message.proto3() {
1832 g.P("if m != nil {")
1833 } else {
1834 g.P("if m != nil && m." + f.goName + " != nil {")
1835 }
1836 g.P("return " + star + "m." + f.goName)
1837 g.P("}")
1838 g.P("return ", f.getterDef)
1839 g.P("}")
1840 g.P()
1841}
1842
1843// setter prints the setter method of the field.
1844func (f *simpleField) setter(g *Generator, mc *msgCtx) {
1845 // No setter for regular fields yet
1846}
1847
1848// getProtoDef returns the default value explicitly stated in the proto file, e.g "yoshi" or "5".
1849func (f *simpleField) getProtoDef() string {
1850 return f.protoDef
1851}
1852
1853// getProtoTypeName returns the protobuf type name for the field as returned by field.GetTypeName(), e.g. ".google.protobuf.Duration".
1854func (f *simpleField) getProtoTypeName() string {
1855 return f.protoTypeName
1856}
1857
1858// getProtoType returns the *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64.
1859func (f *simpleField) getProtoType() descriptor.FieldDescriptorProto_Type {
1860 return f.protoType
1861}
1862
1863// oneofSubFields are kept slize held by each oneofField. They do not appear in the top level slize of fields for the message.
1864type oneofSubField struct {
1865 fieldCommon
1866 protoTypeName string // Proto type name, empty if primitive, e.g. ".google.protobuf.Duration"
1867 protoType descriptor.FieldDescriptorProto_Type // Actual type enum value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64
1868 oneofTypeName string // Type name of the enclosing struct, e.g. "MessageName_FieldName"
1869 fieldNumber int // Actual field number, as defined in proto, e.g. 12
1870 getterDef string // Default for getters, e.g. "nil", `""` or "Default_MessageType_FieldName"
1871 protoDef string // Default value as defined in the proto file, e.g "yoshi" or "5"
1872}
1873
1874// wireTypeName returns a textual wire type, needed for oneof sub fields in generated code.
1875func (f *oneofSubField) wireTypeName() string {
1876 switch f.protoType {
1877 case descriptor.FieldDescriptorProto_TYPE_FIXED64,
1878 descriptor.FieldDescriptorProto_TYPE_SFIXED64,
1879 descriptor.FieldDescriptorProto_TYPE_DOUBLE:
1880 return "WireFixed64"
1881 case descriptor.FieldDescriptorProto_TYPE_FIXED32,
1882 descriptor.FieldDescriptorProto_TYPE_SFIXED32,
1883 descriptor.FieldDescriptorProto_TYPE_FLOAT:
1884 return "WireFixed32"
1885 case descriptor.FieldDescriptorProto_TYPE_GROUP:
1886 return "WireStartGroup"
1887 case descriptor.FieldDescriptorProto_TYPE_MESSAGE,
1888 descriptor.FieldDescriptorProto_TYPE_STRING,
1889 descriptor.FieldDescriptorProto_TYPE_BYTES:
1890 return "WireBytes"
1891 default: // All others are Varints
1892 return "WireVarint"
1893 }
1894}
1895
1896// typedNil prints a nil casted to the pointer to this field.
1897// - for XXX_OneofFuncs
1898func (f *oneofSubField) typedNil(g *Generator) {
1899 g.P("(*", f.oneofTypeName, ")(nil),")
1900}
1901
1902// marshalCase prints the case matching this oneof subfield in the marshalling code.
1903func (f *oneofSubField) marshalCase(g *Generator) {
1904 g.P("case *", f.oneofTypeName, ":")
1905 wire := f.wireTypeName()
1906 var pre, post string
1907 val := "x." + f.goName // overridden for TYPE_BOOL
1908 switch f.protoType {
1909 case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
1910 pre = "b.EncodeFixed64(" + g.Pkg["math"] + ".Float64bits("
1911 post = "))"
1912 case descriptor.FieldDescriptorProto_TYPE_FLOAT:
1913 pre = "b.EncodeFixed32(uint64(" + g.Pkg["math"] + ".Float32bits("
1914 post = ")))"
1915 case descriptor.FieldDescriptorProto_TYPE_INT64, descriptor.FieldDescriptorProto_TYPE_UINT64:
1916 pre, post = "b.EncodeVarint(uint64(", "))"
1917 case descriptor.FieldDescriptorProto_TYPE_INT32, descriptor.FieldDescriptorProto_TYPE_UINT32, descriptor.FieldDescriptorProto_TYPE_ENUM:
1918 pre, post = "b.EncodeVarint(uint64(", "))"
1919 case descriptor.FieldDescriptorProto_TYPE_FIXED64, descriptor.FieldDescriptorProto_TYPE_SFIXED64:
1920 pre, post = "b.EncodeFixed64(uint64(", "))"
1921 case descriptor.FieldDescriptorProto_TYPE_FIXED32, descriptor.FieldDescriptorProto_TYPE_SFIXED32:
1922 pre, post = "b.EncodeFixed32(uint64(", "))"
1923 case descriptor.FieldDescriptorProto_TYPE_BOOL:
1924 g.P("t := uint64(0)")
1925 g.P("if ", val, " { t = 1 }")
1926 val = "t"
1927 pre, post = "b.EncodeVarint(", ")"
1928 case descriptor.FieldDescriptorProto_TYPE_STRING:
1929 pre, post = "b.EncodeStringBytes(", ")"
1930 case descriptor.FieldDescriptorProto_TYPE_GROUP:
1931 pre, post = "b.Marshal(", ")"
1932 case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
1933 pre, post = "b.EncodeMessage(", ")"
1934 case descriptor.FieldDescriptorProto_TYPE_BYTES:
1935 pre, post = "b.EncodeRawBytes(", ")"
1936 case descriptor.FieldDescriptorProto_TYPE_SINT32:
1937 pre, post = "b.EncodeZigzag32(uint64(", "))"
1938 case descriptor.FieldDescriptorProto_TYPE_SINT64:
1939 pre, post = "b.EncodeZigzag64(uint64(", "))"
1940 default:
1941 g.Fail("unhandled oneof field type ", f.protoType.String())
1942 }
1943 g.P("b.EncodeVarint(", f.fieldNumber, "<<3|", g.Pkg["proto"], ".", wire, ")")
1944 if t := f.protoType; t != descriptor.FieldDescriptorProto_TYPE_GROUP && t != descriptor.FieldDescriptorProto_TYPE_MESSAGE {
1945 g.P(pre, val, post)
1946 } else {
1947 g.P("if err := ", pre, val, post, "; err != nil {")
1948 g.P("return err")
1949 g.P("}")
1950 }
1951 if f.protoType == descriptor.FieldDescriptorProto_TYPE_GROUP {
1952 g.P("b.EncodeVarint(", f.fieldNumber, "<<3|", g.Pkg["proto"], ".WireEndGroup)")
1953 }
1954}
1955
1956// unmarshalCase prints the case matching this oneof subfield in the unmarshalling code.
1957func (f *oneofSubField) unmarshalCase(g *Generator, origOneofName string, oneofName string) {
1958 g.P("case ", f.fieldNumber, ": // ", origOneofName, ".", f.getProtoName())
1959 g.P("if wire != ", g.Pkg["proto"], ".", f.wireTypeName(), " {")
1960 g.P("return true, ", g.Pkg["proto"], ".ErrInternalBadWireType")
1961 g.P("}")
1962 lhs := "x, err" // overridden for TYPE_MESSAGE and TYPE_GROUP
1963 var dec, cast, cast2 string
1964 switch f.protoType {
1965 case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
1966 dec, cast = "b.DecodeFixed64()", g.Pkg["math"]+".Float64frombits"
1967 case descriptor.FieldDescriptorProto_TYPE_FLOAT:
1968 dec, cast, cast2 = "b.DecodeFixed32()", "uint32", g.Pkg["math"]+".Float32frombits"
1969 case descriptor.FieldDescriptorProto_TYPE_INT64:
1970 dec, cast = "b.DecodeVarint()", "int64"
1971 case descriptor.FieldDescriptorProto_TYPE_UINT64:
1972 dec = "b.DecodeVarint()"
1973 case descriptor.FieldDescriptorProto_TYPE_INT32:
1974 dec, cast = "b.DecodeVarint()", "int32"
1975 case descriptor.FieldDescriptorProto_TYPE_FIXED64:
1976 dec = "b.DecodeFixed64()"
1977 case descriptor.FieldDescriptorProto_TYPE_FIXED32:
1978 dec, cast = "b.DecodeFixed32()", "uint32"
1979 case descriptor.FieldDescriptorProto_TYPE_BOOL:
1980 dec = "b.DecodeVarint()"
1981 // handled specially below
1982 case descriptor.FieldDescriptorProto_TYPE_STRING:
1983 dec = "b.DecodeStringBytes()"
1984 case descriptor.FieldDescriptorProto_TYPE_GROUP:
1985 g.P("msg := new(", f.goType[1:], ")") // drop star
1986 lhs = "err"
1987 dec = "b.DecodeGroup(msg)"
1988 // handled specially below
1989 case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
1990 g.P("msg := new(", f.goType[1:], ")") // drop star
1991 lhs = "err"
1992 dec = "b.DecodeMessage(msg)"
1993 // handled specially below
1994 case descriptor.FieldDescriptorProto_TYPE_BYTES:
1995 dec = "b.DecodeRawBytes(true)"
1996 case descriptor.FieldDescriptorProto_TYPE_UINT32:
1997 dec, cast = "b.DecodeVarint()", "uint32"
1998 case descriptor.FieldDescriptorProto_TYPE_ENUM:
1999 dec, cast = "b.DecodeVarint()", f.goType
2000 case descriptor.FieldDescriptorProto_TYPE_SFIXED32:
2001 dec, cast = "b.DecodeFixed32()", "int32"
2002 case descriptor.FieldDescriptorProto_TYPE_SFIXED64:
2003 dec, cast = "b.DecodeFixed64()", "int64"
2004 case descriptor.FieldDescriptorProto_TYPE_SINT32:
2005 dec, cast = "b.DecodeZigzag32()", "int32"
2006 case descriptor.FieldDescriptorProto_TYPE_SINT64:
2007 dec, cast = "b.DecodeZigzag64()", "int64"
2008 default:
2009 g.Fail("unhandled oneof field type ", f.protoType.String())
2010 }
2011 g.P(lhs, " := ", dec)
2012 val := "x"
2013 if cast != "" {
2014 val = cast + "(" + val + ")"
2015 }
2016 if cast2 != "" {
2017 val = cast2 + "(" + val + ")"
2018 }
2019 switch f.protoType {
2020 case descriptor.FieldDescriptorProto_TYPE_BOOL:
2021 val += " != 0"
2022 case descriptor.FieldDescriptorProto_TYPE_GROUP,
2023 descriptor.FieldDescriptorProto_TYPE_MESSAGE:
2024 val = "msg"
2025 }
2026 g.P("m.", oneofName, " = &", f.oneofTypeName, "{", val, "}")
2027 g.P("return true, err")
2028}
2029
2030// sizerCase prints the case matching this oneof subfield in the sizer code.
2031func (f *oneofSubField) sizerCase(g *Generator) {
2032 g.P("case *", f.oneofTypeName, ":")
2033 val := "x." + f.goName
2034 var varint, fixed string
2035 switch f.protoType {
2036 case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
2037 fixed = "8"
2038 case descriptor.FieldDescriptorProto_TYPE_FLOAT:
2039 fixed = "4"
2040 case descriptor.FieldDescriptorProto_TYPE_INT64, descriptor.FieldDescriptorProto_TYPE_UINT64, descriptor.FieldDescriptorProto_TYPE_INT32, descriptor.FieldDescriptorProto_TYPE_UINT32, descriptor.FieldDescriptorProto_TYPE_ENUM:
2041 varint = val
2042 case descriptor.FieldDescriptorProto_TYPE_FIXED64, descriptor.FieldDescriptorProto_TYPE_SFIXED64:
2043 fixed = "8"
2044 case descriptor.FieldDescriptorProto_TYPE_FIXED32, descriptor.FieldDescriptorProto_TYPE_SFIXED32:
2045 fixed = "4"
2046 case descriptor.FieldDescriptorProto_TYPE_BOOL:
2047 fixed = "1"
2048 case descriptor.FieldDescriptorProto_TYPE_STRING:
2049 fixed = "len(" + val + ")"
2050 varint = fixed
2051 case descriptor.FieldDescriptorProto_TYPE_GROUP:
2052 fixed = g.Pkg["proto"] + ".Size(" + val + ")"
2053 case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
2054 g.P("s := ", g.Pkg["proto"], ".Size(", val, ")")
2055 fixed = "s"
2056 varint = fixed
2057 case descriptor.FieldDescriptorProto_TYPE_BYTES:
2058 fixed = "len(" + val + ")"
2059 varint = fixed
2060 case descriptor.FieldDescriptorProto_TYPE_SINT32:
2061 varint = "(uint32(" + val + ") << 1) ^ uint32((int32(" + val + ") >> 31))"
2062 case descriptor.FieldDescriptorProto_TYPE_SINT64:
2063 varint = "uint64(" + val + " << 1) ^ uint64((int64(" + val + ") >> 63))"
2064 default:
2065 g.Fail("unhandled oneof field type ", f.protoType.String())
2066 }
2067 // Tag and wire varint is known statically,
2068 // so don't generate code for that part of the size computation.
2069 tagAndWireSize := proto.SizeVarint(uint64(f.fieldNumber << 3)) // wire doesn't affect varint size
2070 g.P("n += ", tagAndWireSize, " // tag and wire")
2071 if varint != "" {
2072 g.P("n += ", g.Pkg["proto"], ".SizeVarint(uint64(", varint, "))")
2073 }
2074 if fixed != "" {
2075 g.P("n += ", fixed)
2076 }
2077 if f.protoType == descriptor.FieldDescriptorProto_TYPE_GROUP {
2078 g.P("n += ", tagAndWireSize, " // tag and wire")
2079 }
2080}
2081
2082// getProtoDef returns the default value explicitly stated in the proto file, e.g "yoshi" or "5".
2083func (f *oneofSubField) getProtoDef() string {
2084 return f.protoDef
2085}
2086
2087// getProtoTypeName returns the protobuf type name for the field as returned by field.GetTypeName(), e.g. ".google.protobuf.Duration".
2088func (f *oneofSubField) getProtoTypeName() string {
2089 return f.protoTypeName
2090}
2091
2092// getProtoType returns the *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64.
2093func (f *oneofSubField) getProtoType() descriptor.FieldDescriptorProto_Type {
2094 return f.protoType
2095}
2096
2097// oneofField represents the oneof on top level.
2098// The alternative fields within the oneof are represented by oneofSubField.
2099type oneofField struct {
2100 fieldCommon
2101 subFields []*oneofSubField // All the possible oneof fields
2102 comment string // The full comment for the field, e.g. "// Types that are valid to be assigned to MyOneof:\n\\"
2103}
2104
2105// decl prints the declaration of the field in the struct (if any).
2106func (f *oneofField) decl(g *Generator, mc *msgCtx) {
2107 comment := f.comment
2108 for _, sf := range f.subFields {
2109 comment += "//\t*" + sf.oneofTypeName + "\n"
2110 }
2111 g.P(comment, Annotate(mc.message.file, f.fullPath, f.goName), " ", f.goType, " `", f.tags, "`")
2112}
2113
2114// getter for a oneof field will print additional discriminators and interfaces for the oneof,
2115// also it prints all the getters for the sub fields.
2116func (f *oneofField) getter(g *Generator, mc *msgCtx) {
2117 // The discriminator type
2118 g.P("type ", f.goType, " interface {")
2119 g.P(f.goType, "()")
2120 g.P("}")
2121 g.P()
2122 // The subField types, fulfilling the discriminator type contract
2123 for _, sf := range f.subFields {
2124 g.P("type ", Annotate(mc.message.file, sf.fullPath, sf.oneofTypeName), " struct {")
2125 g.P(Annotate(mc.message.file, sf.fullPath, sf.goName), " ", sf.goType, " `", sf.tags, "`")
2126 g.P("}")
2127 g.P()
2128 }
2129 for _, sf := range f.subFields {
2130 g.P("func (*", sf.oneofTypeName, ") ", f.goType, "() {}")
2131 g.P()
2132 }
2133 // Getter for the oneof field
2134 g.P("func (m *", mc.goName, ") ", Annotate(mc.message.file, f.fullPath, f.getterName), "() ", f.goType, " {")
2135 g.P("if m != nil { return m.", f.goName, " }")
2136 g.P("return nil")
2137 g.P("}")
2138 g.P()
2139 // Getters for each oneof
2140 for _, sf := range f.subFields {
2141 g.P("func (m *", mc.goName, ") ", Annotate(mc.message.file, sf.fullPath, sf.getterName), "() "+sf.goType+" {")
2142 g.P("if x, ok := m.", f.getterName, "().(*", sf.oneofTypeName, "); ok {")
2143 g.P("return x.", sf.goName)
2144 g.P("}")
2145 g.P("return ", sf.getterDef)
2146 g.P("}")
2147 g.P()
2148 }
2149}
2150
2151// setter prints the setter method of the field.
2152func (f *oneofField) setter(g *Generator, mc *msgCtx) {
2153 // No setters for oneof yet
2154}
2155
2156// topLevelField interface implemented by all types of fields on the top level (not oneofSubField).
2157type topLevelField interface {
2158 decl(g *Generator, mc *msgCtx) // print declaration within the struct
2159 getter(g *Generator, mc *msgCtx) // print getter
2160 setter(g *Generator, mc *msgCtx) // print setter if applicable
2161}
2162
2163// defField interface implemented by all types of fields that can have defaults (not oneofField, but instead oneofSubField).
2164type defField interface {
2165 getProtoDef() string // default value explicitly stated in the proto file, e.g "yoshi" or "5"
2166 getProtoName() string // proto name of a field, e.g. "field_name" or "descriptor"
2167 getGoType() string // go type of the field as a string, e.g. "*int32"
2168 getProtoTypeName() string // protobuf type name for the field, e.g. ".google.protobuf.Duration"
2169 getProtoType() descriptor.FieldDescriptorProto_Type // *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64
2170}
2171
2172// generateDefaultConstants adds constants for default values if needed, which is only if the default value is.
2173// explicit in the proto.
2174func (g *Generator) generateDefaultConstants(mc *msgCtx, topLevelFields []topLevelField) {
2175 // Collect fields that can have defaults
2176 dFields := []defField{}
2177 for _, pf := range topLevelFields {
2178 if f, ok := pf.(*oneofField); ok {
2179 for _, osf := range f.subFields {
2180 dFields = append(dFields, osf)
2181 }
2182 continue
2183 }
2184 dFields = append(dFields, pf.(defField))
2185 }
2186 for _, df := range dFields {
2187 def := df.getProtoDef()
2188 if def == "" {
2189 continue
2190 }
2191 fieldname := g.defaultConstantName(mc.goName, df.getProtoName())
2192 typename := df.getGoType()
2193 if typename[0] == '*' {
2194 typename = typename[1:]
2195 }
2196 kind := "const "
2197 switch {
2198 case typename == "bool":
2199 case typename == "string":
2200 def = strconv.Quote(def)
2201 case typename == "[]byte":
2202 def = "[]byte(" + strconv.Quote(unescape(def)) + ")"
2203 kind = "var "
2204 case def == "inf", def == "-inf", def == "nan":
2205 // These names are known to, and defined by, the protocol language.
2206 switch def {
2207 case "inf":
2208 def = "math.Inf(1)"
2209 case "-inf":
2210 def = "math.Inf(-1)"
2211 case "nan":
2212 def = "math.NaN()"
2213 }
2214 if df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_FLOAT {
2215 def = "float32(" + def + ")"
2216 }
2217 kind = "var "
2218 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_ENUM:
2219 // Must be an enum. Need to construct the prefixed name.
2220 obj := g.ObjectNamed(df.getProtoTypeName())
2221 var enum *EnumDescriptor
2222 if id, ok := obj.(*ImportedDescriptor); ok {
2223 // The enum type has been publicly imported.
2224 enum, _ = id.o.(*EnumDescriptor)
2225 } else {
2226 enum, _ = obj.(*EnumDescriptor)
2227 }
2228 if enum == nil {
2229 log.Printf("don't know how to generate constant for %s", fieldname)
2230 continue
2231 }
2232 def = g.DefaultPackageName(obj) + enum.prefix() + def
2233 }
2234 g.P(kind, fieldname, " ", typename, " = ", def)
2235 g.file.addExport(mc.message, constOrVarSymbol{fieldname, kind, ""})
2236 }
2237 g.P()
2238}
2239
2240// generateInternalStructFields just adds the XXX_<something> fields to the message struct.
2241func (g *Generator) generateInternalStructFields(mc *msgCtx, topLevelFields []topLevelField) {
2242 g.P("XXX_NoUnkeyedLiteral\tstruct{} `json:\"-\"`") // prevent unkeyed struct literals
2243 if len(mc.message.ExtensionRange) > 0 {
2244 messageset := ""
2245 if opts := mc.message.Options; opts != nil && opts.GetMessageSetWireFormat() {
2246 messageset = "protobuf_messageset:\"1\" "
2247 }
2248 g.P(g.Pkg["proto"], ".XXX_InternalExtensions `", messageset, "json:\"-\"`")
2249 }
2250 g.P("XXX_unrecognized\t[]byte `json:\"-\"`")
2251 g.P("XXX_sizecache\tint32 `json:\"-\"`")
2252
2253}
2254
2255// generateOneofFuncs adds all the utility functions for oneof, including marshalling, unmarshalling and sizer.
2256func (g *Generator) generateOneofFuncs(mc *msgCtx, topLevelFields []topLevelField) {
2257 ofields := []*oneofField{}
2258 for _, f := range topLevelFields {
2259 if o, ok := f.(*oneofField); ok {
2260 ofields = append(ofields, o)
2261 }
2262 }
2263 if len(ofields) == 0 {
2264 return
2265 }
2266 enc := "_" + mc.goName + "_OneofMarshaler"
2267 dec := "_" + mc.goName + "_OneofUnmarshaler"
2268 size := "_" + mc.goName + "_OneofSizer"
2269 encSig := "(msg " + g.Pkg["proto"] + ".Message, b *" + g.Pkg["proto"] + ".Buffer) error"
2270 decSig := "(msg " + g.Pkg["proto"] + ".Message, tag, wire int, b *" + g.Pkg["proto"] + ".Buffer) (bool, error)"
2271 sizeSig := "(msg " + g.Pkg["proto"] + ".Message) (n int)"
2272
2273 // OneofFuncs
2274 g.P("// XXX_OneofFuncs is for the internal use of the proto package.")
2275 g.P("func (*", mc.goName, ") XXX_OneofFuncs() (func", encSig, ", func", decSig, ", func", sizeSig, ", []interface{}) {")
2276 g.P("return ", enc, ", ", dec, ", ", size, ", []interface{}{")
2277 for _, of := range ofields {
2278 for _, sf := range of.subFields {
2279 sf.typedNil(g)
2280 }
2281 }
2282 g.P("}")
2283 g.P("}")
2284 g.P()
2285
2286 // marshaler
2287 g.P("func ", enc, encSig, " {")
2288 g.P("m := msg.(*", mc.goName, ")")
2289 for _, of := range ofields {
2290 g.P("// ", of.getProtoName())
2291 g.P("switch x := m.", of.goName, ".(type) {")
2292 for _, sf := range of.subFields {
2293 // also fills in field.wire
2294 sf.marshalCase(g)
2295 }
2296 g.P("case nil:")
2297 g.P("default:")
2298 g.P(" return ", g.Pkg["fmt"], `.Errorf("`, mc.goName, ".", of.goName, ` has unexpected type %T", x)`)
2299 g.P("}")
2300 }
2301 g.P("return nil")
2302 g.P("}")
2303 g.P()
2304
2305 // unmarshaler
2306 g.P("func ", dec, decSig, " {")
2307 g.P("m := msg.(*", mc.goName, ")")
2308 g.P("switch tag {")
2309 for _, of := range ofields {
2310 for _, sf := range of.subFields {
2311 sf.unmarshalCase(g, of.getProtoName(), of.goName)
2312 }
2313 }
2314 g.P("default:")
2315 g.P("return false, nil")
2316 g.P("}")
2317 g.P("}")
2318 g.P()
2319
2320 // sizer
2321 g.P("func ", size, sizeSig, " {")
2322 g.P("m := msg.(*", mc.goName, ")")
2323 for _, of := range ofields {
2324 g.P("// ", of.getProtoName())
2325 g.P("switch x := m.", of.goName, ".(type) {")
2326 for _, sf := range of.subFields {
2327 // also fills in field.wire
2328 sf.sizerCase(g)
2329 }
2330 g.P("case nil:")
2331 g.P("default:")
2332 g.P("panic(", g.Pkg["fmt"], ".Sprintf(\"proto: unexpected type %T in oneof\", x))")
2333 g.P("}")
2334 }
2335 g.P("return n")
2336 g.P("}")
2337 g.P()
2338}
2339
2340// generateMessageStruct adds the actual struct with it's members (but not methods) to the output.
2341func (g *Generator) generateMessageStruct(mc *msgCtx, topLevelFields []topLevelField) {
2342 comments := g.PrintComments(mc.message.path)
2343
2344 // Guarantee deprecation comments appear after user-provided comments.
2345 if mc.message.GetOptions().GetDeprecated() {
2346 if comments {
2347 // Convention: Separate deprecation comments from original
2348 // comments with an empty line.
2349 g.P("//")
2350 }
2351 g.P(deprecationComment)
2352 }
2353
2354 g.P("type ", Annotate(mc.message.file, mc.message.path, mc.goName), " struct {")
2355 for _, pf := range topLevelFields {
2356 pf.decl(g, mc)
2357 }
2358 g.generateInternalStructFields(mc, topLevelFields)
2359 g.P("}")
2360}
2361
2362// generateGetters adds getters for all fields, including oneofs and weak fields when applicable.
2363func (g *Generator) generateGetters(mc *msgCtx, topLevelFields []topLevelField) {
2364 for _, pf := range topLevelFields {
2365 pf.getter(g, mc)
2366 }
2367}
2368
2369// generateSetters add setters for all fields, including oneofs and weak fields when applicable.
2370func (g *Generator) generateSetters(mc *msgCtx, topLevelFields []topLevelField) {
2371 for _, pf := range topLevelFields {
2372 pf.setter(g, mc)
2373 }
2374}
2375
2376// generateCommonMethods adds methods to the message that are not on a per field basis.
2377func (g *Generator) generateCommonMethods(mc *msgCtx) {
2378 // Reset, String and ProtoMessage methods.
2379 g.P("func (m *", mc.goName, ") Reset() { *m = ", mc.goName, "{} }")
2380 g.P("func (m *", mc.goName, ") String() string { return ", g.Pkg["proto"], ".CompactTextString(m) }")
2381 g.P("func (*", mc.goName, ") ProtoMessage() {}")
2382 var indexes []string
2383 for m := mc.message; m != nil; m = m.parent {
2384 indexes = append([]string{strconv.Itoa(m.index)}, indexes...)
2385 }
2386 g.P("func (*", mc.goName, ") Descriptor() ([]byte, []int) {")
2387 g.P("return ", g.file.VarName(), ", []int{", strings.Join(indexes, ", "), "}")
2388 g.P("}")
2389 // TODO: Revisit the decision to use a XXX_WellKnownType method
2390 // if we change proto.MessageName to work with multiple equivalents.
2391 if mc.message.file.GetPackage() == "google.protobuf" && wellKnownTypes[mc.message.GetName()] {
2392 g.P("func (*", mc.goName, `) XXX_WellKnownType() string { return "`, mc.message.GetName(), `" }`)
2393 }
2394
2395 // Extension support methods
2396 if len(mc.message.ExtensionRange) > 0 {
2397 // message_set_wire_format only makes sense when extensions are defined.
2398 if opts := mc.message.Options; opts != nil && opts.GetMessageSetWireFormat() {
2399 g.P()
2400 g.P("func (m *", mc.goName, ") MarshalJSON() ([]byte, error) {")
2401 g.P("return ", g.Pkg["proto"], ".MarshalMessageSetJSON(&m.XXX_InternalExtensions)")
2402 g.P("}")
2403 g.P("func (m *", mc.goName, ") UnmarshalJSON(buf []byte) error {")
2404 g.P("return ", g.Pkg["proto"], ".UnmarshalMessageSetJSON(buf, &m.XXX_InternalExtensions)")
2405 g.P("}")
2406 }
2407
2408 g.P()
2409 g.P("var extRange_", mc.goName, " = []", g.Pkg["proto"], ".ExtensionRange{")
2410 for _, r := range mc.message.ExtensionRange {
2411 end := fmt.Sprint(*r.End - 1) // make range inclusive on both ends
2412 g.P("{Start: ", r.Start, ", End: ", end, "},")
2413 }
2414 g.P("}")
2415 g.P("func (*", mc.goName, ") ExtensionRangeArray() []", g.Pkg["proto"], ".ExtensionRange {")
2416 g.P("return extRange_", mc.goName)
2417 g.P("}")
2418 }
2419
2420 // TODO: It does not scale to keep adding another method for every
2421 // operation on protos that we want to switch over to using the
2422 // table-driven approach. Instead, we should only add a single method
2423 // that allows getting access to the *InternalMessageInfo struct and then
2424 // calling Unmarshal, Marshal, Merge, Size, and Discard directly on that.
2425
2426 // Wrapper for table-driven marshaling and unmarshaling.
2427 g.P("func (m *", mc.goName, ") XXX_Unmarshal(b []byte) error {")
2428 g.P("return xxx_messageInfo_", mc.goName, ".Unmarshal(m, b)")
2429 g.P("}")
2430
2431 g.P("func (m *", mc.goName, ") XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {")
2432 g.P("return xxx_messageInfo_", mc.goName, ".Marshal(b, m, deterministic)")
2433 g.P("}")
2434
2435 g.P("func (dst *", mc.goName, ") XXX_Merge(src ", g.Pkg["proto"], ".Message) {")
2436 g.P("xxx_messageInfo_", mc.goName, ".Merge(dst, src)")
2437 g.P("}")
2438
2439 g.P("func (m *", mc.goName, ") XXX_Size() int {") // avoid name clash with "Size" field in some message
2440 g.P("return xxx_messageInfo_", mc.goName, ".Size(m)")
2441 g.P("}")
2442
2443 g.P("func (m *", mc.goName, ") XXX_DiscardUnknown() {")
2444 g.P("xxx_messageInfo_", mc.goName, ".DiscardUnknown(m)")
2445 g.P("}")
2446
2447 g.P("var xxx_messageInfo_", mc.goName, " ", g.Pkg["proto"], ".InternalMessageInfo")
2448 g.P()
2449}
2450
2451// Generate the type, methods and default constant definitions for this Descriptor.
2452func (g *Generator) generateMessage(message *Descriptor) {
2453 topLevelFields := []topLevelField{}
2454 oFields := make(map[int32]*oneofField)
2455 // The full type name
2456 typeName := message.TypeName()
2457 // The full type name, CamelCased.
2458 goTypeName := CamelCaseSlice(typeName)
2459
2460 usedNames := make(map[string]bool)
2461 for _, n := range methodNames {
2462 usedNames[n] = true
2463 }
2464
2465 // allocNames finds a conflict-free variation of the given strings,
2466 // consistently mutating their suffixes.
2467 // It returns the same number of strings.
2468 allocNames := func(ns ...string) []string {
2469 Loop:
2470 for {
2471 for _, n := range ns {
2472 if usedNames[n] {
2473 for i := range ns {
2474 ns[i] += "_"
2475 }
2476 continue Loop
2477 }
2478 }
2479 for _, n := range ns {
2480 usedNames[n] = true
2481 }
2482 return ns
2483 }
2484 }
2485
2486 mapFieldTypes := make(map[*descriptor.FieldDescriptorProto]string) // keep track of the map fields to be added later
2487
2488 // Build a structure more suitable for generating the text in one pass
2489 for i, field := range message.Field {
2490 // Allocate the getter and the field at the same time so name
2491 // collisions create field/method consistent names.
2492 // TODO: This allocation occurs based on the order of the fields
2493 // in the proto file, meaning that a change in the field
2494 // ordering can change generated Method/Field names.
2495 base := CamelCase(*field.Name)
2496 ns := allocNames(base, "Get"+base)
2497 fieldName, fieldGetterName := ns[0], ns[1]
2498 typename, wiretype := g.GoType(message, field)
2499 jsonName := *field.Name
2500 tag := fmt.Sprintf("protobuf:%s json:%q", g.goTag(message, field, wiretype), jsonName+",omitempty")
2501
2502 oneof := field.OneofIndex != nil
2503 if oneof && oFields[*field.OneofIndex] == nil {
2504 odp := message.OneofDecl[int(*field.OneofIndex)]
2505 base := CamelCase(odp.GetName())
2506 names := allocNames(base, "Get"+base)
2507 fname, gname := names[0], names[1]
2508
2509 // This is the first field of a oneof we haven't seen before.
2510 // Generate the union field.
2511 oneofFullPath := fmt.Sprintf("%s,%d,%d", message.path, messageOneofPath, *field.OneofIndex)
2512 c, ok := g.makeComments(oneofFullPath)
2513 if ok {
2514 c += "\n//\n"
2515 }
2516 c += "// Types that are valid to be assigned to " + fname + ":\n"
2517 // Generate the rest of this comment later,
2518 // when we've computed any disambiguation.
2519
2520 dname := "is" + goTypeName + "_" + fname
2521 tag := `protobuf_oneof:"` + odp.GetName() + `"`
2522 of := oneofField{
2523 fieldCommon: fieldCommon{
2524 goName: fname,
2525 getterName: gname,
2526 goType: dname,
2527 tags: tag,
2528 protoName: odp.GetName(),
2529 fullPath: oneofFullPath,
2530 },
2531 comment: c,
2532 }
2533 topLevelFields = append(topLevelFields, &of)
2534 oFields[*field.OneofIndex] = &of
2535 }
2536
2537 if *field.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE {
2538 desc := g.ObjectNamed(field.GetTypeName())
2539 if d, ok := desc.(*Descriptor); ok && d.GetOptions().GetMapEntry() {
2540 // Figure out the Go types and tags for the key and value types.
2541 keyField, valField := d.Field[0], d.Field[1]
2542 keyType, keyWire := g.GoType(d, keyField)
2543 valType, valWire := g.GoType(d, valField)
2544 keyTag, valTag := g.goTag(d, keyField, keyWire), g.goTag(d, valField, valWire)
2545
2546 // We don't use stars, except for message-typed values.
2547 // Message and enum types are the only two possibly foreign types used in maps,
2548 // so record their use. They are not permitted as map keys.
2549 keyType = strings.TrimPrefix(keyType, "*")
2550 switch *valField.Type {
2551 case descriptor.FieldDescriptorProto_TYPE_ENUM:
2552 valType = strings.TrimPrefix(valType, "*")
2553 g.RecordTypeUse(valField.GetTypeName())
2554 case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
2555 g.RecordTypeUse(valField.GetTypeName())
2556 default:
2557 valType = strings.TrimPrefix(valType, "*")
2558 }
2559
2560 typename = fmt.Sprintf("map[%s]%s", keyType, valType)
2561 mapFieldTypes[field] = typename // record for the getter generation
2562
2563 tag += fmt.Sprintf(" protobuf_key:%s protobuf_val:%s", keyTag, valTag)
2564 }
2565 }
2566
2567 dvalue := g.getterDefault(field, goTypeName)
2568 if oneof {
2569 tname := goTypeName + "_" + fieldName
2570 // It is possible for this to collide with a message or enum
2571 // nested in this message. Check for collisions.
2572 for {
2573 ok := true
2574 for _, desc := range message.nested {
2575 if CamelCaseSlice(desc.TypeName()) == tname {
2576 ok = false
2577 break
2578 }
2579 }
2580 for _, enum := range message.enums {
2581 if CamelCaseSlice(enum.TypeName()) == tname {
2582 ok = false
2583 break
2584 }
2585 }
2586 if !ok {
2587 tname += "_"
2588 continue
2589 }
2590 break
2591 }
2592
2593 oneofField := oFields[*field.OneofIndex]
2594 tag := "protobuf:" + g.goTag(message, field, wiretype)
2595 sf := oneofSubField{
2596 fieldCommon: fieldCommon{
2597 goName: fieldName,
2598 getterName: fieldGetterName,
2599 goType: typename,
2600 tags: tag,
2601 protoName: field.GetName(),
2602 fullPath: fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i),
2603 },
2604 protoTypeName: field.GetTypeName(),
2605 fieldNumber: int(*field.Number),
2606 protoType: *field.Type,
2607 getterDef: dvalue,
2608 protoDef: field.GetDefaultValue(),
2609 oneofTypeName: tname,
2610 }
2611 oneofField.subFields = append(oneofField.subFields, &sf)
2612 g.RecordTypeUse(field.GetTypeName())
2613 continue
2614 }
2615
2616 fieldDeprecated := ""
2617 if field.GetOptions().GetDeprecated() {
2618 fieldDeprecated = deprecationComment
2619 }
2620
2621 fieldFullPath := fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i)
2622 c, ok := g.makeComments(fieldFullPath)
2623 if ok {
2624 c += "\n"
2625 }
2626 rf := simpleField{
2627 fieldCommon: fieldCommon{
2628 goName: fieldName,
2629 getterName: fieldGetterName,
2630 goType: typename,
2631 tags: tag,
2632 protoName: field.GetName(),
2633 fullPath: fieldFullPath,
2634 },
2635 protoTypeName: field.GetTypeName(),
2636 protoType: *field.Type,
2637 deprecated: fieldDeprecated,
2638 getterDef: dvalue,
2639 protoDef: field.GetDefaultValue(),
2640 comment: c,
2641 }
2642 var pf topLevelField = &rf
2643
2644 topLevelFields = append(topLevelFields, pf)
2645 g.RecordTypeUse(field.GetTypeName())
2646 }
2647
2648 mc := &msgCtx{
2649 goName: goTypeName,
2650 message: message,
2651 }
2652
2653 g.generateMessageStruct(mc, topLevelFields)
2654 g.P()
2655 g.generateCommonMethods(mc)
2656 g.P()
2657 g.generateDefaultConstants(mc, topLevelFields)
2658 g.P()
2659 g.generateGetters(mc, topLevelFields)
2660 g.P()
2661 g.generateSetters(mc, topLevelFields)
2662 g.P()
2663 g.generateOneofFuncs(mc, topLevelFields)
2664 g.P()
2665
2666 if !message.group {
2667
2668 var oneofTypes []string
2669 for _, f := range topLevelFields {
2670 if of, ok := f.(*oneofField); ok {
2671 for _, osf := range of.subFields {
2672 oneofTypes = append(oneofTypes, osf.oneofTypeName)
2673 }
2674 }
2675 }
2676
2677 opts := message.Options
2678 ms := &messageSymbol{
2679 sym: goTypeName,
2680 hasExtensions: len(message.ExtensionRange) > 0,
2681 isMessageSet: opts != nil && opts.GetMessageSetWireFormat(),
2682 oneofTypes: oneofTypes,
2683 }
2684 g.file.addExport(message, ms)
2685 }
2686
2687 for _, ext := range message.ext {
2688 g.generateExtension(ext)
2689 }
2690
2691 fullName := strings.Join(message.TypeName(), ".")
2692 if g.file.Package != nil {
2693 fullName = *g.file.Package + "." + fullName
2694 }
2695
2696 g.addInitf("%s.RegisterType((*%s)(nil), %q)", g.Pkg["proto"], goTypeName, fullName)
2697 // Register types for native map types.
2698 for _, k := range mapFieldKeys(mapFieldTypes) {
2699 fullName := strings.TrimPrefix(*k.TypeName, ".")
2700 g.addInitf("%s.RegisterMapType((%s)(nil), %q)", g.Pkg["proto"], mapFieldTypes[k], fullName)
2701 }
2702
2703}
2704
2705type byTypeName []*descriptor.FieldDescriptorProto
2706
2707func (a byTypeName) Len() int { return len(a) }
2708func (a byTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
2709func (a byTypeName) Less(i, j int) bool { return *a[i].TypeName < *a[j].TypeName }
2710
2711// mapFieldKeys returns the keys of m in a consistent order.
2712func mapFieldKeys(m map[*descriptor.FieldDescriptorProto]string) []*descriptor.FieldDescriptorProto {
2713 keys := make([]*descriptor.FieldDescriptorProto, 0, len(m))
2714 for k := range m {
2715 keys = append(keys, k)
2716 }
2717 sort.Sort(byTypeName(keys))
2718 return keys
2719}
2720
2721var escapeChars = [256]byte{
2722 'a': '\a', 'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t', 'v': '\v', '\\': '\\', '"': '"', '\'': '\'', '?': '?',
2723}
2724
2725// unescape reverses the "C" escaping that protoc does for default values of bytes fields.
2726// It is best effort in that it effectively ignores malformed input. Seemingly invalid escape
2727// sequences are conveyed, unmodified, into the decoded result.
2728func unescape(s string) string {
2729 // NB: Sadly, we can't use strconv.Unquote because protoc will escape both
2730 // single and double quotes, but strconv.Unquote only allows one or the
2731 // other (based on actual surrounding quotes of its input argument).
2732
2733 var out []byte
2734 for len(s) > 0 {
2735 // regular character, or too short to be valid escape
2736 if s[0] != '\\' || len(s) < 2 {
2737 out = append(out, s[0])
2738 s = s[1:]
2739 } else if c := escapeChars[s[1]]; c != 0 {
2740 // escape sequence
2741 out = append(out, c)
2742 s = s[2:]
2743 } else if s[1] == 'x' || s[1] == 'X' {
2744 // hex escape, e.g. "\x80
2745 if len(s) < 4 {
2746 // too short to be valid
2747 out = append(out, s[:2]...)
2748 s = s[2:]
2749 continue
2750 }
2751 v, err := strconv.ParseUint(s[2:4], 16, 8)
2752 if err != nil {
2753 out = append(out, s[:4]...)
2754 } else {
2755 out = append(out, byte(v))
2756 }
2757 s = s[4:]
2758 } else if '0' <= s[1] && s[1] <= '7' {
2759 // octal escape, can vary from 1 to 3 octal digits; e.g., "\0" "\40" or "\164"
2760 // so consume up to 2 more bytes or up to end-of-string
2761 n := len(s[1:]) - len(strings.TrimLeft(s[1:], "01234567"))
2762 if n > 3 {
2763 n = 3
2764 }
2765 v, err := strconv.ParseUint(s[1:1+n], 8, 8)
2766 if err != nil {
2767 out = append(out, s[:1+n]...)
2768 } else {
2769 out = append(out, byte(v))
2770 }
2771 s = s[1+n:]
2772 } else {
2773 // bad escape, just propagate the slash as-is
2774 out = append(out, s[0])
2775 s = s[1:]
2776 }
2777 }
2778
2779 return string(out)
2780}
2781
2782func (g *Generator) generateExtension(ext *ExtensionDescriptor) {
2783 ccTypeName := ext.DescName()
2784
2785 extObj := g.ObjectNamed(*ext.Extendee)
2786 var extDesc *Descriptor
2787 if id, ok := extObj.(*ImportedDescriptor); ok {
2788 // This is extending a publicly imported message.
2789 // We need the underlying type for goTag.
2790 extDesc = id.o.(*Descriptor)
2791 } else {
2792 extDesc = extObj.(*Descriptor)
2793 }
2794 extendedType := "*" + g.TypeName(extObj) // always use the original
2795 field := ext.FieldDescriptorProto
2796 fieldType, wireType := g.GoType(ext.parent, field)
2797 tag := g.goTag(extDesc, field, wireType)
2798 g.RecordTypeUse(*ext.Extendee)
2799 if n := ext.FieldDescriptorProto.TypeName; n != nil {
2800 // foreign extension type
2801 g.RecordTypeUse(*n)
2802 }
2803
2804 typeName := ext.TypeName()
2805
2806 // Special case for proto2 message sets: If this extension is extending
2807 // proto2.bridge.MessageSet, and its final name component is "message_set_extension",
2808 // then drop that last component.
2809 //
2810 // TODO: This should be implemented in the text formatter rather than the generator.
2811 // In addition, the situation for when to apply this special case is implemented
2812 // differently in other languages:
2813 // https://github.com/google/protobuf/blob/aff10976/src/google/protobuf/text_format.cc#L1560
2814 mset := false
2815 if extDesc.GetOptions().GetMessageSetWireFormat() && typeName[len(typeName)-1] == "message_set_extension" {
2816 typeName = typeName[:len(typeName)-1]
2817 mset = true
2818 }
2819
2820 // For text formatting, the package must be exactly what the .proto file declares,
2821 // ignoring overrides such as the go_package option, and with no dot/underscore mapping.
2822 extName := strings.Join(typeName, ".")
2823 if g.file.Package != nil {
2824 extName = *g.file.Package + "." + extName
2825 }
2826
2827 g.P("var ", ccTypeName, " = &", g.Pkg["proto"], ".ExtensionDesc{")
2828 g.P("ExtendedType: (", extendedType, ")(nil),")
2829 g.P("ExtensionType: (", fieldType, ")(nil),")
2830 g.P("Field: ", field.Number, ",")
2831 g.P(`Name: "`, extName, `",`)
2832 g.P("Tag: ", tag, ",")
2833 g.P(`Filename: "`, g.file.GetName(), `",`)
2834
2835 g.P("}")
2836 g.P()
2837
2838 if mset {
2839 // Generate a bit more code to register with message_set.go.
2840 g.addInitf("%s.RegisterMessageSetType((%s)(nil), %d, %q)", g.Pkg["proto"], fieldType, *field.Number, extName)
2841 }
2842
2843 g.file.addExport(ext, constOrVarSymbol{ccTypeName, "var", ""})
2844}
2845
2846func (g *Generator) generateInitFunction() {
2847 for _, enum := range g.file.enum {
2848 g.generateEnumRegistration(enum)
2849 }
2850 for _, d := range g.file.desc {
2851 for _, ext := range d.ext {
2852 g.generateExtensionRegistration(ext)
2853 }
2854 }
2855 for _, ext := range g.file.ext {
2856 g.generateExtensionRegistration(ext)
2857 }
2858 if len(g.init) == 0 {
2859 return
2860 }
2861 g.P("func init() {")
2862 for _, l := range g.init {
2863 g.P(l)
2864 }
2865 g.P("}")
2866 g.init = nil
2867}
2868
2869func (g *Generator) generateFileDescriptor(file *FileDescriptor) {
2870 // Make a copy and trim source_code_info data.
2871 // TODO: Trim this more when we know exactly what we need.
2872 pb := proto.Clone(file.FileDescriptorProto).(*descriptor.FileDescriptorProto)
2873 pb.SourceCodeInfo = nil
2874
2875 b, err := proto.Marshal(pb)
2876 if err != nil {
2877 g.Fail(err.Error())
2878 }
2879
2880 var buf bytes.Buffer
2881 w, _ := gzip.NewWriterLevel(&buf, gzip.BestCompression)
2882 w.Write(b)
2883 w.Close()
2884 b = buf.Bytes()
2885
2886 v := file.VarName()
2887 g.P()
2888 g.P("func init() { ", g.Pkg["proto"], ".RegisterFile(", strconv.Quote(*file.Name), ", ", v, ") }")
2889 g.P("var ", v, " = []byte{")
2890 g.P("// ", len(b), " bytes of a gzipped FileDescriptorProto")
2891 for len(b) > 0 {
2892 n := 16
2893 if n > len(b) {
2894 n = len(b)
2895 }
2896
2897 s := ""
2898 for _, c := range b[:n] {
2899 s += fmt.Sprintf("0x%02x,", c)
2900 }
2901 g.P(s)
2902
2903 b = b[n:]
2904 }
2905 g.P("}")
2906}
2907
2908func (g *Generator) generateEnumRegistration(enum *EnumDescriptor) {
2909 // // We always print the full (proto-world) package name here.
2910 pkg := enum.File().GetPackage()
2911 if pkg != "" {
2912 pkg += "."
2913 }
2914 // The full type name
2915 typeName := enum.TypeName()
2916 // The full type name, CamelCased.
2917 ccTypeName := CamelCaseSlice(typeName)
2918 g.addInitf("%s.RegisterEnum(%q, %[3]s_name, %[3]s_value)", g.Pkg["proto"], pkg+ccTypeName, ccTypeName)
2919}
2920
2921func (g *Generator) generateExtensionRegistration(ext *ExtensionDescriptor) {
2922 g.addInitf("%s.RegisterExtension(%s)", g.Pkg["proto"], ext.DescName())
2923}
2924
2925// And now lots of helper functions.
2926
2927// Is c an ASCII lower-case letter?
2928func isASCIILower(c byte) bool {
2929 return 'a' <= c && c <= 'z'
2930}
2931
2932// Is c an ASCII digit?
2933func isASCIIDigit(c byte) bool {
2934 return '0' <= c && c <= '9'
2935}
2936
2937// CamelCase returns the CamelCased name.
2938// If there is an interior underscore followed by a lower case letter,
2939// drop the underscore and convert the letter to upper case.
2940// There is a remote possibility of this rewrite causing a name collision,
2941// but it's so remote we're prepared to pretend it's nonexistent - since the
2942// C++ generator lowercases names, it's extremely unlikely to have two fields
2943// with different capitalizations.
2944// In short, _my_field_name_2 becomes XMyFieldName_2.
2945func CamelCase(s string) string {
2946 if s == "" {
2947 return ""
2948 }
2949 t := make([]byte, 0, 32)
2950 i := 0
2951 if s[0] == '_' {
2952 // Need a capital letter; drop the '_'.
2953 t = append(t, 'X')
2954 i++
2955 }
2956 // Invariant: if the next letter is lower case, it must be converted
2957 // to upper case.
2958 // That is, we process a word at a time, where words are marked by _ or
2959 // upper case letter. Digits are treated as words.
2960 for ; i < len(s); i++ {
2961 c := s[i]
2962 if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) {
2963 continue // Skip the underscore in s.
2964 }
2965 if isASCIIDigit(c) {
2966 t = append(t, c)
2967 continue
2968 }
2969 // Assume we have a letter now - if not, it's a bogus identifier.
2970 // The next word is a sequence of characters that must start upper case.
2971 if isASCIILower(c) {
2972 c ^= ' ' // Make it a capital letter.
2973 }
2974 t = append(t, c) // Guaranteed not lower case.
2975 // Accept lower case sequence that follows.
2976 for i+1 < len(s) && isASCIILower(s[i+1]) {
2977 i++
2978 t = append(t, s[i])
2979 }
2980 }
2981 return string(t)
2982}
2983
2984// CamelCaseSlice is like CamelCase, but the argument is a slice of strings to
2985// be joined with "_".
2986func CamelCaseSlice(elem []string) string { return CamelCase(strings.Join(elem, "_")) }
2987
2988// dottedSlice turns a sliced name into a dotted name.
2989func dottedSlice(elem []string) string { return strings.Join(elem, ".") }
2990
2991// Is this field optional?
2992func isOptional(field *descriptor.FieldDescriptorProto) bool {
2993 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_OPTIONAL
2994}
2995
2996// Is this field required?
2997func isRequired(field *descriptor.FieldDescriptorProto) bool {
2998 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REQUIRED
2999}
3000
3001// Is this field repeated?
3002func isRepeated(field *descriptor.FieldDescriptorProto) bool {
3003 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED
3004}
3005
3006// Is this field a scalar numeric type?
3007func isScalar(field *descriptor.FieldDescriptorProto) bool {
3008 if field.Type == nil {
3009 return false
3010 }
3011 switch *field.Type {
3012 case descriptor.FieldDescriptorProto_TYPE_DOUBLE,
3013 descriptor.FieldDescriptorProto_TYPE_FLOAT,
3014 descriptor.FieldDescriptorProto_TYPE_INT64,
3015 descriptor.FieldDescriptorProto_TYPE_UINT64,
3016 descriptor.FieldDescriptorProto_TYPE_INT32,
3017 descriptor.FieldDescriptorProto_TYPE_FIXED64,
3018 descriptor.FieldDescriptorProto_TYPE_FIXED32,
3019 descriptor.FieldDescriptorProto_TYPE_BOOL,
3020 descriptor.FieldDescriptorProto_TYPE_UINT32,
3021 descriptor.FieldDescriptorProto_TYPE_ENUM,
3022 descriptor.FieldDescriptorProto_TYPE_SFIXED32,
3023 descriptor.FieldDescriptorProto_TYPE_SFIXED64,
3024 descriptor.FieldDescriptorProto_TYPE_SINT32,
3025 descriptor.FieldDescriptorProto_TYPE_SINT64:
3026 return true
3027 default:
3028 return false
3029 }
3030}
3031
3032// badToUnderscore is the mapping function used to generate Go names from package names,
3033// which can be dotted in the input .proto file. It replaces non-identifier characters such as
3034// dot or dash with underscore.
3035func badToUnderscore(r rune) rune {
3036 if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' {
3037 return r
3038 }
3039 return '_'
3040}
3041
3042// baseName returns the last path element of the name, with the last dotted suffix removed.
3043func baseName(name string) string {
3044 // First, find the last element
3045 if i := strings.LastIndex(name, "/"); i >= 0 {
3046 name = name[i+1:]
3047 }
3048 // Now drop the suffix
3049 if i := strings.LastIndex(name, "."); i >= 0 {
3050 name = name[0:i]
3051 }
3052 return name
3053}
3054
3055// The SourceCodeInfo message describes the location of elements of a parsed
3056// .proto file by way of a "path", which is a sequence of integers that
3057// describe the route from a FileDescriptorProto to the relevant submessage.
3058// The path alternates between a field number of a repeated field, and an index
3059// into that repeated field. The constants below define the field numbers that
3060// are used.
3061//
3062// See descriptor.proto for more information about this.
3063const (
3064 // tag numbers in FileDescriptorProto
3065 packagePath = 2 // package
3066 messagePath = 4 // message_type
3067 enumPath = 5 // enum_type
3068 // tag numbers in DescriptorProto
3069 messageFieldPath = 2 // field
3070 messageMessagePath = 3 // nested_type
3071 messageEnumPath = 4 // enum_type
3072 messageOneofPath = 8 // oneof_decl
3073 // tag numbers in EnumDescriptorProto
3074 enumValuePath = 2 // value
3075)
3076
3077var supportTypeAliases bool
3078
3079func init() {
3080 for _, tag := range build.Default.ReleaseTags {
3081 if tag == "go1.9" {
3082 supportTypeAliases = true
3083 return
3084 }
3085 }
3086}