1 // Go support for Protocol Buffers - Google's data interchange format
3 // Copyright 2010 The Go Authors. All rights reserved.
4 // https://github.com/golang/protobuf
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are
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
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.
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.
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
60 "github.com/golang/protobuf/proto"
61 "github.com/golang/protobuf/protoc-gen-go/generator/internal/remap"
63 "github.com/golang/protobuf/protoc-gen-go/descriptor"
64 plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
67 // generatedCodeVersion indicates a version of the generated code.
68 // It is incremented whenever an incompatibility between the generated code and
69 // proto package is introduced; the generated code references
70 // a constant, proto.ProtoPackageIsVersionN (where N is generatedCodeVersion).
71 const generatedCodeVersion = 3
73 // A Plugin provides functionality to add to the output during Go code generation,
74 // such as to produce RPC stubs.
75 type Plugin interface {
76 // Name identifies the plugin.
78 // Init is called once after data structures are built but before
79 // code generation begins.
81 // Generate produces the code generated by the plugin for this file,
82 // except for the imports, by calling the generator's methods P, In, and Out.
83 Generate(file *FileDescriptor)
84 // GenerateImports produces the import declarations for this file.
85 // It is called after Generate.
86 GenerateImports(file *FileDescriptor)
91 // RegisterPlugin installs a (second-order) plugin to be run when the Go output is generated.
92 // It is typically called during initialization.
93 func RegisterPlugin(p Plugin) {
94 plugins = append(plugins, p)
97 // A GoImportPath is the import path of a Go package. e.g., "google.golang.org/genproto/protobuf".
98 type GoImportPath string
100 func (p GoImportPath) String() string { return strconv.Quote(string(p)) }
102 // A GoPackageName is the name of a Go package. e.g., "protobuf".
103 type GoPackageName string
105 // Each type we import as a protocol buffer (other than FileDescriptorProto) needs
106 // a pointer to the FileDescriptorProto that represents it. These types achieve that
107 // wrapping by placing each Proto inside a struct with the pointer to its File. The
108 // structs have the same names as their contents, with "Proto" removed.
109 // FileDescriptor is used to store the things that it points to.
111 // The file and package name method are common to messages and enums.
113 file *FileDescriptor // File this object comes from.
116 // GoImportPath is the import path of the Go package containing the type.
117 func (c *common) GoImportPath() GoImportPath {
118 return c.file.importPath
121 func (c *common) File() *FileDescriptor { return c.file }
123 func fileIsProto3(file *descriptor.FileDescriptorProto) bool {
124 return file.GetSyntax() == "proto3"
127 func (c *common) proto3() bool { return fileIsProto3(c.file.FileDescriptorProto) }
129 // Descriptor represents a protocol buffer message.
130 type Descriptor struct {
132 *descriptor.DescriptorProto
133 parent *Descriptor // The containing message, if any.
134 nested []*Descriptor // Inner messages, if any.
135 enums []*EnumDescriptor // Inner enums, if any.
136 ext []*ExtensionDescriptor // Extensions, if any.
137 typename []string // Cached typename vector.
138 index int // The index into the container, whether the file or another message.
139 path string // The SourceCodeInfo path as comma-separated integers.
143 // TypeName returns the elements of the dotted type name.
144 // The package name is not part of this name.
145 func (d *Descriptor) TypeName() []string {
146 if d.typename != nil {
150 for parent := d; parent != nil; parent = parent.parent {
153 s := make([]string, n)
154 for parent := d; parent != nil; parent = parent.parent {
156 s[n] = parent.GetName()
162 // EnumDescriptor describes an enum. If it's at top level, its parent will be nil.
163 // Otherwise it will be the descriptor of the message in which it is defined.
164 type EnumDescriptor struct {
166 *descriptor.EnumDescriptorProto
167 parent *Descriptor // The containing message, if any.
168 typename []string // Cached typename vector.
169 index int // The index into the container, whether the file or a message.
170 path string // The SourceCodeInfo path as comma-separated integers.
173 // TypeName returns the elements of the dotted type name.
174 // The package name is not part of this name.
175 func (e *EnumDescriptor) TypeName() (s []string) {
176 if e.typename != nil {
181 s = make([]string, 1)
183 pname := e.parent.TypeName()
184 s = make([]string, len(pname)+1)
192 // Everything but the last element of the full type name, CamelCased.
193 // The values of type Foo.Bar are call Foo_value1... not Foo_Bar_value1... .
194 func (e *EnumDescriptor) prefix() string {
196 // If the enum is not part of a message, the prefix is just the type name.
197 return CamelCase(*e.Name) + "_"
199 typeName := e.TypeName()
200 return CamelCaseSlice(typeName[0:len(typeName)-1]) + "_"
203 // The integer value of the named constant in this enumerated type.
204 func (e *EnumDescriptor) integerValueAsString(name string) string {
205 for _, c := range e.Value {
206 if c.GetName() == name {
207 return fmt.Sprint(c.GetNumber())
210 log.Fatal("cannot find value for enum constant")
214 // ExtensionDescriptor describes an extension. If it's at top level, its parent will be nil.
215 // Otherwise it will be the descriptor of the message in which it is defined.
216 type ExtensionDescriptor struct {
218 *descriptor.FieldDescriptorProto
219 parent *Descriptor // The containing message, if any.
222 // TypeName returns the elements of the dotted type name.
223 // The package name is not part of this name.
224 func (e *ExtensionDescriptor) TypeName() (s []string) {
227 // top-level extension
228 s = make([]string, 1)
230 pname := e.parent.TypeName()
231 s = make([]string, len(pname)+1)
238 // DescName returns the variable name used for the generated descriptor.
239 func (e *ExtensionDescriptor) DescName() string {
240 // The full type name.
241 typeName := e.TypeName()
242 // Each scope of the extension is individually CamelCased, and all are joined with "_" with an "E_" prefix.
243 for i, s := range typeName {
244 typeName[i] = CamelCase(s)
246 return "E_" + strings.Join(typeName, "_")
249 // ImportedDescriptor describes a type that has been publicly imported from another file.
250 type ImportedDescriptor struct {
255 func (id *ImportedDescriptor) TypeName() []string { return id.o.TypeName() }
257 // FileDescriptor describes an protocol buffer descriptor file (.proto).
258 // It includes slices of all the messages and enums defined within it.
259 // Those slices are constructed by WrapTypes.
260 type FileDescriptor struct {
261 *descriptor.FileDescriptorProto
262 desc []*Descriptor // All the messages defined in this file.
263 enum []*EnumDescriptor // All the enums defined in this file.
264 ext []*ExtensionDescriptor // All the top-level extensions defined in this file.
265 imp []*ImportedDescriptor // All types defined in files publicly imported by this file.
267 // Comments, stored as a map of path (comma-separated integers) to the comment.
268 comments map[string]*descriptor.SourceCodeInfo_Location
270 // The full list of symbols that are exported,
271 // as a map from the exported object to its symbols.
272 // This is used for supporting public imports.
273 exported map[Object][]symbol
275 importPath GoImportPath // Import path of this file's package.
276 packageName GoPackageName // Name of this file's Go package.
278 proto3 bool // whether to generate proto3 code for this file
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.
284 func (d *FileDescriptor) VarName() string {
285 h := sha256.Sum256([]byte(d.GetName()))
286 return fmt.Sprintf("fileDescriptor_%s", hex.EncodeToString(h[:8]))
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).
293 func (d *FileDescriptor) goPackageOption() (impPath GoImportPath, pkg GoPackageName, ok bool) {
294 opt := d.GetOptions().GetGoPackage()
298 // A semicolon-delimited suffix delimits the import path and package name.
299 sc := strings.Index(opt, ";")
301 return GoImportPath(opt[:sc]), cleanPackageName(opt[sc+1:]), true
303 // The presence of a slash implies there's an import path.
304 slash := strings.LastIndex(opt, "/")
306 return GoImportPath(opt), cleanPackageName(opt[slash+1:]), true
308 return "", cleanPackageName(opt), true
311 // goFileName returns the output name for the generated Go file.
312 func (d *FileDescriptor) goFileName(pathType pathType) string {
314 if ext := path.Ext(name); ext == ".proto" || ext == ".protodevel" {
315 name = name[:len(name)-len(ext)]
319 if pathType == pathTypeSourceRelative {
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)
335 func (d *FileDescriptor) addExport(obj Object, sym symbol) {
336 d.exported[obj] = append(d.exported[obj], sym)
339 // symbol is an interface representing an exported Go symbol.
340 type symbol interface {
341 // GenerateAlias should generate an appropriate alias
342 // for the symbol from the named package.
343 GenerateAlias(g *Generator, filename string, pkg GoPackageName)
346 type messageSymbol struct {
348 hasExtensions, isMessageSet bool
352 type getterSymbol struct {
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)
359 func (ms *messageSymbol) GenerateAlias(g *Generator, filename string, pkg GoPackageName) {
360 g.P("// ", ms.sym, " from public import ", filename)
361 g.P("type ", ms.sym, " = ", pkg, ".", ms.sym)
362 for _, name := range ms.oneofTypes {
363 g.P("type ", name, " = ", pkg, ".", name)
367 type enumSymbol struct {
369 proto3 bool // Whether this came from a proto3 file.
372 func (es enumSymbol) GenerateAlias(g *Generator, filename string, pkg GoPackageName) {
374 g.P("// ", s, " from public import ", filename)
375 g.P("type ", s, " = ", pkg, ".", s)
376 g.P("var ", s, "_name = ", pkg, ".", s, "_name")
377 g.P("var ", s, "_value = ", pkg, ".", s, "_value")
380 type constOrVarSymbol struct {
382 typ string // either "const" or "var"
383 cast string // if non-empty, a type cast is required (used for enums)
386 func (cs constOrVarSymbol) GenerateAlias(g *Generator, filename string, pkg GoPackageName) {
387 v := string(pkg) + "." + cs.sym
389 v = cs.cast + "(" + v + ")"
391 g.P(cs.typ, " ", cs.sym, " = ", v)
394 // Object is an interface abstracting the abilities shared by enums, messages, extensions and imported objects.
395 type Object interface {
396 GoImportPath() GoImportPath
398 File() *FileDescriptor
401 // Generator is the type whose methods generate the output, stored in the associated response structure.
402 type Generator struct {
405 Request *plugin.CodeGeneratorRequest // The input.
406 Response *plugin.CodeGeneratorResponse // The output.
408 Param map[string]string // Command-line parameters.
409 PackageImportPath string // Go import path of the package we're generating code for
410 ImportPrefix string // String to prefix to imported package file names.
411 ImportMap map[string]string // Mapping from .proto file name to import path
413 Pkg map[string]string // The names under which we import support packages
415 outputImportPath GoImportPath // Package we're generating code for.
416 allFiles []*FileDescriptor // All files in the tree
417 allFilesByName map[string]*FileDescriptor // All files by filename.
418 genFiles []*FileDescriptor // Those files we will generate output for.
419 file *FileDescriptor // The file we are compiling now.
420 packageNames map[GoImportPath]GoPackageName // Imported package names in the current file.
421 usedPackages map[GoImportPath]bool // Packages used in current file.
422 usedPackageNames map[GoPackageName]bool // Package names used in the current file.
423 addedImports map[GoImportPath]bool // Additional imports to emit.
424 typeNameToObject map[string]Object // Key is a fully-qualified name in input syntax.
425 init []string // Lines to emit in the init function.
427 pathType pathType // How to generate output filenames.
429 annotateCode bool // whether to store annotations
430 annotations []*descriptor.GeneratedCodeInfo_Annotation // annotations to store
436 pathTypeImport pathType = iota
437 pathTypeSourceRelative
440 // New creates a new generator and allocates the request and response protobufs.
441 func New() *Generator {
443 g.Buffer = new(bytes.Buffer)
444 g.Request = new(plugin.CodeGeneratorRequest)
445 g.Response = new(plugin.CodeGeneratorResponse)
449 // Error reports a problem, including an error, and exits the program.
450 func (g *Generator) Error(err error, msgs ...string) {
451 s := strings.Join(msgs, " ") + ":" + err.Error()
452 log.Print("protoc-gen-go: error:", s)
456 // Fail reports a problem and exits the program.
457 func (g *Generator) Fail(msgs ...string) {
458 s := strings.Join(msgs, " ")
459 log.Print("protoc-gen-go: error:", s)
463 // CommandLineParameters breaks the comma-separated list of key=value pairs
464 // in the parameter (a member of the request protobuf) into a key/value map.
465 // It then sets file name mappings defined by those entries.
466 func (g *Generator) CommandLineParameters(parameter string) {
467 g.Param = make(map[string]string)
468 for _, p := range strings.Split(parameter, ",") {
469 if i := strings.Index(p, "="); i < 0 {
472 g.Param[p[0:i]] = p[i+1:]
476 g.ImportMap = make(map[string]string)
477 pluginList := "none" // Default list of plugin names to enable (empty means all).
478 for k, v := range g.Param {
480 case "import_prefix":
483 g.PackageImportPath = v
487 g.pathType = pathTypeImport
488 case "source_relative":
489 g.pathType = pathTypeSourceRelative
491 g.Fail(fmt.Sprintf(`Unknown path type %q: want "import" or "source_relative".`, v))
495 case "annotate_code":
497 g.annotateCode = true
500 if len(k) > 0 && k[0] == 'M' {
501 g.ImportMap[k[1:]] = v
505 if pluginList != "" {
506 // Amend the set of plugins.
507 enabled := make(map[string]bool)
508 for _, name := range strings.Split(pluginList, "+") {
511 var nplugins []Plugin
512 for _, p := range plugins {
513 if enabled[p.Name()] {
514 nplugins = append(nplugins, p)
521 // DefaultPackageName returns the package name printed for the object.
522 // If its file is in a different package, it returns the package name we're using for this file, plus ".".
523 // Otherwise it returns the empty string.
524 func (g *Generator) DefaultPackageName(obj Object) string {
525 importPath := obj.GoImportPath()
526 if importPath == g.outputImportPath {
529 return string(g.GoPackageName(importPath)) + "."
532 // GoPackageName returns the name used for a package.
533 func (g *Generator) GoPackageName(importPath GoImportPath) GoPackageName {
534 if name, ok := g.packageNames[importPath]; ok {
537 name := cleanPackageName(baseName(string(importPath)))
538 for i, orig := 1, name; g.usedPackageNames[name] || isGoPredeclaredIdentifier[string(name)]; i++ {
539 name = orig + GoPackageName(strconv.Itoa(i))
541 g.packageNames[importPath] = name
542 g.usedPackageNames[name] = true
546 // AddImport adds a package to the generated file's import section.
547 // It returns the name used for the package.
548 func (g *Generator) AddImport(importPath GoImportPath) GoPackageName {
549 g.addedImports[importPath] = true
550 return g.GoPackageName(importPath)
553 var globalPackageNames = map[GoPackageName]bool{
559 // Create and remember a guaranteed unique package name. Pkg is the candidate name.
560 // The FileDescriptor parameter is unused.
561 func RegisterUniquePackageName(pkg string, f *FileDescriptor) string {
562 name := cleanPackageName(pkg)
563 for i, orig := 1, name; globalPackageNames[name]; i++ {
564 name = orig + GoPackageName(strconv.Itoa(i))
566 globalPackageNames[name] = true
570 var isGoKeyword = map[string]bool{
598 var isGoPredeclaredIdentifier = map[string]bool{
640 func cleanPackageName(name string) GoPackageName {
641 name = strings.Map(badToUnderscore, name)
642 // Identifier must not be keyword or predeclared identifier: insert _.
643 if isGoKeyword[name] {
646 // Identifier must not begin with digit: insert _.
647 if r, _ := utf8.DecodeRuneInString(name); unicode.IsDigit(r) {
650 return GoPackageName(name)
653 // defaultGoPackage returns the package name to use,
654 // derived from the import path of the package we're building code for.
655 func (g *Generator) defaultGoPackage() GoPackageName {
656 p := g.PackageImportPath
657 if i := strings.LastIndex(p, "/"); i >= 0 {
660 return cleanPackageName(p)
663 // SetPackageNames sets the package name for this run.
664 // The package name must agree across all files being generated.
665 // It also defines unique package names for all imported files.
666 func (g *Generator) SetPackageNames() {
667 g.outputImportPath = g.genFiles[0].importPath
669 defaultPackageNames := make(map[GoImportPath]GoPackageName)
670 for _, f := range g.genFiles {
671 if _, p, ok := f.goPackageOption(); ok {
672 defaultPackageNames[f.importPath] = p
675 for _, f := range g.genFiles {
676 if _, p, ok := f.goPackageOption(); ok {
677 // Source file: option go_package = "quux/bar";
679 } else if p, ok := defaultPackageNames[f.importPath]; ok {
680 // A go_package option in another file in the same package.
682 // This is a poor choice in general, since every source file should
683 // contain a go_package option. Supported mainly for historical
686 } else if p := g.defaultGoPackage(); p != "" {
687 // Command-line: import_path=quux/bar.
689 // The import_path flag sets a package name for files which don't
690 // contain a go_package option.
692 } else if p := f.GetPackage(); p != "" {
693 // Source file: package quux.bar;
694 f.packageName = cleanPackageName(p)
697 f.packageName = cleanPackageName(baseName(f.GetName()))
701 // Check that all files have a consistent package name and import path.
702 for _, f := range g.genFiles[1:] {
703 if a, b := g.genFiles[0].importPath, f.importPath; a != b {
704 g.Fail(fmt.Sprintf("inconsistent package import paths: %v, %v", a, b))
706 if a, b := g.genFiles[0].packageName, f.packageName; a != b {
707 g.Fail(fmt.Sprintf("inconsistent package names: %v, %v", a, b))
711 // Names of support packages. These never vary (if there are conflicts,
712 // we rename the conflicting package), so this could be removed someday.
713 g.Pkg = map[string]string{
720 // WrapTypes walks the incoming data, wrapping DescriptorProtos, EnumDescriptorProtos
721 // and FileDescriptorProtos into file-referenced objects within the Generator.
722 // It also creates the list of files to generate and so should be called before GenerateAllFiles.
723 func (g *Generator) WrapTypes() {
724 g.allFiles = make([]*FileDescriptor, 0, len(g.Request.ProtoFile))
725 g.allFilesByName = make(map[string]*FileDescriptor, len(g.allFiles))
726 genFileNames := make(map[string]bool)
727 for _, n := range g.Request.FileToGenerate {
728 genFileNames[n] = true
730 for _, f := range g.Request.ProtoFile {
731 fd := &FileDescriptor{
732 FileDescriptorProto: f,
733 exported: make(map[Object][]symbol),
734 proto3: fileIsProto3(f),
736 // The import path may be set in a number of ways.
737 if substitution, ok := g.ImportMap[f.GetName()]; ok {
738 // Command-line: M=foo.proto=quux/bar.
740 // Explicit mapping of source file to import path.
741 fd.importPath = GoImportPath(substitution)
742 } else if genFileNames[f.GetName()] && g.PackageImportPath != "" {
743 // Command-line: import_path=quux/bar.
745 // The import_path flag sets the import path for every file that
746 // we generate code for.
747 fd.importPath = GoImportPath(g.PackageImportPath)
748 } else if p, _, _ := fd.goPackageOption(); p != "" {
749 // Source file: option go_package = "quux/bar";
751 // The go_package option sets the import path. Most users should use this.
756 // Last resort when nothing else is available.
757 fd.importPath = GoImportPath(path.Dir(f.GetName()))
759 // We must wrap the descriptors before we wrap the enums
760 fd.desc = wrapDescriptors(fd)
761 g.buildNestedDescriptors(fd.desc)
762 fd.enum = wrapEnumDescriptors(fd, fd.desc)
763 g.buildNestedEnums(fd.desc, fd.enum)
764 fd.ext = wrapExtensions(fd)
766 g.allFiles = append(g.allFiles, fd)
767 g.allFilesByName[f.GetName()] = fd
769 for _, fd := range g.allFiles {
770 fd.imp = wrapImported(fd, g)
773 g.genFiles = make([]*FileDescriptor, 0, len(g.Request.FileToGenerate))
774 for _, fileName := range g.Request.FileToGenerate {
775 fd := g.allFilesByName[fileName]
777 g.Fail("could not find file named", fileName)
779 g.genFiles = append(g.genFiles, fd)
783 // Scan the descriptors in this file. For each one, build the slice of nested descriptors
784 func (g *Generator) buildNestedDescriptors(descs []*Descriptor) {
785 for _, desc := range descs {
786 if len(desc.NestedType) != 0 {
787 for _, nest := range descs {
788 if nest.parent == desc {
789 desc.nested = append(desc.nested, nest)
792 if len(desc.nested) != len(desc.NestedType) {
793 g.Fail("internal error: nesting failure for", desc.GetName())
799 func (g *Generator) buildNestedEnums(descs []*Descriptor, enums []*EnumDescriptor) {
800 for _, desc := range descs {
801 if len(desc.EnumType) != 0 {
802 for _, enum := range enums {
803 if enum.parent == desc {
804 desc.enums = append(desc.enums, enum)
807 if len(desc.enums) != len(desc.EnumType) {
808 g.Fail("internal error: enum nesting failure for", desc.GetName())
814 // Construct the Descriptor
815 func newDescriptor(desc *descriptor.DescriptorProto, parent *Descriptor, file *FileDescriptor, index int) *Descriptor {
817 common: common{file},
818 DescriptorProto: desc,
823 d.path = fmt.Sprintf("%d,%d", messagePath, index)
825 d.path = fmt.Sprintf("%s,%d,%d", parent.path, messageMessagePath, index)
828 // The only way to distinguish a group from a message is whether
829 // the containing message has a TYPE_GROUP field that matches.
831 parts := d.TypeName()
832 if file.Package != nil {
833 parts = append([]string{*file.Package}, parts...)
835 exp := "." + strings.Join(parts, ".")
836 for _, field := range parent.Field {
837 if field.GetType() == descriptor.FieldDescriptorProto_TYPE_GROUP && field.GetTypeName() == exp {
844 for _, field := range desc.Extension {
845 d.ext = append(d.ext, &ExtensionDescriptor{common{file}, field, d})
851 // Return a slice of all the Descriptors defined within this file
852 func wrapDescriptors(file *FileDescriptor) []*Descriptor {
853 sl := make([]*Descriptor, 0, len(file.MessageType)+10)
854 for i, desc := range file.MessageType {
855 sl = wrapThisDescriptor(sl, desc, nil, file, i)
860 // Wrap this Descriptor, recursively
861 func wrapThisDescriptor(sl []*Descriptor, desc *descriptor.DescriptorProto, parent *Descriptor, file *FileDescriptor, index int) []*Descriptor {
862 sl = append(sl, newDescriptor(desc, parent, file, index))
864 for i, nested := range desc.NestedType {
865 sl = wrapThisDescriptor(sl, nested, me, file, i)
870 // Construct the EnumDescriptor
871 func newEnumDescriptor(desc *descriptor.EnumDescriptorProto, parent *Descriptor, file *FileDescriptor, index int) *EnumDescriptor {
872 ed := &EnumDescriptor{
873 common: common{file},
874 EnumDescriptorProto: desc,
879 ed.path = fmt.Sprintf("%d,%d", enumPath, index)
881 ed.path = fmt.Sprintf("%s,%d,%d", parent.path, messageEnumPath, index)
886 // Return a slice of all the EnumDescriptors defined within this file
887 func wrapEnumDescriptors(file *FileDescriptor, descs []*Descriptor) []*EnumDescriptor {
888 sl := make([]*EnumDescriptor, 0, len(file.EnumType)+10)
890 for i, enum := range file.EnumType {
891 sl = append(sl, newEnumDescriptor(enum, nil, file, i))
893 // Enums within messages. Enums within embedded messages appear in the outer-most message.
894 for _, nested := range descs {
895 for i, enum := range nested.EnumType {
896 sl = append(sl, newEnumDescriptor(enum, nested, file, i))
902 // Return a slice of all the top-level ExtensionDescriptors defined within this file.
903 func wrapExtensions(file *FileDescriptor) []*ExtensionDescriptor {
904 var sl []*ExtensionDescriptor
905 for _, field := range file.Extension {
906 sl = append(sl, &ExtensionDescriptor{common{file}, field, nil})
911 // Return a slice of all the types that are publicly imported into this file.
912 func wrapImported(file *FileDescriptor, g *Generator) (sl []*ImportedDescriptor) {
913 for _, index := range file.PublicDependency {
914 df := g.fileByName(file.Dependency[index])
915 for _, d := range df.desc {
916 if d.GetOptions().GetMapEntry() {
919 sl = append(sl, &ImportedDescriptor{common{file}, d})
921 for _, e := range df.enum {
922 sl = append(sl, &ImportedDescriptor{common{file}, e})
924 for _, ext := range df.ext {
925 sl = append(sl, &ImportedDescriptor{common{file}, ext})
931 func extractComments(file *FileDescriptor) {
932 file.comments = make(map[string]*descriptor.SourceCodeInfo_Location)
933 for _, loc := range file.GetSourceCodeInfo().GetLocation() {
934 if loc.LeadingComments == nil {
938 for _, n := range loc.Path {
939 p = append(p, strconv.Itoa(int(n)))
941 file.comments[strings.Join(p, ",")] = loc
945 // BuildTypeNameMap builds the map from fully qualified type names to objects.
946 // The key names for the map come from the input data, which puts a period at the beginning.
947 // It should be called after SetPackageNames and before GenerateAllFiles.
948 func (g *Generator) BuildTypeNameMap() {
949 g.typeNameToObject = make(map[string]Object)
950 for _, f := range g.allFiles {
951 // The names in this loop are defined by the proto world, not us, so the
952 // package name may be empty. If so, the dotted package name of X will
953 // be ".X"; otherwise it will be ".pkg.X".
954 dottedPkg := "." + f.GetPackage()
955 if dottedPkg != "." {
958 for _, enum := range f.enum {
959 name := dottedPkg + dottedSlice(enum.TypeName())
960 g.typeNameToObject[name] = enum
962 for _, desc := range f.desc {
963 name := dottedPkg + dottedSlice(desc.TypeName())
964 g.typeNameToObject[name] = desc
969 // ObjectNamed, given a fully-qualified input type name as it appears in the input data,
970 // returns the descriptor for the message or enum with that name.
971 func (g *Generator) ObjectNamed(typeName string) Object {
972 o, ok := g.typeNameToObject[typeName]
974 g.Fail("can't find object with type", typeName)
979 // AnnotatedAtoms is a list of atoms (as consumed by P) that records the file name and proto AST path from which they originated.
980 type AnnotatedAtoms struct {
986 // Annotate records the file name and proto AST path of a list of atoms
987 // so that a later call to P can emit a link from each atom to its origin.
988 func Annotate(file *FileDescriptor, path string, atoms ...interface{}) *AnnotatedAtoms {
989 return &AnnotatedAtoms{source: *file.Name, path: path, atoms: atoms}
992 // printAtom prints the (atomic, non-annotation) argument to the generated output.
993 func (g *Generator) printAtom(v interface{}) {
994 switch v := v.(type) {
1014 g.WriteString(string(v))
1016 g.WriteString(strconv.Quote(string(v)))
1018 g.Fail(fmt.Sprintf("unknown type in printer: %T", v))
1022 // P prints the arguments to the generated output. It handles strings and int32s, plus
1023 // handling indirections because they may be *string, etc. Any inputs of type AnnotatedAtoms may emit
1024 // annotations in a .meta file in addition to outputting the atoms themselves (if g.annotateCode
1026 func (g *Generator) P(str ...interface{}) {
1030 g.WriteString(g.indent)
1031 for _, v := range str {
1032 switch v := v.(type) {
1033 case *AnnotatedAtoms:
1034 begin := int32(g.Len())
1035 for _, v := range v.atoms {
1039 end := int32(g.Len())
1041 for _, token := range strings.Split(v.path, ",") {
1042 val, err := strconv.ParseInt(token, 10, 32)
1044 g.Fail("could not parse proto AST path: ", err.Error())
1046 path = append(path, int32(val))
1048 g.annotations = append(g.annotations, &descriptor.GeneratedCodeInfo_Annotation{
1050 SourceFile: &v.source,
1062 // addInitf stores the given statement to be printed inside the file's init function.
1063 // The statement is given as a format specifier and arguments.
1064 func (g *Generator) addInitf(stmt string, a ...interface{}) {
1065 g.init = append(g.init, fmt.Sprintf(stmt, a...))
1068 // In Indents the output one tab stop.
1069 func (g *Generator) In() { g.indent += "\t" }
1071 // Out unindents the output one tab stop.
1072 func (g *Generator) Out() {
1073 if len(g.indent) > 0 {
1074 g.indent = g.indent[1:]
1078 // GenerateAllFiles generates the output for all the files we're outputting.
1079 func (g *Generator) GenerateAllFiles() {
1080 // Initialize the plugins
1081 for _, p := range plugins {
1084 // Generate the output. The generator runs for every file, even the files
1085 // that we don't generate output for, so that we can collate the full list
1086 // of exported symbols to support public imports.
1087 genFileMap := make(map[*FileDescriptor]bool, len(g.genFiles))
1088 for _, file := range g.genFiles {
1089 genFileMap[file] = true
1091 for _, file := range g.allFiles {
1094 g.writeOutput = genFileMap[file]
1099 fname := file.goFileName(g.pathType)
1100 g.Response.File = append(g.Response.File, &plugin.CodeGeneratorResponse_File{
1101 Name: proto.String(fname),
1102 Content: proto.String(g.String()),
1105 // Store the generated code annotations in text, as the protoc plugin protocol requires that
1106 // strings contain valid UTF-8.
1107 g.Response.File = append(g.Response.File, &plugin.CodeGeneratorResponse_File{
1108 Name: proto.String(file.goFileName(g.pathType) + ".meta"),
1109 Content: proto.String(proto.CompactTextString(&descriptor.GeneratedCodeInfo{Annotation: g.annotations})),
1115 // Run all the plugins associated with the file.
1116 func (g *Generator) runPlugins(file *FileDescriptor) {
1117 for _, p := range plugins {
1122 // Fill the response protocol buffer with the generated output for all the files we're
1123 // supposed to generate.
1124 func (g *Generator) generate(file *FileDescriptor) {
1126 g.usedPackages = make(map[GoImportPath]bool)
1127 g.packageNames = make(map[GoImportPath]GoPackageName)
1128 g.usedPackageNames = make(map[GoPackageName]bool)
1129 g.addedImports = make(map[GoImportPath]bool)
1130 for name := range globalPackageNames {
1131 g.usedPackageNames[name] = true
1134 g.P("// This is a compile-time assertion to ensure that this generated file")
1135 g.P("// is compatible with the proto package it is being compiled against.")
1136 g.P("// A compilation error at this line likely means your copy of the")
1137 g.P("// proto package needs to be updated.")
1138 g.P("const _ = ", g.Pkg["proto"], ".ProtoPackageIsVersion", generatedCodeVersion, " // please upgrade the proto package")
1141 for _, td := range g.file.imp {
1142 g.generateImported(td)
1144 for _, enum := range g.file.enum {
1145 g.generateEnum(enum)
1147 for _, desc := range g.file.desc {
1148 // Don't generate virtual messages for maps.
1149 if desc.GetOptions().GetMapEntry() {
1152 g.generateMessage(desc)
1154 for _, ext := range g.file.ext {
1155 g.generateExtension(ext)
1157 g.generateInitFunction()
1158 g.generateFileDescriptor(file)
1160 // Run the plugins before the imports so we know which imports are necessary.
1163 // Generate header and imports last, though they appear first in the output.
1165 remAnno := g.annotations
1166 g.Buffer = new(bytes.Buffer)
1173 // Adjust the offsets for annotations displaced by the header and imports.
1174 for _, anno := range remAnno {
1175 *anno.Begin += int32(g.Len())
1176 *anno.End += int32(g.Len())
1177 g.annotations = append(g.annotations, anno)
1179 g.Write(rem.Bytes())
1181 // Reformat generated code and patch annotation locations.
1182 fset := token.NewFileSet()
1183 original := g.Bytes()
1185 // make a copy independent of g; we'll need it after Reset.
1186 original = append([]byte(nil), original...)
1188 fileAST, err := parser.ParseFile(fset, "", original, parser.ParseComments)
1190 // Print out the bad code with line numbers.
1191 // This should never happen in practice, but it can while changing generated code,
1192 // so consider this a debugging aid.
1193 var src bytes.Buffer
1194 s := bufio.NewScanner(bytes.NewReader(original))
1195 for line := 1; s.Scan(); line++ {
1196 fmt.Fprintf(&src, "%5d\t%s\n", line, s.Bytes())
1198 g.Fail("bad Go source code was generated:", err.Error(), "\n"+src.String())
1200 ast.SortImports(fset, fileAST)
1202 err = (&printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}).Fprint(g, fset, fileAST)
1204 g.Fail("generated Go source code could not be reformatted:", err.Error())
1207 m, err := remap.Compute(original, g.Bytes())
1209 g.Fail("formatted generated Go source code could not be mapped back to the original code:", err.Error())
1211 for _, anno := range g.annotations {
1212 new, ok := m.Find(int(*anno.Begin), int(*anno.End))
1214 g.Fail("span in formatted generated Go source code could not be mapped back to the original code")
1216 *anno.Begin = int32(new.Pos)
1217 *anno.End = int32(new.End)
1222 // Generate the header, including package definition
1223 func (g *Generator) generateHeader() {
1224 g.P("// Code generated by protoc-gen-go. DO NOT EDIT.")
1225 if g.file.GetOptions().GetDeprecated() {
1226 g.P("// ", g.file.Name, " is a deprecated file.")
1228 g.P("// source: ", g.file.Name)
1231 g.PrintComments(strconv.Itoa(packagePath))
1233 g.P("package ", g.file.packageName)
1237 // deprecationComment is the standard comment added to deprecated
1238 // messages, fields, enums, and enum values.
1239 var deprecationComment = "// Deprecated: Do not use."
1241 // PrintComments prints any comments from the source .proto file.
1242 // The path is a comma-separated list of integers.
1243 // It returns an indication of whether any comments were printed.
1244 // See descriptor.proto for its format.
1245 func (g *Generator) PrintComments(path string) bool {
1249 if c, ok := g.makeComments(path); ok {
1256 // makeComments generates the comment string for the field, no "\n" at the end
1257 func (g *Generator) makeComments(path string) (string, bool) {
1258 loc, ok := g.file.comments[path]
1262 w := new(bytes.Buffer)
1264 for _, line := range strings.Split(strings.TrimSuffix(loc.GetLeadingComments(), "\n"), "\n") {
1265 fmt.Fprintf(w, "%s//%s", nl, line)
1268 return w.String(), true
1271 func (g *Generator) fileByName(filename string) *FileDescriptor {
1272 return g.allFilesByName[filename]
1275 // weak returns whether the ith import of the current file is a weak import.
1276 func (g *Generator) weak(i int32) bool {
1277 for _, j := range g.file.WeakDependency {
1285 // Generate the imports
1286 func (g *Generator) generateImports() {
1287 imports := make(map[GoImportPath]GoPackageName)
1288 for i, s := range g.file.Dependency {
1289 fd := g.fileByName(s)
1290 importPath := fd.importPath
1291 // Do not import our own package.
1292 if importPath == g.file.importPath {
1295 // Do not import weak imports.
1296 if g.weak(int32(i)) {
1299 // Do not import a package twice.
1300 if _, ok := imports[importPath]; ok {
1303 // We need to import all the dependencies, even if we don't reference them,
1304 // because other code and tools depend on having the full transitive closure
1305 // of protocol buffer types in the binary.
1306 packageName := g.GoPackageName(importPath)
1307 if _, ok := g.usedPackages[importPath]; !ok {
1310 imports[importPath] = packageName
1312 for importPath := range g.addedImports {
1313 imports[importPath] = g.GoPackageName(importPath)
1315 // We almost always need a proto import. Rather than computing when we
1316 // do, which is tricky when there's a plugin, just import it and
1317 // reference it later. The same argument applies to the fmt and math packages.
1319 g.P(g.Pkg["fmt"] + ` "fmt"`)
1320 g.P(g.Pkg["math"] + ` "math"`)
1321 g.P(g.Pkg["proto"]+" ", GoImportPath(g.ImportPrefix)+"github.com/golang/protobuf/proto")
1322 for importPath, packageName := range imports {
1323 g.P(packageName, " ", GoImportPath(g.ImportPrefix)+importPath)
1327 // TODO: may need to worry about uniqueness across plugins
1328 for _, p := range plugins {
1329 p.GenerateImports(g.file)
1332 g.P("// Reference imports to suppress errors if they are not otherwise used.")
1333 g.P("var _ = ", g.Pkg["proto"], ".Marshal")
1334 g.P("var _ = ", g.Pkg["fmt"], ".Errorf")
1335 g.P("var _ = ", g.Pkg["math"], ".Inf")
1339 func (g *Generator) generateImported(id *ImportedDescriptor) {
1341 filename := *df.Name
1342 if df.importPath == g.file.importPath {
1343 // Don't generate type aliases for files in the same Go package as this one.
1346 if !supportTypeAliases {
1347 g.Fail(fmt.Sprintf("%s: public imports require at least go1.9", filename))
1349 g.usedPackages[df.importPath] = true
1351 for _, sym := range df.exported[id.o] {
1352 sym.GenerateAlias(g, filename, g.GoPackageName(df.importPath))
1358 // Generate the enum definitions for this EnumDescriptor.
1359 func (g *Generator) generateEnum(enum *EnumDescriptor) {
1360 // The full type name
1361 typeName := enum.TypeName()
1362 // The full type name, CamelCased.
1363 ccTypeName := CamelCaseSlice(typeName)
1364 ccPrefix := enum.prefix()
1366 deprecatedEnum := ""
1367 if enum.GetOptions().GetDeprecated() {
1368 deprecatedEnum = deprecationComment
1370 g.PrintComments(enum.path)
1371 g.P("type ", Annotate(enum.file, enum.path, ccTypeName), " int32", deprecatedEnum)
1372 g.file.addExport(enum, enumSymbol{ccTypeName, enum.proto3()})
1374 for i, e := range enum.Value {
1375 etorPath := fmt.Sprintf("%s,%d,%d", enum.path, enumValuePath, i)
1376 g.PrintComments(etorPath)
1378 deprecatedValue := ""
1379 if e.GetOptions().GetDeprecated() {
1380 deprecatedValue = deprecationComment
1383 name := ccPrefix + *e.Name
1384 g.P(Annotate(enum.file, etorPath, name), " ", ccTypeName, " = ", e.Number, " ", deprecatedValue)
1385 g.file.addExport(enum, constOrVarSymbol{name, "const", ccTypeName})
1389 g.P("var ", ccTypeName, "_name = map[int32]string{")
1390 generated := make(map[int32]bool) // avoid duplicate values
1391 for _, e := range enum.Value {
1393 if _, present := generated[*e.Number]; present {
1394 duplicate = "// Duplicate value: "
1396 g.P(duplicate, e.Number, ": ", strconv.Quote(*e.Name), ",")
1397 generated[*e.Number] = true
1401 g.P("var ", ccTypeName, "_value = map[string]int32{")
1402 for _, e := range enum.Value {
1403 g.P(strconv.Quote(*e.Name), ": ", e.Number, ",")
1409 g.P("func (x ", ccTypeName, ") Enum() *", ccTypeName, " {")
1410 g.P("p := new(", ccTypeName, ")")
1417 g.P("func (x ", ccTypeName, ") String() string {")
1418 g.P("return ", g.Pkg["proto"], ".EnumName(", ccTypeName, "_name, int32(x))")
1423 g.P("func (x *", ccTypeName, ") UnmarshalJSON(data []byte) error {")
1424 g.P("value, err := ", g.Pkg["proto"], ".UnmarshalJSONEnum(", ccTypeName, `_value, data, "`, ccTypeName, `")`)
1425 g.P("if err != nil {")
1428 g.P("*x = ", ccTypeName, "(value)")
1434 var indexes []string
1435 for m := enum.parent; m != nil; m = m.parent {
1436 // XXX: skip groups?
1437 indexes = append([]string{strconv.Itoa(m.index)}, indexes...)
1439 indexes = append(indexes, strconv.Itoa(enum.index))
1440 g.P("func (", ccTypeName, ") EnumDescriptor() ([]byte, []int) {")
1441 g.P("return ", g.file.VarName(), ", []int{", strings.Join(indexes, ", "), "}")
1444 if enum.file.GetPackage() == "google.protobuf" && enum.GetName() == "NullValue" {
1445 g.P("func (", ccTypeName, `) XXX_WellKnownType() string { return "`, enum.GetName(), `" }`)
1449 g.generateEnumRegistration(enum)
1452 // The tag is a string like "varint,2,opt,name=fieldname,def=7" that
1453 // identifies details of the field for the protocol buffer marshaling and unmarshaling
1454 // code. The fields are:
1456 // protocol tag number
1457 // opt,req,rep for optional, required, or repeated
1458 // packed whether the encoding is "packed" (optional; repeated primitives only)
1459 // name= the original declared name
1460 // enum= the name of the enum type if it is an enum-typed field.
1461 // proto3 if this field is in a proto3 message
1462 // def= string representation of the default value, if any.
1463 // The default value must be in a representation that can be used at run-time
1464 // to generate the default value. Thus bools become 0 and 1, for instance.
1465 func (g *Generator) goTag(message *Descriptor, field *descriptor.FieldDescriptorProto, wiretype string) string {
1468 case isOptional(field):
1470 case isRequired(field):
1472 case isRepeated(field):
1475 var defaultValue string
1476 if dv := field.DefaultValue; dv != nil { // set means an explicit default
1478 // Some types need tweaking.
1479 switch *field.Type {
1480 case descriptor.FieldDescriptorProto_TYPE_BOOL:
1481 if defaultValue == "true" {
1486 case descriptor.FieldDescriptorProto_TYPE_STRING,
1487 descriptor.FieldDescriptorProto_TYPE_BYTES:
1488 // Nothing to do. Quoting is done for the whole tag.
1489 case descriptor.FieldDescriptorProto_TYPE_ENUM:
1490 // For enums we need to provide the integer constant.
1491 obj := g.ObjectNamed(field.GetTypeName())
1492 if id, ok := obj.(*ImportedDescriptor); ok {
1493 // It is an enum that was publicly imported.
1494 // We need the underlying type.
1497 enum, ok := obj.(*EnumDescriptor)
1499 log.Printf("obj is a %T", obj)
1500 if id, ok := obj.(*ImportedDescriptor); ok {
1501 log.Printf("id.o is a %T", id.o)
1503 g.Fail("unknown enum type", CamelCaseSlice(obj.TypeName()))
1505 defaultValue = enum.integerValueAsString(defaultValue)
1506 case descriptor.FieldDescriptorProto_TYPE_FLOAT:
1507 if def := defaultValue; def != "inf" && def != "-inf" && def != "nan" {
1508 if f, err := strconv.ParseFloat(defaultValue, 32); err == nil {
1509 defaultValue = fmt.Sprint(float32(f))
1512 case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
1513 if def := defaultValue; def != "inf" && def != "-inf" && def != "nan" {
1514 if f, err := strconv.ParseFloat(defaultValue, 64); err == nil {
1515 defaultValue = fmt.Sprint(f)
1519 defaultValue = ",def=" + defaultValue
1522 if *field.Type == descriptor.FieldDescriptorProto_TYPE_ENUM {
1523 // We avoid using obj.GoPackageName(), because we want to use the
1524 // original (proto-world) package name.
1525 obj := g.ObjectNamed(field.GetTypeName())
1526 if id, ok := obj.(*ImportedDescriptor); ok {
1530 if pkg := obj.File().GetPackage(); pkg != "" {
1533 enum += CamelCaseSlice(obj.TypeName())
1536 if (field.Options != nil && field.Options.GetPacked()) ||
1537 // Per https://developers.google.com/protocol-buffers/docs/proto3#simple:
1538 // "In proto3, repeated fields of scalar numeric types use packed encoding by default."
1539 (message.proto3() && (field.Options == nil || field.Options.Packed == nil) &&
1540 isRepeated(field) && isScalar(field)) {
1543 fieldName := field.GetName()
1545 if *field.Type == descriptor.FieldDescriptorProto_TYPE_GROUP {
1546 // We must use the type name for groups instead of
1547 // the field name to preserve capitalization.
1548 // type_name in FieldDescriptorProto is fully-qualified,
1549 // but we only want the local part.
1550 name = *field.TypeName
1551 if i := strings.LastIndex(name, "."); i >= 0 {
1555 if json := field.GetJsonName(); field.Extendee == nil && json != "" && json != name {
1556 // TODO: escaping might be needed, in which case
1557 // perhaps this should be in its own "json" tag.
1558 name += ",json=" + json
1560 name = ",name=" + name
1561 if message.proto3() {
1565 if field.OneofIndex != nil {
1568 return strconv.Quote(fmt.Sprintf("%s,%d,%s%s%s%s%s%s",
1579 func needsStar(typ descriptor.FieldDescriptorProto_Type) bool {
1581 case descriptor.FieldDescriptorProto_TYPE_GROUP:
1583 case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
1585 case descriptor.FieldDescriptorProto_TYPE_BYTES:
1591 // TypeName is the printed name appropriate for an item. If the object is in the current file,
1592 // TypeName drops the package name and underscores the rest.
1593 // Otherwise the object is from another package; and the result is the underscored
1594 // package name followed by the item name.
1595 // The result always has an initial capital.
1596 func (g *Generator) TypeName(obj Object) string {
1597 return g.DefaultPackageName(obj) + CamelCaseSlice(obj.TypeName())
1600 // GoType returns a string representing the type name, and the wire type
1601 func (g *Generator) GoType(message *Descriptor, field *descriptor.FieldDescriptorProto) (typ string, wire string) {
1603 switch *field.Type {
1604 case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
1605 typ, wire = "float64", "fixed64"
1606 case descriptor.FieldDescriptorProto_TYPE_FLOAT:
1607 typ, wire = "float32", "fixed32"
1608 case descriptor.FieldDescriptorProto_TYPE_INT64:
1609 typ, wire = "int64", "varint"
1610 case descriptor.FieldDescriptorProto_TYPE_UINT64:
1611 typ, wire = "uint64", "varint"
1612 case descriptor.FieldDescriptorProto_TYPE_INT32:
1613 typ, wire = "int32", "varint"
1614 case descriptor.FieldDescriptorProto_TYPE_UINT32:
1615 typ, wire = "uint32", "varint"
1616 case descriptor.FieldDescriptorProto_TYPE_FIXED64:
1617 typ, wire = "uint64", "fixed64"
1618 case descriptor.FieldDescriptorProto_TYPE_FIXED32:
1619 typ, wire = "uint32", "fixed32"
1620 case descriptor.FieldDescriptorProto_TYPE_BOOL:
1621 typ, wire = "bool", "varint"
1622 case descriptor.FieldDescriptorProto_TYPE_STRING:
1623 typ, wire = "string", "bytes"
1624 case descriptor.FieldDescriptorProto_TYPE_GROUP:
1625 desc := g.ObjectNamed(field.GetTypeName())
1626 typ, wire = "*"+g.TypeName(desc), "group"
1627 case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
1628 desc := g.ObjectNamed(field.GetTypeName())
1629 typ, wire = "*"+g.TypeName(desc), "bytes"
1630 case descriptor.FieldDescriptorProto_TYPE_BYTES:
1631 typ, wire = "[]byte", "bytes"
1632 case descriptor.FieldDescriptorProto_TYPE_ENUM:
1633 desc := g.ObjectNamed(field.GetTypeName())
1634 typ, wire = g.TypeName(desc), "varint"
1635 case descriptor.FieldDescriptorProto_TYPE_SFIXED32:
1636 typ, wire = "int32", "fixed32"
1637 case descriptor.FieldDescriptorProto_TYPE_SFIXED64:
1638 typ, wire = "int64", "fixed64"
1639 case descriptor.FieldDescriptorProto_TYPE_SINT32:
1640 typ, wire = "int32", "zigzag32"
1641 case descriptor.FieldDescriptorProto_TYPE_SINT64:
1642 typ, wire = "int64", "zigzag64"
1644 g.Fail("unknown type for", field.GetName())
1646 if isRepeated(field) {
1648 } else if message != nil && message.proto3() {
1650 } else if field.OneofIndex != nil && message != nil {
1652 } else if needsStar(*field.Type) {
1658 func (g *Generator) RecordTypeUse(t string) {
1659 if _, ok := g.typeNameToObject[t]; !ok {
1662 importPath := g.ObjectNamed(t).GoImportPath()
1663 if importPath == g.outputImportPath {
1664 // Don't record use of objects in our package.
1667 g.AddImport(importPath)
1668 g.usedPackages[importPath] = true
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.
1674 var methodNames = [...]string{
1680 "ExtensionRangeArray",
1685 // Names of messages in the `google.protobuf` package for which
1686 // we will generate XXX_WellKnownType methods.
1687 var wellKnownTypes = map[string]bool{
1696 "DoubleValue": true,
1699 "UInt64Value": true,
1701 "UInt32Value": true,
1703 "StringValue": true,
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"
1709 func (g *Generator) getterDefault(field *descriptor.FieldDescriptorProto, goMessageType string) string {
1710 if isRepeated(field) {
1713 if def := field.GetDefaultValue(); def != "" {
1714 defaultConstant := g.defaultConstantName(goMessageType, field.GetName())
1715 if *field.Type != descriptor.FieldDescriptorProto_TYPE_BYTES {
1716 return defaultConstant
1718 return "append([]byte(nil), " + defaultConstant + "...)"
1720 switch *field.Type {
1721 case descriptor.FieldDescriptorProto_TYPE_BOOL:
1723 case descriptor.FieldDescriptorProto_TYPE_STRING:
1725 case descriptor.FieldDescriptorProto_TYPE_GROUP, descriptor.FieldDescriptorProto_TYPE_MESSAGE, descriptor.FieldDescriptorProto_TYPE_BYTES:
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)
1734 enum, _ = obj.(*EnumDescriptor)
1737 log.Printf("don't know how to generate getter for %s", field.GetName())
1740 if len(enum.Value) == 0 {
1741 return "0 // empty enum"
1743 first := enum.Value[0].GetName()
1744 return g.DefaultPackageName(obj) + enum.prefix() + first
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"
1752 func (g *Generator) defaultConstantName(goMessageType, protoFieldName string) string {
1753 return "Default_" + goMessageType + "_" + CamelCase(protoFieldName)
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.
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).
1762 // Extension fields (and message sets) are however handled separately.
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
1768 // msgCtx contains the context for the generator functions.
1769 type msgCtx struct {
1770 goName string // Go struct name of the message, e.g. MessageName
1771 message *Descriptor // The descriptor for the message
1774 // fieldCommon contains data common to all types of fields.
1775 type 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"
1784 // getProtoName gets the proto name of a field, e.g. "field_name" or "descriptor".
1785 func (f *fieldCommon) getProtoName() string {
1789 // getGoType returns the go type of the field as a string, e.g. "*int32".
1790 func (f *fieldCommon) getGoType() string {
1794 // simpleField is not weak, not a oneof, not an extension. Can be required, optional or repeated.
1795 type simpleField struct {
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"
1805 // decl prints the declaration of the field in the struct (if any).
1806 func (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)
1810 // getter prints the getter for the field.
1811 func (f *simpleField) getter(g *Generator, mc *msgCtx) {
1814 if needsStar(f.protoType) && tname[0] == '*' {
1818 if f.deprecated != "" {
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)
1831 if mc.message.proto3() {
1832 g.P("if m != nil {")
1834 g.P("if m != nil && m." + f.goName + " != nil {")
1836 g.P("return " + star + "m." + f.goName)
1838 g.P("return ", f.getterDef)
1843 // setter prints the setter method of the field.
1844 func (f *simpleField) setter(g *Generator, mc *msgCtx) {
1845 // No setter for regular fields yet
1848 // getProtoDef returns the default value explicitly stated in the proto file, e.g "yoshi" or "5".
1849 func (f *simpleField) getProtoDef() string {
1853 // getProtoTypeName returns the protobuf type name for the field as returned by field.GetTypeName(), e.g. ".google.protobuf.Duration".
1854 func (f *simpleField) getProtoTypeName() string {
1855 return f.protoTypeName
1858 // getProtoType returns the *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64.
1859 func (f *simpleField) getProtoType() descriptor.FieldDescriptorProto_Type {
1863 // oneofSubFields are kept slize held by each oneofField. They do not appear in the top level slize of fields for the message.
1864 type oneofSubField struct {
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 deprecated string // Deprecation comment, if any.
1875 // typedNil prints a nil casted to the pointer to this field.
1876 // - for XXX_OneofWrappers
1877 func (f *oneofSubField) typedNil(g *Generator) {
1878 g.P("(*", f.oneofTypeName, ")(nil),")
1881 // getProtoDef returns the default value explicitly stated in the proto file, e.g "yoshi" or "5".
1882 func (f *oneofSubField) getProtoDef() string {
1886 // getProtoTypeName returns the protobuf type name for the field as returned by field.GetTypeName(), e.g. ".google.protobuf.Duration".
1887 func (f *oneofSubField) getProtoTypeName() string {
1888 return f.protoTypeName
1891 // getProtoType returns the *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64.
1892 func (f *oneofSubField) getProtoType() descriptor.FieldDescriptorProto_Type {
1896 // oneofField represents the oneof on top level.
1897 // The alternative fields within the oneof are represented by oneofSubField.
1898 type oneofField struct {
1900 subFields []*oneofSubField // All the possible oneof fields
1901 comment string // The full comment for the field, e.g. "// Types that are valid to be assigned to MyOneof:\n\\"
1904 // decl prints the declaration of the field in the struct (if any).
1905 func (f *oneofField) decl(g *Generator, mc *msgCtx) {
1906 comment := f.comment
1907 for _, sf := range f.subFields {
1908 comment += "//\t*" + sf.oneofTypeName + "\n"
1910 g.P(comment, Annotate(mc.message.file, f.fullPath, f.goName), " ", f.goType, " `", f.tags, "`")
1913 // getter for a oneof field will print additional discriminators and interfaces for the oneof,
1914 // also it prints all the getters for the sub fields.
1915 func (f *oneofField) getter(g *Generator, mc *msgCtx) {
1916 // The discriminator type
1917 g.P("type ", f.goType, " interface {")
1921 // The subField types, fulfilling the discriminator type contract
1922 for _, sf := range f.subFields {
1923 g.P("type ", Annotate(mc.message.file, sf.fullPath, sf.oneofTypeName), " struct {")
1924 g.P(Annotate(mc.message.file, sf.fullPath, sf.goName), " ", sf.goType, " `", sf.tags, "`")
1928 for _, sf := range f.subFields {
1929 g.P("func (*", sf.oneofTypeName, ") ", f.goType, "() {}")
1932 // Getter for the oneof field
1933 g.P("func (m *", mc.goName, ") ", Annotate(mc.message.file, f.fullPath, f.getterName), "() ", f.goType, " {")
1934 g.P("if m != nil { return m.", f.goName, " }")
1938 // Getters for each oneof
1939 for _, sf := range f.subFields {
1940 if sf.deprecated != "" {
1943 g.P("func (m *", mc.goName, ") ", Annotate(mc.message.file, sf.fullPath, sf.getterName), "() "+sf.goType+" {")
1944 g.P("if x, ok := m.", f.getterName, "().(*", sf.oneofTypeName, "); ok {")
1945 g.P("return x.", sf.goName)
1947 g.P("return ", sf.getterDef)
1953 // setter prints the setter method of the field.
1954 func (f *oneofField) setter(g *Generator, mc *msgCtx) {
1955 // No setters for oneof yet
1958 // topLevelField interface implemented by all types of fields on the top level (not oneofSubField).
1959 type topLevelField interface {
1960 decl(g *Generator, mc *msgCtx) // print declaration within the struct
1961 getter(g *Generator, mc *msgCtx) // print getter
1962 setter(g *Generator, mc *msgCtx) // print setter if applicable
1965 // defField interface implemented by all types of fields that can have defaults (not oneofField, but instead oneofSubField).
1966 type defField interface {
1967 getProtoDef() string // default value explicitly stated in the proto file, e.g "yoshi" or "5"
1968 getProtoName() string // proto name of a field, e.g. "field_name" or "descriptor"
1969 getGoType() string // go type of the field as a string, e.g. "*int32"
1970 getProtoTypeName() string // protobuf type name for the field, e.g. ".google.protobuf.Duration"
1971 getProtoType() descriptor.FieldDescriptorProto_Type // *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64
1974 // generateDefaultConstants adds constants for default values if needed, which is only if the default value is.
1975 // explicit in the proto.
1976 func (g *Generator) generateDefaultConstants(mc *msgCtx, topLevelFields []topLevelField) {
1977 // Collect fields that can have defaults
1978 dFields := []defField{}
1979 for _, pf := range topLevelFields {
1980 if f, ok := pf.(*oneofField); ok {
1981 for _, osf := range f.subFields {
1982 dFields = append(dFields, osf)
1986 dFields = append(dFields, pf.(defField))
1988 for _, df := range dFields {
1989 def := df.getProtoDef()
1993 fieldname := g.defaultConstantName(mc.goName, df.getProtoName())
1994 typename := df.getGoType()
1995 if typename[0] == '*' {
1996 typename = typename[1:]
2000 case typename == "bool":
2001 case typename == "string":
2002 def = strconv.Quote(def)
2003 case typename == "[]byte":
2004 def = "[]byte(" + strconv.Quote(unescape(def)) + ")"
2006 case def == "inf", def == "-inf", def == "nan":
2007 // These names are known to, and defined by, the protocol language.
2012 def = "math.Inf(-1)"
2016 if df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_FLOAT {
2017 def = "float32(" + def + ")"
2020 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_FLOAT:
2021 if f, err := strconv.ParseFloat(def, 32); err == nil {
2022 def = fmt.Sprint(float32(f))
2024 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_DOUBLE:
2025 if f, err := strconv.ParseFloat(def, 64); err == nil {
2028 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_ENUM:
2029 // Must be an enum. Need to construct the prefixed name.
2030 obj := g.ObjectNamed(df.getProtoTypeName())
2031 var enum *EnumDescriptor
2032 if id, ok := obj.(*ImportedDescriptor); ok {
2033 // The enum type has been publicly imported.
2034 enum, _ = id.o.(*EnumDescriptor)
2036 enum, _ = obj.(*EnumDescriptor)
2039 log.Printf("don't know how to generate constant for %s", fieldname)
2042 def = g.DefaultPackageName(obj) + enum.prefix() + def
2044 g.P(kind, fieldname, " ", typename, " = ", def)
2045 g.file.addExport(mc.message, constOrVarSymbol{fieldname, kind, ""})
2050 // generateInternalStructFields just adds the XXX_<something> fields to the message struct.
2051 func (g *Generator) generateInternalStructFields(mc *msgCtx, topLevelFields []topLevelField) {
2052 g.P("XXX_NoUnkeyedLiteral\tstruct{} `json:\"-\"`") // prevent unkeyed struct literals
2053 if len(mc.message.ExtensionRange) > 0 {
2055 if opts := mc.message.Options; opts != nil && opts.GetMessageSetWireFormat() {
2056 messageset = "protobuf_messageset:\"1\" "
2058 g.P(g.Pkg["proto"], ".XXX_InternalExtensions `", messageset, "json:\"-\"`")
2060 g.P("XXX_unrecognized\t[]byte `json:\"-\"`")
2061 g.P("XXX_sizecache\tint32 `json:\"-\"`")
2065 // generateOneofFuncs adds all the utility functions for oneof, including marshalling, unmarshalling and sizer.
2066 func (g *Generator) generateOneofFuncs(mc *msgCtx, topLevelFields []topLevelField) {
2067 ofields := []*oneofField{}
2068 for _, f := range topLevelFields {
2069 if o, ok := f.(*oneofField); ok {
2070 ofields = append(ofields, o)
2073 if len(ofields) == 0 {
2078 g.P("// XXX_OneofWrappers is for the internal use of the proto package.")
2079 g.P("func (*", mc.goName, ") XXX_OneofWrappers() []interface{} {")
2080 g.P("return []interface{}{")
2081 for _, of := range ofields {
2082 for _, sf := range of.subFields {
2091 // generateMessageStruct adds the actual struct with it's members (but not methods) to the output.
2092 func (g *Generator) generateMessageStruct(mc *msgCtx, topLevelFields []topLevelField) {
2093 comments := g.PrintComments(mc.message.path)
2095 // Guarantee deprecation comments appear after user-provided comments.
2096 if mc.message.GetOptions().GetDeprecated() {
2098 // Convention: Separate deprecation comments from original
2099 // comments with an empty line.
2102 g.P(deprecationComment)
2105 g.P("type ", Annotate(mc.message.file, mc.message.path, mc.goName), " struct {")
2106 for _, pf := range topLevelFields {
2109 g.generateInternalStructFields(mc, topLevelFields)
2113 // generateGetters adds getters for all fields, including oneofs and weak fields when applicable.
2114 func (g *Generator) generateGetters(mc *msgCtx, topLevelFields []topLevelField) {
2115 for _, pf := range topLevelFields {
2120 // generateSetters add setters for all fields, including oneofs and weak fields when applicable.
2121 func (g *Generator) generateSetters(mc *msgCtx, topLevelFields []topLevelField) {
2122 for _, pf := range topLevelFields {
2127 // generateCommonMethods adds methods to the message that are not on a per field basis.
2128 func (g *Generator) generateCommonMethods(mc *msgCtx) {
2129 // Reset, String and ProtoMessage methods.
2130 g.P("func (m *", mc.goName, ") Reset() { *m = ", mc.goName, "{} }")
2131 g.P("func (m *", mc.goName, ") String() string { return ", g.Pkg["proto"], ".CompactTextString(m) }")
2132 g.P("func (*", mc.goName, ") ProtoMessage() {}")
2133 var indexes []string
2134 for m := mc.message; m != nil; m = m.parent {
2135 indexes = append([]string{strconv.Itoa(m.index)}, indexes...)
2137 g.P("func (*", mc.goName, ") Descriptor() ([]byte, []int) {")
2138 g.P("return ", g.file.VarName(), ", []int{", strings.Join(indexes, ", "), "}")
2141 // TODO: Revisit the decision to use a XXX_WellKnownType method
2142 // if we change proto.MessageName to work with multiple equivalents.
2143 if mc.message.file.GetPackage() == "google.protobuf" && wellKnownTypes[mc.message.GetName()] {
2144 g.P("func (*", mc.goName, `) XXX_WellKnownType() string { return "`, mc.message.GetName(), `" }`)
2148 // Extension support methods
2149 if len(mc.message.ExtensionRange) > 0 {
2151 g.P("var extRange_", mc.goName, " = []", g.Pkg["proto"], ".ExtensionRange{")
2152 for _, r := range mc.message.ExtensionRange {
2153 end := fmt.Sprint(*r.End - 1) // make range inclusive on both ends
2154 g.P("{Start: ", r.Start, ", End: ", end, "},")
2157 g.P("func (*", mc.goName, ") ExtensionRangeArray() []", g.Pkg["proto"], ".ExtensionRange {")
2158 g.P("return extRange_", mc.goName)
2163 // TODO: It does not scale to keep adding another method for every
2164 // operation on protos that we want to switch over to using the
2165 // table-driven approach. Instead, we should only add a single method
2166 // that allows getting access to the *InternalMessageInfo struct and then
2167 // calling Unmarshal, Marshal, Merge, Size, and Discard directly on that.
2169 // Wrapper for table-driven marshaling and unmarshaling.
2170 g.P("func (m *", mc.goName, ") XXX_Unmarshal(b []byte) error {")
2171 g.P("return xxx_messageInfo_", mc.goName, ".Unmarshal(m, b)")
2174 g.P("func (m *", mc.goName, ") XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {")
2175 g.P("return xxx_messageInfo_", mc.goName, ".Marshal(b, m, deterministic)")
2178 g.P("func (m *", mc.goName, ") XXX_Merge(src ", g.Pkg["proto"], ".Message) {")
2179 g.P("xxx_messageInfo_", mc.goName, ".Merge(m, src)")
2182 g.P("func (m *", mc.goName, ") XXX_Size() int {") // avoid name clash with "Size" field in some message
2183 g.P("return xxx_messageInfo_", mc.goName, ".Size(m)")
2186 g.P("func (m *", mc.goName, ") XXX_DiscardUnknown() {")
2187 g.P("xxx_messageInfo_", mc.goName, ".DiscardUnknown(m)")
2190 g.P("var xxx_messageInfo_", mc.goName, " ", g.Pkg["proto"], ".InternalMessageInfo")
2194 // Generate the type, methods and default constant definitions for this Descriptor.
2195 func (g *Generator) generateMessage(message *Descriptor) {
2196 topLevelFields := []topLevelField{}
2197 oFields := make(map[int32]*oneofField)
2198 // The full type name
2199 typeName := message.TypeName()
2200 // The full type name, CamelCased.
2201 goTypeName := CamelCaseSlice(typeName)
2203 usedNames := make(map[string]bool)
2204 for _, n := range methodNames {
2208 // allocNames finds a conflict-free variation of the given strings,
2209 // consistently mutating their suffixes.
2210 // It returns the same number of strings.
2211 allocNames := func(ns ...string) []string {
2214 for _, n := range ns {
2222 for _, n := range ns {
2229 mapFieldTypes := make(map[*descriptor.FieldDescriptorProto]string) // keep track of the map fields to be added later
2231 // Build a structure more suitable for generating the text in one pass
2232 for i, field := range message.Field {
2233 // Allocate the getter and the field at the same time so name
2234 // collisions create field/method consistent names.
2235 // TODO: This allocation occurs based on the order of the fields
2236 // in the proto file, meaning that a change in the field
2237 // ordering can change generated Method/Field names.
2238 base := CamelCase(*field.Name)
2239 ns := allocNames(base, "Get"+base)
2240 fieldName, fieldGetterName := ns[0], ns[1]
2241 typename, wiretype := g.GoType(message, field)
2242 jsonName := *field.Name
2243 tag := fmt.Sprintf("protobuf:%s json:%q", g.goTag(message, field, wiretype), jsonName+",omitempty")
2245 oneof := field.OneofIndex != nil
2246 if oneof && oFields[*field.OneofIndex] == nil {
2247 odp := message.OneofDecl[int(*field.OneofIndex)]
2248 base := CamelCase(odp.GetName())
2249 fname := allocNames(base)[0]
2251 // This is the first field of a oneof we haven't seen before.
2252 // Generate the union field.
2253 oneofFullPath := fmt.Sprintf("%s,%d,%d", message.path, messageOneofPath, *field.OneofIndex)
2254 c, ok := g.makeComments(oneofFullPath)
2258 c += "// Types that are valid to be assigned to " + fname + ":\n"
2259 // Generate the rest of this comment later,
2260 // when we've computed any disambiguation.
2262 dname := "is" + goTypeName + "_" + fname
2263 tag := `protobuf_oneof:"` + odp.GetName() + `"`
2265 fieldCommon: fieldCommon{
2267 getterName: "Get"+fname,
2270 protoName: odp.GetName(),
2271 fullPath: oneofFullPath,
2275 topLevelFields = append(topLevelFields, &of)
2276 oFields[*field.OneofIndex] = &of
2279 if *field.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE {
2280 desc := g.ObjectNamed(field.GetTypeName())
2281 if d, ok := desc.(*Descriptor); ok && d.GetOptions().GetMapEntry() {
2282 // Figure out the Go types and tags for the key and value types.
2283 keyField, valField := d.Field[0], d.Field[1]
2284 keyType, keyWire := g.GoType(d, keyField)
2285 valType, valWire := g.GoType(d, valField)
2286 keyTag, valTag := g.goTag(d, keyField, keyWire), g.goTag(d, valField, valWire)
2288 // We don't use stars, except for message-typed values.
2289 // Message and enum types are the only two possibly foreign types used in maps,
2290 // so record their use. They are not permitted as map keys.
2291 keyType = strings.TrimPrefix(keyType, "*")
2292 switch *valField.Type {
2293 case descriptor.FieldDescriptorProto_TYPE_ENUM:
2294 valType = strings.TrimPrefix(valType, "*")
2295 g.RecordTypeUse(valField.GetTypeName())
2296 case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
2297 g.RecordTypeUse(valField.GetTypeName())
2299 valType = strings.TrimPrefix(valType, "*")
2302 typename = fmt.Sprintf("map[%s]%s", keyType, valType)
2303 mapFieldTypes[field] = typename // record for the getter generation
2305 tag += fmt.Sprintf(" protobuf_key:%s protobuf_val:%s", keyTag, valTag)
2309 fieldDeprecated := ""
2310 if field.GetOptions().GetDeprecated() {
2311 fieldDeprecated = deprecationComment
2314 dvalue := g.getterDefault(field, goTypeName)
2316 tname := goTypeName + "_" + fieldName
2317 // It is possible for this to collide with a message or enum
2318 // nested in this message. Check for collisions.
2321 for _, desc := range message.nested {
2322 if CamelCaseSlice(desc.TypeName()) == tname {
2327 for _, enum := range message.enums {
2328 if CamelCaseSlice(enum.TypeName()) == tname {
2340 oneofField := oFields[*field.OneofIndex]
2341 tag := "protobuf:" + g.goTag(message, field, wiretype)
2342 sf := oneofSubField{
2343 fieldCommon: fieldCommon{
2345 getterName: fieldGetterName,
2348 protoName: field.GetName(),
2349 fullPath: fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i),
2351 protoTypeName: field.GetTypeName(),
2352 fieldNumber: int(*field.Number),
2353 protoType: *field.Type,
2355 protoDef: field.GetDefaultValue(),
2356 oneofTypeName: tname,
2357 deprecated: fieldDeprecated,
2359 oneofField.subFields = append(oneofField.subFields, &sf)
2360 g.RecordTypeUse(field.GetTypeName())
2364 fieldFullPath := fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i)
2365 c, ok := g.makeComments(fieldFullPath)
2370 fieldCommon: fieldCommon{
2372 getterName: fieldGetterName,
2375 protoName: field.GetName(),
2376 fullPath: fieldFullPath,
2378 protoTypeName: field.GetTypeName(),
2379 protoType: *field.Type,
2380 deprecated: fieldDeprecated,
2382 protoDef: field.GetDefaultValue(),
2385 var pf topLevelField = &rf
2387 topLevelFields = append(topLevelFields, pf)
2388 g.RecordTypeUse(field.GetTypeName())
2396 g.generateMessageStruct(mc, topLevelFields)
2398 g.generateCommonMethods(mc)
2400 g.generateDefaultConstants(mc, topLevelFields)
2402 g.generateGetters(mc, topLevelFields)
2404 g.generateSetters(mc, topLevelFields)
2406 g.generateOneofFuncs(mc, topLevelFields)
2409 var oneofTypes []string
2410 for _, f := range topLevelFields {
2411 if of, ok := f.(*oneofField); ok {
2412 for _, osf := range of.subFields {
2413 oneofTypes = append(oneofTypes, osf.oneofTypeName)
2418 opts := message.Options
2419 ms := &messageSymbol{
2421 hasExtensions: len(message.ExtensionRange) > 0,
2422 isMessageSet: opts != nil && opts.GetMessageSetWireFormat(),
2423 oneofTypes: oneofTypes,
2425 g.file.addExport(message, ms)
2427 for _, ext := range message.ext {
2428 g.generateExtension(ext)
2431 fullName := strings.Join(message.TypeName(), ".")
2432 if g.file.Package != nil {
2433 fullName = *g.file.Package + "." + fullName
2436 g.addInitf("%s.RegisterType((*%s)(nil), %q)", g.Pkg["proto"], goTypeName, fullName)
2437 // Register types for native map types.
2438 for _, k := range mapFieldKeys(mapFieldTypes) {
2439 fullName := strings.TrimPrefix(*k.TypeName, ".")
2440 g.addInitf("%s.RegisterMapType((%s)(nil), %q)", g.Pkg["proto"], mapFieldTypes[k], fullName)
2445 type byTypeName []*descriptor.FieldDescriptorProto
2447 func (a byTypeName) Len() int { return len(a) }
2448 func (a byTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
2449 func (a byTypeName) Less(i, j int) bool { return *a[i].TypeName < *a[j].TypeName }
2451 // mapFieldKeys returns the keys of m in a consistent order.
2452 func mapFieldKeys(m map[*descriptor.FieldDescriptorProto]string) []*descriptor.FieldDescriptorProto {
2453 keys := make([]*descriptor.FieldDescriptorProto, 0, len(m))
2455 keys = append(keys, k)
2457 sort.Sort(byTypeName(keys))
2461 var escapeChars = [256]byte{
2462 'a': '\a', 'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t', 'v': '\v', '\\': '\\', '"': '"', '\'': '\'', '?': '?',
2465 // unescape reverses the "C" escaping that protoc does for default values of bytes fields.
2466 // It is best effort in that it effectively ignores malformed input. Seemingly invalid escape
2467 // sequences are conveyed, unmodified, into the decoded result.
2468 func unescape(s string) string {
2469 // NB: Sadly, we can't use strconv.Unquote because protoc will escape both
2470 // single and double quotes, but strconv.Unquote only allows one or the
2471 // other (based on actual surrounding quotes of its input argument).
2475 // regular character, or too short to be valid escape
2476 if s[0] != '\\' || len(s) < 2 {
2477 out = append(out, s[0])
2479 } else if c := escapeChars[s[1]]; c != 0 {
2481 out = append(out, c)
2483 } else if s[1] == 'x' || s[1] == 'X' {
2484 // hex escape, e.g. "\x80
2486 // too short to be valid
2487 out = append(out, s[:2]...)
2491 v, err := strconv.ParseUint(s[2:4], 16, 8)
2493 out = append(out, s[:4]...)
2495 out = append(out, byte(v))
2498 } else if '0' <= s[1] && s[1] <= '7' {
2499 // octal escape, can vary from 1 to 3 octal digits; e.g., "\0" "\40" or "\164"
2500 // so consume up to 2 more bytes or up to end-of-string
2501 n := len(s[1:]) - len(strings.TrimLeft(s[1:], "01234567"))
2505 v, err := strconv.ParseUint(s[1:1+n], 8, 8)
2507 out = append(out, s[:1+n]...)
2509 out = append(out, byte(v))
2513 // bad escape, just propagate the slash as-is
2514 out = append(out, s[0])
2522 func (g *Generator) generateExtension(ext *ExtensionDescriptor) {
2523 ccTypeName := ext.DescName()
2525 extObj := g.ObjectNamed(*ext.Extendee)
2526 var extDesc *Descriptor
2527 if id, ok := extObj.(*ImportedDescriptor); ok {
2528 // This is extending a publicly imported message.
2529 // We need the underlying type for goTag.
2530 extDesc = id.o.(*Descriptor)
2532 extDesc = extObj.(*Descriptor)
2534 extendedType := "*" + g.TypeName(extObj) // always use the original
2535 field := ext.FieldDescriptorProto
2536 fieldType, wireType := g.GoType(ext.parent, field)
2537 tag := g.goTag(extDesc, field, wireType)
2538 g.RecordTypeUse(*ext.Extendee)
2539 if n := ext.FieldDescriptorProto.TypeName; n != nil {
2540 // foreign extension type
2544 typeName := ext.TypeName()
2546 // Special case for proto2 message sets: If this extension is extending
2547 // proto2.bridge.MessageSet, and its final name component is "message_set_extension",
2548 // then drop that last component.
2550 // TODO: This should be implemented in the text formatter rather than the generator.
2551 // In addition, the situation for when to apply this special case is implemented
2552 // differently in other languages:
2553 // https://github.com/google/protobuf/blob/aff10976/src/google/protobuf/text_format.cc#L1560
2554 if extDesc.GetOptions().GetMessageSetWireFormat() && typeName[len(typeName)-1] == "message_set_extension" {
2555 typeName = typeName[:len(typeName)-1]
2558 // For text formatting, the package must be exactly what the .proto file declares,
2559 // ignoring overrides such as the go_package option, and with no dot/underscore mapping.
2560 extName := strings.Join(typeName, ".")
2561 if g.file.Package != nil {
2562 extName = *g.file.Package + "." + extName
2565 g.P("var ", ccTypeName, " = &", g.Pkg["proto"], ".ExtensionDesc{")
2566 g.P("ExtendedType: (", extendedType, ")(nil),")
2567 g.P("ExtensionType: (", fieldType, ")(nil),")
2568 g.P("Field: ", field.Number, ",")
2569 g.P(`Name: "`, extName, `",`)
2570 g.P("Tag: ", tag, ",")
2571 g.P(`Filename: "`, g.file.GetName(), `",`)
2576 g.addInitf("%s.RegisterExtension(%s)", g.Pkg["proto"], ext.DescName())
2578 g.file.addExport(ext, constOrVarSymbol{ccTypeName, "var", ""})
2581 func (g *Generator) generateInitFunction() {
2582 if len(g.init) == 0 {
2585 g.P("func init() {")
2586 for _, l := range g.init {
2593 func (g *Generator) generateFileDescriptor(file *FileDescriptor) {
2594 // Make a copy and trim source_code_info data.
2595 // TODO: Trim this more when we know exactly what we need.
2596 pb := proto.Clone(file.FileDescriptorProto).(*descriptor.FileDescriptorProto)
2597 pb.SourceCodeInfo = nil
2599 b, err := proto.Marshal(pb)
2604 var buf bytes.Buffer
2605 w, _ := gzip.NewWriterLevel(&buf, gzip.BestCompression)
2612 g.P("func init() { ", g.Pkg["proto"], ".RegisterFile(", strconv.Quote(*file.Name), ", ", v, ") }")
2613 g.P("var ", v, " = []byte{")
2614 g.P("// ", len(b), " bytes of a gzipped FileDescriptorProto")
2622 for _, c := range b[:n] {
2623 s += fmt.Sprintf("0x%02x,", c)
2632 func (g *Generator) generateEnumRegistration(enum *EnumDescriptor) {
2633 // // We always print the full (proto-world) package name here.
2634 pkg := enum.File().GetPackage()
2638 // The full type name
2639 typeName := enum.TypeName()
2640 // The full type name, CamelCased.
2641 ccTypeName := CamelCaseSlice(typeName)
2642 g.addInitf("%s.RegisterEnum(%q, %[3]s_name, %[3]s_value)", g.Pkg["proto"], pkg+ccTypeName, ccTypeName)
2645 // And now lots of helper functions.
2647 // Is c an ASCII lower-case letter?
2648 func isASCIILower(c byte) bool {
2649 return 'a' <= c && c <= 'z'
2652 // Is c an ASCII digit?
2653 func isASCIIDigit(c byte) bool {
2654 return '0' <= c && c <= '9'
2657 // CamelCase returns the CamelCased name.
2658 // If there is an interior underscore followed by a lower case letter,
2659 // drop the underscore and convert the letter to upper case.
2660 // There is a remote possibility of this rewrite causing a name collision,
2661 // but it's so remote we're prepared to pretend it's nonexistent - since the
2662 // C++ generator lowercases names, it's extremely unlikely to have two fields
2663 // with different capitalizations.
2664 // In short, _my_field_name_2 becomes XMyFieldName_2.
2665 func CamelCase(s string) string {
2669 t := make([]byte, 0, 32)
2672 // Need a capital letter; drop the '_'.
2676 // Invariant: if the next letter is lower case, it must be converted
2678 // That is, we process a word at a time, where words are marked by _ or
2679 // upper case letter. Digits are treated as words.
2680 for ; i < len(s); i++ {
2682 if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) {
2683 continue // Skip the underscore in s.
2685 if isASCIIDigit(c) {
2689 // Assume we have a letter now - if not, it's a bogus identifier.
2690 // The next word is a sequence of characters that must start upper case.
2691 if isASCIILower(c) {
2692 c ^= ' ' // Make it a capital letter.
2694 t = append(t, c) // Guaranteed not lower case.
2695 // Accept lower case sequence that follows.
2696 for i+1 < len(s) && isASCIILower(s[i+1]) {
2704 // CamelCaseSlice is like CamelCase, but the argument is a slice of strings to
2705 // be joined with "_".
2706 func CamelCaseSlice(elem []string) string { return CamelCase(strings.Join(elem, "_")) }
2708 // dottedSlice turns a sliced name into a dotted name.
2709 func dottedSlice(elem []string) string { return strings.Join(elem, ".") }
2711 // Is this field optional?
2712 func isOptional(field *descriptor.FieldDescriptorProto) bool {
2713 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_OPTIONAL
2716 // Is this field required?
2717 func isRequired(field *descriptor.FieldDescriptorProto) bool {
2718 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REQUIRED
2721 // Is this field repeated?
2722 func isRepeated(field *descriptor.FieldDescriptorProto) bool {
2723 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED
2726 // Is this field a scalar numeric type?
2727 func isScalar(field *descriptor.FieldDescriptorProto) bool {
2728 if field.Type == nil {
2731 switch *field.Type {
2732 case descriptor.FieldDescriptorProto_TYPE_DOUBLE,
2733 descriptor.FieldDescriptorProto_TYPE_FLOAT,
2734 descriptor.FieldDescriptorProto_TYPE_INT64,
2735 descriptor.FieldDescriptorProto_TYPE_UINT64,
2736 descriptor.FieldDescriptorProto_TYPE_INT32,
2737 descriptor.FieldDescriptorProto_TYPE_FIXED64,
2738 descriptor.FieldDescriptorProto_TYPE_FIXED32,
2739 descriptor.FieldDescriptorProto_TYPE_BOOL,
2740 descriptor.FieldDescriptorProto_TYPE_UINT32,
2741 descriptor.FieldDescriptorProto_TYPE_ENUM,
2742 descriptor.FieldDescriptorProto_TYPE_SFIXED32,
2743 descriptor.FieldDescriptorProto_TYPE_SFIXED64,
2744 descriptor.FieldDescriptorProto_TYPE_SINT32,
2745 descriptor.FieldDescriptorProto_TYPE_SINT64:
2752 // badToUnderscore is the mapping function used to generate Go names from package names,
2753 // which can be dotted in the input .proto file. It replaces non-identifier characters such as
2754 // dot or dash with underscore.
2755 func badToUnderscore(r rune) rune {
2756 if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' {
2762 // baseName returns the last path element of the name, with the last dotted suffix removed.
2763 func baseName(name string) string {
2764 // First, find the last element
2765 if i := strings.LastIndex(name, "/"); i >= 0 {
2768 // Now drop the suffix
2769 if i := strings.LastIndex(name, "."); i >= 0 {
2775 // The SourceCodeInfo message describes the location of elements of a parsed
2776 // .proto file by way of a "path", which is a sequence of integers that
2777 // describe the route from a FileDescriptorProto to the relevant submessage.
2778 // The path alternates between a field number of a repeated field, and an index
2779 // into that repeated field. The constants below define the field numbers that
2782 // See descriptor.proto for more information about this.
2784 // tag numbers in FileDescriptorProto
2785 packagePath = 2 // package
2786 messagePath = 4 // message_type
2787 enumPath = 5 // enum_type
2788 // tag numbers in DescriptorProto
2789 messageFieldPath = 2 // field
2790 messageMessagePath = 3 // nested_type
2791 messageEnumPath = 4 // enum_type
2792 messageOneofPath = 8 // oneof_decl
2793 // tag numbers in EnumDescriptorProto
2794 enumValuePath = 2 // value
2797 var supportTypeAliases bool
2800 for _, tag := range build.Default.ReleaseTags {
2802 supportTypeAliases = true