blob: 6f4a902b5be567afb016211819f730a87df48368 [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"
William Kurkiandaa6bb22019-03-07 12:26:28 -050046 "go/ast"
khenaidooac637102019-01-14 15:44:34 -050047 "go/build"
48 "go/parser"
49 "go/printer"
50 "go/token"
51 "log"
52 "os"
53 "path"
54 "sort"
55 "strconv"
56 "strings"
57 "unicode"
58 "unicode/utf8"
59
60 "github.com/golang/protobuf/proto"
61 "github.com/golang/protobuf/protoc-gen-go/generator/internal/remap"
62
63 "github.com/golang/protobuf/protoc-gen-go/descriptor"
64 plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
65)
66
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).
William Kurkiandaa6bb22019-03-07 12:26:28 -050071const generatedCodeVersion = 3
khenaidooac637102019-01-14 15:44:34 -050072
73// A Plugin provides functionality to add to the output during Go code generation,
74// such as to produce RPC stubs.
75type Plugin interface {
76 // Name identifies the plugin.
77 Name() string
78 // Init is called once after data structures are built but before
79 // code generation begins.
80 Init(g *Generator)
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)
87}
88
89var plugins []Plugin
90
91// RegisterPlugin installs a (second-order) plugin to be run when the Go output is generated.
92// It is typically called during initialization.
93func RegisterPlugin(p Plugin) {
94 plugins = append(plugins, p)
95}
96
97// A GoImportPath is the import path of a Go package. e.g., "google.golang.org/genproto/protobuf".
98type GoImportPath string
99
100func (p GoImportPath) String() string { return strconv.Quote(string(p)) }
101
102// A GoPackageName is the name of a Go package. e.g., "protobuf".
103type GoPackageName string
104
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.
110
111// The file and package name method are common to messages and enums.
112type common struct {
113 file *FileDescriptor // File this object comes from.
114}
115
116// GoImportPath is the import path of the Go package containing the type.
117func (c *common) GoImportPath() GoImportPath {
118 return c.file.importPath
119}
120
121func (c *common) File() *FileDescriptor { return c.file }
122
123func fileIsProto3(file *descriptor.FileDescriptorProto) bool {
124 return file.GetSyntax() == "proto3"
125}
126
127func (c *common) proto3() bool { return fileIsProto3(c.file.FileDescriptorProto) }
128
129// Descriptor represents a protocol buffer message.
130type Descriptor struct {
131 common
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.
140 group bool
141}
142
143// TypeName returns the elements of the dotted type name.
144// The package name is not part of this name.
145func (d *Descriptor) TypeName() []string {
146 if d.typename != nil {
147 return d.typename
148 }
149 n := 0
150 for parent := d; parent != nil; parent = parent.parent {
151 n++
152 }
153 s := make([]string, n)
154 for parent := d; parent != nil; parent = parent.parent {
155 n--
156 s[n] = parent.GetName()
157 }
158 d.typename = s
159 return s
160}
161
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.
164type EnumDescriptor struct {
165 common
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.
171}
172
173// TypeName returns the elements of the dotted type name.
174// The package name is not part of this name.
175func (e *EnumDescriptor) TypeName() (s []string) {
176 if e.typename != nil {
177 return e.typename
178 }
179 name := e.GetName()
180 if e.parent == nil {
181 s = make([]string, 1)
182 } else {
183 pname := e.parent.TypeName()
184 s = make([]string, len(pname)+1)
185 copy(s, pname)
186 }
187 s[len(s)-1] = name
188 e.typename = s
189 return s
190}
191
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... .
194func (e *EnumDescriptor) prefix() string {
195 if e.parent == nil {
196 // If the enum is not part of a message, the prefix is just the type name.
197 return CamelCase(*e.Name) + "_"
198 }
199 typeName := e.TypeName()
200 return CamelCaseSlice(typeName[0:len(typeName)-1]) + "_"
201}
202
203// The integer value of the named constant in this enumerated type.
204func (e *EnumDescriptor) integerValueAsString(name string) string {
205 for _, c := range e.Value {
206 if c.GetName() == name {
207 return fmt.Sprint(c.GetNumber())
208 }
209 }
210 log.Fatal("cannot find value for enum constant")
211 return ""
212}
213
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.
216type ExtensionDescriptor struct {
217 common
218 *descriptor.FieldDescriptorProto
219 parent *Descriptor // The containing message, if any.
220}
221
222// TypeName returns the elements of the dotted type name.
223// The package name is not part of this name.
224func (e *ExtensionDescriptor) TypeName() (s []string) {
225 name := e.GetName()
226 if e.parent == nil {
227 // top-level extension
228 s = make([]string, 1)
229 } else {
230 pname := e.parent.TypeName()
231 s = make([]string, len(pname)+1)
232 copy(s, pname)
233 }
234 s[len(s)-1] = name
235 return s
236}
237
238// DescName returns the variable name used for the generated descriptor.
239func (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)
245 }
246 return "E_" + strings.Join(typeName, "_")
247}
248
249// ImportedDescriptor describes a type that has been publicly imported from another file.
250type ImportedDescriptor struct {
251 common
252 o Object
253}
254
255func (id *ImportedDescriptor) TypeName() []string { return id.o.TypeName() }
256
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.
260type 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.
266
267 // Comments, stored as a map of path (comma-separated integers) to the comment.
268 comments map[string]*descriptor.SourceCodeInfo_Location
269
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
274
khenaidooac637102019-01-14 15:44:34 -0500275 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 {
William Kurkiandaa6bb22019-03-07 12:26:28 -0500285 h := sha256.Sum256([]byte(d.GetName()))
286 return fmt.Sprintf("fileDescriptor_%s", hex.EncodeToString(h[:8]))
khenaidooac637102019-01-14 15:44:34 -0500287}
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.
William Kurkiandaa6bb22019-03-07 12:26:28 -0500343 GenerateAlias(g *Generator, filename string, pkg GoPackageName)
khenaidooac637102019-01-14 15:44:34 -0500344}
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
William Kurkiandaa6bb22019-03-07 12:26:28 -0500359func (ms *messageSymbol) GenerateAlias(g *Generator, filename string, pkg GoPackageName) {
360 g.P("// ", ms.sym, " from public import ", filename)
khenaidooac637102019-01-14 15:44:34 -0500361 g.P("type ", ms.sym, " = ", pkg, ".", ms.sym)
362 for _, name := range ms.oneofTypes {
363 g.P("type ", name, " = ", pkg, ".", name)
364 }
365}
366
367type enumSymbol struct {
368 name string
369 proto3 bool // Whether this came from a proto3 file.
370}
371
William Kurkiandaa6bb22019-03-07 12:26:28 -0500372func (es enumSymbol) GenerateAlias(g *Generator, filename string, pkg GoPackageName) {
khenaidooac637102019-01-14 15:44:34 -0500373 s := es.name
William Kurkiandaa6bb22019-03-07 12:26:28 -0500374 g.P("// ", s, " from public import ", filename)
khenaidooac637102019-01-14 15:44:34 -0500375 g.P("type ", s, " = ", pkg, ".", s)
376 g.P("var ", s, "_name = ", pkg, ".", s, "_name")
377 g.P("var ", s, "_value = ", pkg, ".", s, "_value")
378}
379
380type constOrVarSymbol struct {
381 sym string
382 typ string // either "const" or "var"
383 cast string // if non-empty, a type cast is required (used for enums)
384}
385
William Kurkiandaa6bb22019-03-07 12:26:28 -0500386func (cs constOrVarSymbol) GenerateAlias(g *Generator, filename string, pkg GoPackageName) {
khenaidooac637102019-01-14 15:44:34 -0500387 v := string(pkg) + "." + cs.sym
388 if cs.cast != "" {
389 v = cs.cast + "(" + v + ")"
390 }
391 g.P(cs.typ, " ", cs.sym, " = ", v)
392}
393
394// Object is an interface abstracting the abilities shared by enums, messages, extensions and imported objects.
395type Object interface {
396 GoImportPath() GoImportPath
397 TypeName() []string
398 File() *FileDescriptor
399}
400
401// Generator is the type whose methods generate the output, stored in the associated response structure.
402type Generator struct {
403 *bytes.Buffer
404
405 Request *plugin.CodeGeneratorRequest // The input.
406 Response *plugin.CodeGeneratorResponse // The output.
407
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
412
413 Pkg map[string]string // The names under which we import support packages
414
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.
William Kurkiandaa6bb22019-03-07 12:26:28 -0500423 addedImports map[GoImportPath]bool // Additional imports to emit.
khenaidooac637102019-01-14 15:44:34 -0500424 typeNameToObject map[string]Object // Key is a fully-qualified name in input syntax.
425 init []string // Lines to emit in the init function.
426 indent string
427 pathType pathType // How to generate output filenames.
428 writeOutput bool
429 annotateCode bool // whether to store annotations
430 annotations []*descriptor.GeneratedCodeInfo_Annotation // annotations to store
431}
432
433type pathType int
434
435const (
436 pathTypeImport pathType = iota
437 pathTypeSourceRelative
438)
439
440// New creates a new generator and allocates the request and response protobufs.
441func New() *Generator {
442 g := new(Generator)
443 g.Buffer = new(bytes.Buffer)
444 g.Request = new(plugin.CodeGeneratorRequest)
445 g.Response = new(plugin.CodeGeneratorResponse)
446 return g
447}
448
449// Error reports a problem, including an error, and exits the program.
450func (g *Generator) Error(err error, msgs ...string) {
451 s := strings.Join(msgs, " ") + ":" + err.Error()
452 log.Print("protoc-gen-go: error:", s)
453 os.Exit(1)
454}
455
456// Fail reports a problem and exits the program.
457func (g *Generator) Fail(msgs ...string) {
458 s := strings.Join(msgs, " ")
459 log.Print("protoc-gen-go: error:", s)
460 os.Exit(1)
461}
462
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.
466func (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 {
470 g.Param[p] = ""
471 } else {
472 g.Param[p[0:i]] = p[i+1:]
473 }
474 }
475
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 {
479 switch k {
480 case "import_prefix":
481 g.ImportPrefix = v
482 case "import_path":
483 g.PackageImportPath = v
484 case "paths":
485 switch v {
486 case "import":
487 g.pathType = pathTypeImport
488 case "source_relative":
489 g.pathType = pathTypeSourceRelative
490 default:
491 g.Fail(fmt.Sprintf(`Unknown path type %q: want "import" or "source_relative".`, v))
492 }
493 case "plugins":
494 pluginList = v
495 case "annotate_code":
496 if v == "true" {
497 g.annotateCode = true
498 }
499 default:
500 if len(k) > 0 && k[0] == 'M' {
501 g.ImportMap[k[1:]] = v
502 }
503 }
504 }
505 if pluginList != "" {
506 // Amend the set of plugins.
507 enabled := make(map[string]bool)
508 for _, name := range strings.Split(pluginList, "+") {
509 enabled[name] = true
510 }
511 var nplugins []Plugin
512 for _, p := range plugins {
513 if enabled[p.Name()] {
514 nplugins = append(nplugins, p)
515 }
516 }
517 plugins = nplugins
518 }
519}
520
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.
524func (g *Generator) DefaultPackageName(obj Object) string {
525 importPath := obj.GoImportPath()
526 if importPath == g.outputImportPath {
527 return ""
528 }
529 return string(g.GoPackageName(importPath)) + "."
530}
531
532// GoPackageName returns the name used for a package.
533func (g *Generator) GoPackageName(importPath GoImportPath) GoPackageName {
534 if name, ok := g.packageNames[importPath]; ok {
535 return name
536 }
537 name := cleanPackageName(baseName(string(importPath)))
William Kurkiandaa6bb22019-03-07 12:26:28 -0500538 for i, orig := 1, name; g.usedPackageNames[name] || isGoPredeclaredIdentifier[string(name)]; i++ {
khenaidooac637102019-01-14 15:44:34 -0500539 name = orig + GoPackageName(strconv.Itoa(i))
540 }
541 g.packageNames[importPath] = name
542 g.usedPackageNames[name] = true
543 return name
544}
545
William Kurkiandaa6bb22019-03-07 12:26:28 -0500546// AddImport adds a package to the generated file's import section.
547// It returns the name used for the package.
548func (g *Generator) AddImport(importPath GoImportPath) GoPackageName {
549 g.addedImports[importPath] = true
550 return g.GoPackageName(importPath)
551}
552
khenaidooac637102019-01-14 15:44:34 -0500553var globalPackageNames = map[GoPackageName]bool{
554 "fmt": true,
555 "math": true,
556 "proto": true,
557}
558
559// Create and remember a guaranteed unique package name. Pkg is the candidate name.
560// The FileDescriptor parameter is unused.
561func 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))
565 }
566 globalPackageNames[name] = true
567 return string(name)
568}
569
570var isGoKeyword = map[string]bool{
571 "break": true,
572 "case": true,
573 "chan": true,
574 "const": true,
575 "continue": true,
576 "default": true,
577 "else": true,
578 "defer": true,
579 "fallthrough": true,
580 "for": true,
581 "func": true,
582 "go": true,
583 "goto": true,
584 "if": true,
585 "import": true,
586 "interface": true,
587 "map": true,
588 "package": true,
589 "range": true,
590 "return": true,
591 "select": true,
592 "struct": true,
593 "switch": true,
594 "type": true,
595 "var": true,
596}
597
William Kurkiandaa6bb22019-03-07 12:26:28 -0500598var isGoPredeclaredIdentifier = map[string]bool{
599 "append": true,
600 "bool": true,
601 "byte": true,
602 "cap": true,
603 "close": true,
604 "complex": true,
605 "complex128": true,
606 "complex64": true,
607 "copy": true,
608 "delete": true,
609 "error": true,
610 "false": true,
611 "float32": true,
612 "float64": true,
613 "imag": true,
614 "int": true,
615 "int16": true,
616 "int32": true,
617 "int64": true,
618 "int8": true,
619 "iota": true,
620 "len": true,
621 "make": true,
622 "new": true,
623 "nil": true,
624 "panic": true,
625 "print": true,
626 "println": true,
627 "real": true,
628 "recover": true,
629 "rune": true,
630 "string": true,
631 "true": true,
632 "uint": true,
633 "uint16": true,
634 "uint32": true,
635 "uint64": true,
636 "uint8": true,
637 "uintptr": true,
638}
639
khenaidooac637102019-01-14 15:44:34 -0500640func cleanPackageName(name string) GoPackageName {
641 name = strings.Map(badToUnderscore, name)
William Kurkiandaa6bb22019-03-07 12:26:28 -0500642 // Identifier must not be keyword or predeclared identifier: insert _.
khenaidooac637102019-01-14 15:44:34 -0500643 if isGoKeyword[name] {
644 name = "_" + name
645 }
646 // Identifier must not begin with digit: insert _.
647 if r, _ := utf8.DecodeRuneInString(name); unicode.IsDigit(r) {
648 name = "_" + name
649 }
650 return GoPackageName(name)
651}
652
653// defaultGoPackage returns the package name to use,
654// derived from the import path of the package we're building code for.
655func (g *Generator) defaultGoPackage() GoPackageName {
656 p := g.PackageImportPath
657 if i := strings.LastIndex(p, "/"); i >= 0 {
658 p = p[i+1:]
659 }
660 return cleanPackageName(p)
661}
662
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.
666func (g *Generator) SetPackageNames() {
667 g.outputImportPath = g.genFiles[0].importPath
668
669 defaultPackageNames := make(map[GoImportPath]GoPackageName)
670 for _, f := range g.genFiles {
671 if _, p, ok := f.goPackageOption(); ok {
672 defaultPackageNames[f.importPath] = p
673 }
674 }
675 for _, f := range g.genFiles {
676 if _, p, ok := f.goPackageOption(); ok {
677 // Source file: option go_package = "quux/bar";
678 f.packageName = p
679 } else if p, ok := defaultPackageNames[f.importPath]; ok {
680 // A go_package option in another file in the same package.
681 //
682 // This is a poor choice in general, since every source file should
683 // contain a go_package option. Supported mainly for historical
684 // compatibility.
685 f.packageName = p
686 } else if p := g.defaultGoPackage(); p != "" {
687 // Command-line: import_path=quux/bar.
688 //
689 // The import_path flag sets a package name for files which don't
690 // contain a go_package option.
691 f.packageName = p
692 } else if p := f.GetPackage(); p != "" {
693 // Source file: package quux.bar;
694 f.packageName = cleanPackageName(p)
695 } else {
696 // Source filename.
697 f.packageName = cleanPackageName(baseName(f.GetName()))
698 }
699 }
700
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))
705 }
706 if a, b := g.genFiles[0].packageName, f.packageName; a != b {
707 g.Fail(fmt.Sprintf("inconsistent package names: %v, %v", a, b))
708 }
709 }
710
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{
714 "fmt": "fmt",
715 "math": "math",
716 "proto": "proto",
717 }
718}
719
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.
723func (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
729 }
730 for _, f := range g.Request.ProtoFile {
731 fd := &FileDescriptor{
732 FileDescriptorProto: f,
733 exported: make(map[Object][]symbol),
734 proto3: fileIsProto3(f),
735 }
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.
739 //
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.
744 //
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";
750 //
751 // The go_package option sets the import path. Most users should use this.
752 fd.importPath = p
753 } else {
754 // Source filename.
755 //
756 // Last resort when nothing else is available.
757 fd.importPath = GoImportPath(path.Dir(f.GetName()))
758 }
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)
765 extractComments(fd)
766 g.allFiles = append(g.allFiles, fd)
767 g.allFilesByName[f.GetName()] = fd
768 }
769 for _, fd := range g.allFiles {
770 fd.imp = wrapImported(fd, g)
771 }
772
773 g.genFiles = make([]*FileDescriptor, 0, len(g.Request.FileToGenerate))
774 for _, fileName := range g.Request.FileToGenerate {
775 fd := g.allFilesByName[fileName]
776 if fd == nil {
777 g.Fail("could not find file named", fileName)
778 }
khenaidooac637102019-01-14 15:44:34 -0500779 g.genFiles = append(g.genFiles, fd)
780 }
781}
782
khenaidooac637102019-01-14 15:44:34 -0500783// Scan the descriptors in this file. For each one, build the slice of nested descriptors
784func (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)
790 }
791 }
792 if len(desc.nested) != len(desc.NestedType) {
793 g.Fail("internal error: nesting failure for", desc.GetName())
794 }
795 }
796 }
797}
798
799func (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)
805 }
806 }
807 if len(desc.enums) != len(desc.EnumType) {
808 g.Fail("internal error: enum nesting failure for", desc.GetName())
809 }
810 }
811 }
812}
813
814// Construct the Descriptor
815func newDescriptor(desc *descriptor.DescriptorProto, parent *Descriptor, file *FileDescriptor, index int) *Descriptor {
816 d := &Descriptor{
817 common: common{file},
818 DescriptorProto: desc,
819 parent: parent,
820 index: index,
821 }
822 if parent == nil {
823 d.path = fmt.Sprintf("%d,%d", messagePath, index)
824 } else {
825 d.path = fmt.Sprintf("%s,%d,%d", parent.path, messageMessagePath, index)
826 }
827
828 // The only way to distinguish a group from a message is whether
829 // the containing message has a TYPE_GROUP field that matches.
830 if parent != nil {
831 parts := d.TypeName()
832 if file.Package != nil {
833 parts = append([]string{*file.Package}, parts...)
834 }
835 exp := "." + strings.Join(parts, ".")
836 for _, field := range parent.Field {
837 if field.GetType() == descriptor.FieldDescriptorProto_TYPE_GROUP && field.GetTypeName() == exp {
838 d.group = true
839 break
840 }
841 }
842 }
843
844 for _, field := range desc.Extension {
845 d.ext = append(d.ext, &ExtensionDescriptor{common{file}, field, d})
846 }
847
848 return d
849}
850
851// Return a slice of all the Descriptors defined within this file
852func 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)
856 }
857 return sl
858}
859
860// Wrap this Descriptor, recursively
861func wrapThisDescriptor(sl []*Descriptor, desc *descriptor.DescriptorProto, parent *Descriptor, file *FileDescriptor, index int) []*Descriptor {
862 sl = append(sl, newDescriptor(desc, parent, file, index))
863 me := sl[len(sl)-1]
864 for i, nested := range desc.NestedType {
865 sl = wrapThisDescriptor(sl, nested, me, file, i)
866 }
867 return sl
868}
869
870// Construct the EnumDescriptor
871func newEnumDescriptor(desc *descriptor.EnumDescriptorProto, parent *Descriptor, file *FileDescriptor, index int) *EnumDescriptor {
872 ed := &EnumDescriptor{
873 common: common{file},
874 EnumDescriptorProto: desc,
875 parent: parent,
876 index: index,
877 }
878 if parent == nil {
879 ed.path = fmt.Sprintf("%d,%d", enumPath, index)
880 } else {
881 ed.path = fmt.Sprintf("%s,%d,%d", parent.path, messageEnumPath, index)
882 }
883 return ed
884}
885
886// Return a slice of all the EnumDescriptors defined within this file
887func wrapEnumDescriptors(file *FileDescriptor, descs []*Descriptor) []*EnumDescriptor {
888 sl := make([]*EnumDescriptor, 0, len(file.EnumType)+10)
889 // Top-level enums.
890 for i, enum := range file.EnumType {
891 sl = append(sl, newEnumDescriptor(enum, nil, file, i))
892 }
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))
897 }
898 }
899 return sl
900}
901
902// Return a slice of all the top-level ExtensionDescriptors defined within this file.
903func wrapExtensions(file *FileDescriptor) []*ExtensionDescriptor {
904 var sl []*ExtensionDescriptor
905 for _, field := range file.Extension {
906 sl = append(sl, &ExtensionDescriptor{common{file}, field, nil})
907 }
908 return sl
909}
910
911// Return a slice of all the types that are publicly imported into this file.
912func 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() {
917 continue
918 }
919 sl = append(sl, &ImportedDescriptor{common{file}, d})
920 }
921 for _, e := range df.enum {
922 sl = append(sl, &ImportedDescriptor{common{file}, e})
923 }
924 for _, ext := range df.ext {
925 sl = append(sl, &ImportedDescriptor{common{file}, ext})
926 }
927 }
928 return
929}
930
931func extractComments(file *FileDescriptor) {
932 file.comments = make(map[string]*descriptor.SourceCodeInfo_Location)
933 for _, loc := range file.GetSourceCodeInfo().GetLocation() {
934 if loc.LeadingComments == nil {
935 continue
936 }
937 var p []string
938 for _, n := range loc.Path {
939 p = append(p, strconv.Itoa(int(n)))
940 }
941 file.comments[strings.Join(p, ",")] = loc
942 }
943}
944
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.
948func (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 != "." {
956 dottedPkg += "."
957 }
958 for _, enum := range f.enum {
959 name := dottedPkg + dottedSlice(enum.TypeName())
960 g.typeNameToObject[name] = enum
961 }
962 for _, desc := range f.desc {
963 name := dottedPkg + dottedSlice(desc.TypeName())
964 g.typeNameToObject[name] = desc
965 }
966 }
967}
968
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.
971func (g *Generator) ObjectNamed(typeName string) Object {
972 o, ok := g.typeNameToObject[typeName]
973 if !ok {
974 g.Fail("can't find object with type", typeName)
975 }
khenaidooac637102019-01-14 15:44:34 -0500976 return o
977}
978
979// AnnotatedAtoms is a list of atoms (as consumed by P) that records the file name and proto AST path from which they originated.
980type AnnotatedAtoms struct {
981 source string
982 path string
983 atoms []interface{}
984}
985
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.
988func Annotate(file *FileDescriptor, path string, atoms ...interface{}) *AnnotatedAtoms {
989 return &AnnotatedAtoms{source: *file.Name, path: path, atoms: atoms}
990}
991
992// printAtom prints the (atomic, non-annotation) argument to the generated output.
993func (g *Generator) printAtom(v interface{}) {
994 switch v := v.(type) {
995 case string:
996 g.WriteString(v)
997 case *string:
998 g.WriteString(*v)
999 case bool:
1000 fmt.Fprint(g, v)
1001 case *bool:
1002 fmt.Fprint(g, *v)
1003 case int:
1004 fmt.Fprint(g, v)
1005 case *int32:
1006 fmt.Fprint(g, *v)
1007 case *int64:
1008 fmt.Fprint(g, *v)
1009 case float64:
1010 fmt.Fprint(g, v)
1011 case *float64:
1012 fmt.Fprint(g, *v)
1013 case GoPackageName:
1014 g.WriteString(string(v))
1015 case GoImportPath:
1016 g.WriteString(strconv.Quote(string(v)))
1017 default:
1018 g.Fail(fmt.Sprintf("unknown type in printer: %T", v))
1019 }
1020}
1021
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
1025// is true).
1026func (g *Generator) P(str ...interface{}) {
1027 if !g.writeOutput {
1028 return
1029 }
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 {
1036 g.printAtom(v)
1037 }
1038 if g.annotateCode {
1039 end := int32(g.Len())
1040 var path []int32
1041 for _, token := range strings.Split(v.path, ",") {
1042 val, err := strconv.ParseInt(token, 10, 32)
1043 if err != nil {
1044 g.Fail("could not parse proto AST path: ", err.Error())
1045 }
1046 path = append(path, int32(val))
1047 }
1048 g.annotations = append(g.annotations, &descriptor.GeneratedCodeInfo_Annotation{
1049 Path: path,
1050 SourceFile: &v.source,
1051 Begin: &begin,
1052 End: &end,
1053 })
1054 }
1055 default:
1056 g.printAtom(v)
1057 }
1058 }
1059 g.WriteByte('\n')
1060}
1061
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.
1064func (g *Generator) addInitf(stmt string, a ...interface{}) {
1065 g.init = append(g.init, fmt.Sprintf(stmt, a...))
1066}
1067
1068// In Indents the output one tab stop.
1069func (g *Generator) In() { g.indent += "\t" }
1070
1071// Out unindents the output one tab stop.
1072func (g *Generator) Out() {
1073 if len(g.indent) > 0 {
1074 g.indent = g.indent[1:]
1075 }
1076}
1077
1078// GenerateAllFiles generates the output for all the files we're outputting.
1079func (g *Generator) GenerateAllFiles() {
1080 // Initialize the plugins
1081 for _, p := range plugins {
1082 p.Init(g)
1083 }
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
1090 }
1091 for _, file := range g.allFiles {
1092 g.Reset()
1093 g.annotations = nil
1094 g.writeOutput = genFileMap[file]
1095 g.generate(file)
1096 if !g.writeOutput {
1097 continue
1098 }
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()),
1103 })
1104 if g.annotateCode {
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})),
1110 })
1111 }
1112 }
1113}
1114
1115// Run all the plugins associated with the file.
1116func (g *Generator) runPlugins(file *FileDescriptor) {
1117 for _, p := range plugins {
1118 p.Generate(file)
1119 }
1120}
1121
1122// Fill the response protocol buffer with the generated output for all the files we're
1123// supposed to generate.
1124func (g *Generator) generate(file *FileDescriptor) {
1125 g.file = file
1126 g.usedPackages = make(map[GoImportPath]bool)
1127 g.packageNames = make(map[GoImportPath]GoPackageName)
1128 g.usedPackageNames = make(map[GoPackageName]bool)
William Kurkiandaa6bb22019-03-07 12:26:28 -05001129 g.addedImports = make(map[GoImportPath]bool)
khenaidooac637102019-01-14 15:44:34 -05001130 for name := range globalPackageNames {
1131 g.usedPackageNames[name] = true
1132 }
1133
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")
1139 g.P()
1140
1141 for _, td := range g.file.imp {
1142 g.generateImported(td)
1143 }
1144 for _, enum := range g.file.enum {
1145 g.generateEnum(enum)
1146 }
1147 for _, desc := range g.file.desc {
1148 // Don't generate virtual messages for maps.
1149 if desc.GetOptions().GetMapEntry() {
1150 continue
1151 }
1152 g.generateMessage(desc)
1153 }
1154 for _, ext := range g.file.ext {
1155 g.generateExtension(ext)
1156 }
1157 g.generateInitFunction()
William Kurkiandaa6bb22019-03-07 12:26:28 -05001158 g.generateFileDescriptor(file)
khenaidooac637102019-01-14 15:44:34 -05001159
1160 // Run the plugins before the imports so we know which imports are necessary.
1161 g.runPlugins(file)
1162
khenaidooac637102019-01-14 15:44:34 -05001163 // Generate header and imports last, though they appear first in the output.
1164 rem := g.Buffer
1165 remAnno := g.annotations
1166 g.Buffer = new(bytes.Buffer)
1167 g.annotations = nil
1168 g.generateHeader()
1169 g.generateImports()
1170 if !g.writeOutput {
1171 return
1172 }
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)
1178 }
1179 g.Write(rem.Bytes())
1180
1181 // Reformat generated code and patch annotation locations.
1182 fset := token.NewFileSet()
1183 original := g.Bytes()
1184 if g.annotateCode {
1185 // make a copy independent of g; we'll need it after Reset.
1186 original = append([]byte(nil), original...)
1187 }
William Kurkiandaa6bb22019-03-07 12:26:28 -05001188 fileAST, err := parser.ParseFile(fset, "", original, parser.ParseComments)
khenaidooac637102019-01-14 15:44:34 -05001189 if err != nil {
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())
1197 }
1198 g.Fail("bad Go source code was generated:", err.Error(), "\n"+src.String())
1199 }
William Kurkiandaa6bb22019-03-07 12:26:28 -05001200 ast.SortImports(fset, fileAST)
khenaidooac637102019-01-14 15:44:34 -05001201 g.Reset()
William Kurkiandaa6bb22019-03-07 12:26:28 -05001202 err = (&printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}).Fprint(g, fset, fileAST)
khenaidooac637102019-01-14 15:44:34 -05001203 if err != nil {
1204 g.Fail("generated Go source code could not be reformatted:", err.Error())
1205 }
1206 if g.annotateCode {
1207 m, err := remap.Compute(original, g.Bytes())
1208 if err != nil {
1209 g.Fail("formatted generated Go source code could not be mapped back to the original code:", err.Error())
1210 }
1211 for _, anno := range g.annotations {
1212 new, ok := m.Find(int(*anno.Begin), int(*anno.End))
1213 if !ok {
1214 g.Fail("span in formatted generated Go source code could not be mapped back to the original code")
1215 }
1216 *anno.Begin = int32(new.Pos)
1217 *anno.End = int32(new.End)
1218 }
1219 }
1220}
1221
1222// Generate the header, including package definition
1223func (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.")
1227 } else {
1228 g.P("// source: ", g.file.Name)
1229 }
1230 g.P()
William Kurkiandaa6bb22019-03-07 12:26:28 -05001231 g.PrintComments(strconv.Itoa(packagePath))
khenaidooac637102019-01-14 15:44:34 -05001232 g.P()
William Kurkiandaa6bb22019-03-07 12:26:28 -05001233 g.P("package ", g.file.packageName)
1234 g.P()
khenaidooac637102019-01-14 15:44:34 -05001235}
1236
1237// deprecationComment is the standard comment added to deprecated
1238// messages, fields, enums, and enum values.
1239var deprecationComment = "// Deprecated: Do not use."
1240
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.
1245func (g *Generator) PrintComments(path string) bool {
1246 if !g.writeOutput {
1247 return false
1248 }
1249 if c, ok := g.makeComments(path); ok {
1250 g.P(c)
1251 return true
1252 }
1253 return false
1254}
1255
1256// makeComments generates the comment string for the field, no "\n" at the end
1257func (g *Generator) makeComments(path string) (string, bool) {
1258 loc, ok := g.file.comments[path]
1259 if !ok {
1260 return "", false
1261 }
1262 w := new(bytes.Buffer)
1263 nl := ""
1264 for _, line := range strings.Split(strings.TrimSuffix(loc.GetLeadingComments(), "\n"), "\n") {
William Kurkiandaa6bb22019-03-07 12:26:28 -05001265 fmt.Fprintf(w, "%s//%s", nl, line)
khenaidooac637102019-01-14 15:44:34 -05001266 nl = "\n"
1267 }
1268 return w.String(), true
1269}
1270
1271func (g *Generator) fileByName(filename string) *FileDescriptor {
1272 return g.allFilesByName[filename]
1273}
1274
1275// weak returns whether the ith import of the current file is a weak import.
1276func (g *Generator) weak(i int32) bool {
1277 for _, j := range g.file.WeakDependency {
1278 if j == i {
1279 return true
1280 }
1281 }
1282 return false
1283}
1284
1285// Generate the imports
1286func (g *Generator) generateImports() {
William Kurkiandaa6bb22019-03-07 12:26:28 -05001287 imports := make(map[GoImportPath]GoPackageName)
khenaidooac637102019-01-14 15:44:34 -05001288 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 {
1293 continue
1294 }
William Kurkiandaa6bb22019-03-07 12:26:28 -05001295 // Do not import weak imports.
1296 if g.weak(int32(i)) {
1297 continue
khenaidooac637102019-01-14 15:44:34 -05001298 }
William Kurkiandaa6bb22019-03-07 12:26:28 -05001299 // Do not import a package twice.
1300 if _, ok := imports[importPath]; ok {
khenaidooac637102019-01-14 15:44:34 -05001301 continue
1302 }
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.
William Kurkiandaa6bb22019-03-07 12:26:28 -05001306 packageName := g.GoPackageName(importPath)
khenaidooac637102019-01-14 15:44:34 -05001307 if _, ok := g.usedPackages[importPath]; !ok {
1308 packageName = "_"
1309 }
William Kurkiandaa6bb22019-03-07 12:26:28 -05001310 imports[importPath] = packageName
khenaidooac637102019-01-14 15:44:34 -05001311 }
William Kurkiandaa6bb22019-03-07 12:26:28 -05001312 for importPath := range g.addedImports {
1313 imports[importPath] = g.GoPackageName(importPath)
1314 }
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.
1318 g.P("import (")
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)
1324 }
1325 g.P(")")
khenaidooac637102019-01-14 15:44:34 -05001326 g.P()
1327 // TODO: may need to worry about uniqueness across plugins
1328 for _, p := range plugins {
1329 p.GenerateImports(g.file)
1330 g.P()
1331 }
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")
1336 g.P()
1337}
1338
1339func (g *Generator) generateImported(id *ImportedDescriptor) {
khenaidooac637102019-01-14 15:44:34 -05001340 df := id.o.File()
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.
khenaidooac637102019-01-14 15:44:34 -05001344 return
1345 }
1346 if !supportTypeAliases {
1347 g.Fail(fmt.Sprintf("%s: public imports require at least go1.9", filename))
1348 }
khenaidooac637102019-01-14 15:44:34 -05001349 g.usedPackages[df.importPath] = true
1350
1351 for _, sym := range df.exported[id.o] {
William Kurkiandaa6bb22019-03-07 12:26:28 -05001352 sym.GenerateAlias(g, filename, g.GoPackageName(df.importPath))
khenaidooac637102019-01-14 15:44:34 -05001353 }
1354
1355 g.P()
1356}
1357
1358// Generate the enum definitions for this EnumDescriptor.
1359func (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()
1365
1366 deprecatedEnum := ""
1367 if enum.GetOptions().GetDeprecated() {
1368 deprecatedEnum = deprecationComment
1369 }
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()})
1373 g.P("const (")
1374 for i, e := range enum.Value {
1375 etorPath := fmt.Sprintf("%s,%d,%d", enum.path, enumValuePath, i)
1376 g.PrintComments(etorPath)
1377
1378 deprecatedValue := ""
1379 if e.GetOptions().GetDeprecated() {
1380 deprecatedValue = deprecationComment
1381 }
1382
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})
1386 }
1387 g.P(")")
William Kurkiandaa6bb22019-03-07 12:26:28 -05001388 g.P()
khenaidooac637102019-01-14 15:44:34 -05001389 g.P("var ", ccTypeName, "_name = map[int32]string{")
1390 generated := make(map[int32]bool) // avoid duplicate values
1391 for _, e := range enum.Value {
1392 duplicate := ""
1393 if _, present := generated[*e.Number]; present {
1394 duplicate = "// Duplicate value: "
1395 }
1396 g.P(duplicate, e.Number, ": ", strconv.Quote(*e.Name), ",")
1397 generated[*e.Number] = true
1398 }
1399 g.P("}")
William Kurkiandaa6bb22019-03-07 12:26:28 -05001400 g.P()
khenaidooac637102019-01-14 15:44:34 -05001401 g.P("var ", ccTypeName, "_value = map[string]int32{")
1402 for _, e := range enum.Value {
1403 g.P(strconv.Quote(*e.Name), ": ", e.Number, ",")
1404 }
1405 g.P("}")
William Kurkiandaa6bb22019-03-07 12:26:28 -05001406 g.P()
khenaidooac637102019-01-14 15:44:34 -05001407
1408 if !enum.proto3() {
1409 g.P("func (x ", ccTypeName, ") Enum() *", ccTypeName, " {")
1410 g.P("p := new(", ccTypeName, ")")
1411 g.P("*p = x")
1412 g.P("return p")
1413 g.P("}")
William Kurkiandaa6bb22019-03-07 12:26:28 -05001414 g.P()
khenaidooac637102019-01-14 15:44:34 -05001415 }
1416
1417 g.P("func (x ", ccTypeName, ") String() string {")
1418 g.P("return ", g.Pkg["proto"], ".EnumName(", ccTypeName, "_name, int32(x))")
1419 g.P("}")
William Kurkiandaa6bb22019-03-07 12:26:28 -05001420 g.P()
khenaidooac637102019-01-14 15:44:34 -05001421
1422 if !enum.proto3() {
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 {")
1426 g.P("return err")
1427 g.P("}")
1428 g.P("*x = ", ccTypeName, "(value)")
1429 g.P("return nil")
1430 g.P("}")
William Kurkiandaa6bb22019-03-07 12:26:28 -05001431 g.P()
khenaidooac637102019-01-14 15:44:34 -05001432 }
1433
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...)
1438 }
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, ", "), "}")
1442 g.P("}")
William Kurkiandaa6bb22019-03-07 12:26:28 -05001443 g.P()
khenaidooac637102019-01-14 15:44:34 -05001444 if enum.file.GetPackage() == "google.protobuf" && enum.GetName() == "NullValue" {
1445 g.P("func (", ccTypeName, `) XXX_WellKnownType() string { return "`, enum.GetName(), `" }`)
William Kurkiandaa6bb22019-03-07 12:26:28 -05001446 g.P()
khenaidooac637102019-01-14 15:44:34 -05001447 }
1448
William Kurkiandaa6bb22019-03-07 12:26:28 -05001449 g.generateEnumRegistration(enum)
khenaidooac637102019-01-14 15:44:34 -05001450}
1451
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:
1455// wire encoding
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.
1465func (g *Generator) goTag(message *Descriptor, field *descriptor.FieldDescriptorProto, wiretype string) string {
1466 optrepreq := ""
1467 switch {
1468 case isOptional(field):
1469 optrepreq = "opt"
1470 case isRequired(field):
1471 optrepreq = "req"
1472 case isRepeated(field):
1473 optrepreq = "rep"
1474 }
1475 var defaultValue string
1476 if dv := field.DefaultValue; dv != nil { // set means an explicit default
1477 defaultValue = *dv
1478 // Some types need tweaking.
1479 switch *field.Type {
1480 case descriptor.FieldDescriptorProto_TYPE_BOOL:
1481 if defaultValue == "true" {
1482 defaultValue = "1"
1483 } else {
1484 defaultValue = "0"
1485 }
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.
1495 obj = id.o
1496 }
1497 enum, ok := obj.(*EnumDescriptor)
1498 if !ok {
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)
1502 }
1503 g.Fail("unknown enum type", CamelCaseSlice(obj.TypeName()))
1504 }
1505 defaultValue = enum.integerValueAsString(defaultValue)
William Kurkiandaa6bb22019-03-07 12:26:28 -05001506 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))
1510 }
1511 }
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)
1516 }
1517 }
khenaidooac637102019-01-14 15:44:34 -05001518 }
1519 defaultValue = ",def=" + defaultValue
1520 }
1521 enum := ""
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 {
1527 obj = id.o
1528 }
1529 enum = ",enum="
1530 if pkg := obj.File().GetPackage(); pkg != "" {
1531 enum += pkg + "."
1532 }
1533 enum += CamelCaseSlice(obj.TypeName())
1534 }
1535 packed := ""
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)) {
1541 packed = ",packed"
1542 }
1543 fieldName := field.GetName()
1544 name := fieldName
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 {
1552 name = name[i+1:]
1553 }
1554 }
William Kurkiandaa6bb22019-03-07 12:26:28 -05001555 if json := field.GetJsonName(); field.Extendee == nil && json != "" && json != name {
khenaidooac637102019-01-14 15:44:34 -05001556 // TODO: escaping might be needed, in which case
1557 // perhaps this should be in its own "json" tag.
1558 name += ",json=" + json
1559 }
1560 name = ",name=" + name
1561 if message.proto3() {
1562 name += ",proto3"
1563 }
1564 oneof := ""
1565 if field.OneofIndex != nil {
1566 oneof = ",oneof"
1567 }
1568 return strconv.Quote(fmt.Sprintf("%s,%d,%s%s%s%s%s%s",
1569 wiretype,
1570 field.GetNumber(),
1571 optrepreq,
1572 packed,
1573 name,
1574 enum,
1575 oneof,
1576 defaultValue))
1577}
1578
1579func needsStar(typ descriptor.FieldDescriptorProto_Type) bool {
1580 switch typ {
1581 case descriptor.FieldDescriptorProto_TYPE_GROUP:
1582 return false
1583 case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
1584 return false
1585 case descriptor.FieldDescriptorProto_TYPE_BYTES:
1586 return false
1587 }
1588 return true
1589}
1590
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.
1596func (g *Generator) TypeName(obj Object) string {
1597 return g.DefaultPackageName(obj) + CamelCaseSlice(obj.TypeName())
1598}
1599
1600// GoType returns a string representing the type name, and the wire type
1601func (g *Generator) GoType(message *Descriptor, field *descriptor.FieldDescriptorProto) (typ string, wire string) {
1602 // TODO: Options.
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"
1643 default:
1644 g.Fail("unknown type for", field.GetName())
1645 }
1646 if isRepeated(field) {
1647 typ = "[]" + typ
1648 } else if message != nil && message.proto3() {
1649 return
1650 } else if field.OneofIndex != nil && message != nil {
1651 return
1652 } else if needsStar(*field.Type) {
1653 typ = "*" + typ
1654 }
1655 return
1656}
1657
1658func (g *Generator) RecordTypeUse(t string) {
William Kurkiandaa6bb22019-03-07 12:26:28 -05001659 if _, ok := g.typeNameToObject[t]; !ok {
1660 return
khenaidooac637102019-01-14 15:44:34 -05001661 }
William Kurkiandaa6bb22019-03-07 12:26:28 -05001662 importPath := g.ObjectNamed(t).GoImportPath()
1663 if importPath == g.outputImportPath {
1664 // Don't record use of objects in our package.
1665 return
1666 }
1667 g.AddImport(importPath)
1668 g.usedPackages[importPath] = true
khenaidooac637102019-01-14 15:44:34 -05001669}
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
William Kurkiandaa6bb22019-03-07 12:26:28 -05001768// msgCtx contains the context for the generator functions.
khenaidooac637102019-01-14 15:44:34 -05001769type 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"
William Kurkiandaa6bb22019-03-07 12:26:28 -05001872 deprecated string // Deprecation comment, if any.
khenaidooac637102019-01-14 15:44:34 -05001873}
1874
1875// typedNil prints a nil casted to the pointer to this field.
William Kurkiandaa6bb22019-03-07 12:26:28 -05001876// - for XXX_OneofWrappers
khenaidooac637102019-01-14 15:44:34 -05001877func (f *oneofSubField) typedNil(g *Generator) {
1878 g.P("(*", f.oneofTypeName, ")(nil),")
1879}
1880
khenaidooac637102019-01-14 15:44:34 -05001881// getProtoDef returns the default value explicitly stated in the proto file, e.g "yoshi" or "5".
1882func (f *oneofSubField) getProtoDef() string {
1883 return f.protoDef
1884}
1885
1886// getProtoTypeName returns the protobuf type name for the field as returned by field.GetTypeName(), e.g. ".google.protobuf.Duration".
1887func (f *oneofSubField) getProtoTypeName() string {
1888 return f.protoTypeName
1889}
1890
1891// getProtoType returns the *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64.
1892func (f *oneofSubField) getProtoType() descriptor.FieldDescriptorProto_Type {
1893 return f.protoType
1894}
1895
1896// oneofField represents the oneof on top level.
1897// The alternative fields within the oneof are represented by oneofSubField.
1898type oneofField struct {
1899 fieldCommon
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\\"
1902}
1903
1904// decl prints the declaration of the field in the struct (if any).
1905func (f *oneofField) decl(g *Generator, mc *msgCtx) {
1906 comment := f.comment
1907 for _, sf := range f.subFields {
1908 comment += "//\t*" + sf.oneofTypeName + "\n"
1909 }
1910 g.P(comment, Annotate(mc.message.file, f.fullPath, f.goName), " ", f.goType, " `", f.tags, "`")
1911}
1912
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.
1915func (f *oneofField) getter(g *Generator, mc *msgCtx) {
1916 // The discriminator type
1917 g.P("type ", f.goType, " interface {")
1918 g.P(f.goType, "()")
1919 g.P("}")
1920 g.P()
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, "`")
1925 g.P("}")
1926 g.P()
1927 }
1928 for _, sf := range f.subFields {
1929 g.P("func (*", sf.oneofTypeName, ") ", f.goType, "() {}")
1930 g.P()
1931 }
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, " }")
1935 g.P("return nil")
1936 g.P("}")
1937 g.P()
1938 // Getters for each oneof
1939 for _, sf := range f.subFields {
William Kurkiandaa6bb22019-03-07 12:26:28 -05001940 if sf.deprecated != "" {
1941 g.P(sf.deprecated)
1942 }
khenaidooac637102019-01-14 15:44:34 -05001943 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)
1946 g.P("}")
1947 g.P("return ", sf.getterDef)
1948 g.P("}")
1949 g.P()
1950 }
1951}
1952
1953// setter prints the setter method of the field.
1954func (f *oneofField) setter(g *Generator, mc *msgCtx) {
1955 // No setters for oneof yet
1956}
1957
1958// topLevelField interface implemented by all types of fields on the top level (not oneofSubField).
1959type 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
1963}
1964
1965// defField interface implemented by all types of fields that can have defaults (not oneofField, but instead oneofSubField).
1966type 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
1972}
1973
1974// generateDefaultConstants adds constants for default values if needed, which is only if the default value is.
1975// explicit in the proto.
1976func (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)
1983 }
1984 continue
1985 }
1986 dFields = append(dFields, pf.(defField))
1987 }
1988 for _, df := range dFields {
1989 def := df.getProtoDef()
1990 if def == "" {
1991 continue
1992 }
1993 fieldname := g.defaultConstantName(mc.goName, df.getProtoName())
1994 typename := df.getGoType()
1995 if typename[0] == '*' {
1996 typename = typename[1:]
1997 }
1998 kind := "const "
1999 switch {
2000 case typename == "bool":
2001 case typename == "string":
2002 def = strconv.Quote(def)
2003 case typename == "[]byte":
2004 def = "[]byte(" + strconv.Quote(unescape(def)) + ")"
2005 kind = "var "
2006 case def == "inf", def == "-inf", def == "nan":
2007 // These names are known to, and defined by, the protocol language.
2008 switch def {
2009 case "inf":
2010 def = "math.Inf(1)"
2011 case "-inf":
2012 def = "math.Inf(-1)"
2013 case "nan":
2014 def = "math.NaN()"
2015 }
2016 if df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_FLOAT {
2017 def = "float32(" + def + ")"
2018 }
2019 kind = "var "
William Kurkiandaa6bb22019-03-07 12:26:28 -05002020 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_FLOAT:
2021 if f, err := strconv.ParseFloat(def, 32); err == nil {
2022 def = fmt.Sprint(float32(f))
2023 }
2024 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_DOUBLE:
2025 if f, err := strconv.ParseFloat(def, 64); err == nil {
2026 def = fmt.Sprint(f)
2027 }
khenaidooac637102019-01-14 15:44:34 -05002028 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)
2035 } else {
2036 enum, _ = obj.(*EnumDescriptor)
2037 }
2038 if enum == nil {
2039 log.Printf("don't know how to generate constant for %s", fieldname)
2040 continue
2041 }
2042 def = g.DefaultPackageName(obj) + enum.prefix() + def
2043 }
2044 g.P(kind, fieldname, " ", typename, " = ", def)
2045 g.file.addExport(mc.message, constOrVarSymbol{fieldname, kind, ""})
2046 }
2047 g.P()
2048}
2049
2050// generateInternalStructFields just adds the XXX_<something> fields to the message struct.
2051func (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 {
2054 messageset := ""
2055 if opts := mc.message.Options; opts != nil && opts.GetMessageSetWireFormat() {
2056 messageset = "protobuf_messageset:\"1\" "
2057 }
2058 g.P(g.Pkg["proto"], ".XXX_InternalExtensions `", messageset, "json:\"-\"`")
2059 }
2060 g.P("XXX_unrecognized\t[]byte `json:\"-\"`")
2061 g.P("XXX_sizecache\tint32 `json:\"-\"`")
2062
2063}
2064
2065// generateOneofFuncs adds all the utility functions for oneof, including marshalling, unmarshalling and sizer.
2066func (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)
2071 }
2072 }
2073 if len(ofields) == 0 {
2074 return
2075 }
khenaidooac637102019-01-14 15:44:34 -05002076
2077 // OneofFuncs
William Kurkiandaa6bb22019-03-07 12:26:28 -05002078 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{}{")
khenaidooac637102019-01-14 15:44:34 -05002081 for _, of := range ofields {
2082 for _, sf := range of.subFields {
2083 sf.typedNil(g)
2084 }
2085 }
2086 g.P("}")
2087 g.P("}")
2088 g.P()
khenaidooac637102019-01-14 15:44:34 -05002089}
2090
2091// generateMessageStruct adds the actual struct with it's members (but not methods) to the output.
2092func (g *Generator) generateMessageStruct(mc *msgCtx, topLevelFields []topLevelField) {
2093 comments := g.PrintComments(mc.message.path)
2094
2095 // Guarantee deprecation comments appear after user-provided comments.
2096 if mc.message.GetOptions().GetDeprecated() {
2097 if comments {
2098 // Convention: Separate deprecation comments from original
2099 // comments with an empty line.
2100 g.P("//")
2101 }
2102 g.P(deprecationComment)
2103 }
2104
2105 g.P("type ", Annotate(mc.message.file, mc.message.path, mc.goName), " struct {")
2106 for _, pf := range topLevelFields {
2107 pf.decl(g, mc)
2108 }
2109 g.generateInternalStructFields(mc, topLevelFields)
2110 g.P("}")
2111}
2112
2113// generateGetters adds getters for all fields, including oneofs and weak fields when applicable.
2114func (g *Generator) generateGetters(mc *msgCtx, topLevelFields []topLevelField) {
2115 for _, pf := range topLevelFields {
2116 pf.getter(g, mc)
2117 }
2118}
2119
2120// generateSetters add setters for all fields, including oneofs and weak fields when applicable.
2121func (g *Generator) generateSetters(mc *msgCtx, topLevelFields []topLevelField) {
2122 for _, pf := range topLevelFields {
2123 pf.setter(g, mc)
2124 }
2125}
2126
2127// generateCommonMethods adds methods to the message that are not on a per field basis.
2128func (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...)
2136 }
2137 g.P("func (*", mc.goName, ") Descriptor() ([]byte, []int) {")
2138 g.P("return ", g.file.VarName(), ", []int{", strings.Join(indexes, ", "), "}")
2139 g.P("}")
William Kurkiandaa6bb22019-03-07 12:26:28 -05002140 g.P()
khenaidooac637102019-01-14 15:44:34 -05002141 // 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(), `" }`)
William Kurkiandaa6bb22019-03-07 12:26:28 -05002145 g.P()
khenaidooac637102019-01-14 15:44:34 -05002146 }
2147
2148 // Extension support methods
2149 if len(mc.message.ExtensionRange) > 0 {
khenaidooac637102019-01-14 15:44:34 -05002150 g.P()
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, "},")
2155 }
2156 g.P("}")
2157 g.P("func (*", mc.goName, ") ExtensionRangeArray() []", g.Pkg["proto"], ".ExtensionRange {")
2158 g.P("return extRange_", mc.goName)
2159 g.P("}")
William Kurkiandaa6bb22019-03-07 12:26:28 -05002160 g.P()
khenaidooac637102019-01-14 15:44:34 -05002161 }
2162
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.
2168
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)")
2172 g.P("}")
2173
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)")
2176 g.P("}")
2177
William Kurkiandaa6bb22019-03-07 12:26:28 -05002178 g.P("func (m *", mc.goName, ") XXX_Merge(src ", g.Pkg["proto"], ".Message) {")
2179 g.P("xxx_messageInfo_", mc.goName, ".Merge(m, src)")
khenaidooac637102019-01-14 15:44:34 -05002180 g.P("}")
2181
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)")
2184 g.P("}")
2185
2186 g.P("func (m *", mc.goName, ") XXX_DiscardUnknown() {")
2187 g.P("xxx_messageInfo_", mc.goName, ".DiscardUnknown(m)")
2188 g.P("}")
2189
2190 g.P("var xxx_messageInfo_", mc.goName, " ", g.Pkg["proto"], ".InternalMessageInfo")
2191 g.P()
2192}
2193
2194// Generate the type, methods and default constant definitions for this Descriptor.
2195func (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)
2202
2203 usedNames := make(map[string]bool)
2204 for _, n := range methodNames {
2205 usedNames[n] = true
2206 }
2207
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 {
2212 Loop:
2213 for {
2214 for _, n := range ns {
2215 if usedNames[n] {
2216 for i := range ns {
2217 ns[i] += "_"
2218 }
2219 continue Loop
2220 }
2221 }
2222 for _, n := range ns {
2223 usedNames[n] = true
2224 }
2225 return ns
2226 }
2227 }
2228
2229 mapFieldTypes := make(map[*descriptor.FieldDescriptorProto]string) // keep track of the map fields to be added later
2230
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")
2244
2245 oneof := field.OneofIndex != nil
2246 if oneof && oFields[*field.OneofIndex] == nil {
2247 odp := message.OneofDecl[int(*field.OneofIndex)]
2248 base := CamelCase(odp.GetName())
William Kurkiandaa6bb22019-03-07 12:26:28 -05002249 fname := allocNames(base)[0]
khenaidooac637102019-01-14 15:44:34 -05002250
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)
2255 if ok {
2256 c += "\n//\n"
2257 }
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.
2261
2262 dname := "is" + goTypeName + "_" + fname
2263 tag := `protobuf_oneof:"` + odp.GetName() + `"`
2264 of := oneofField{
2265 fieldCommon: fieldCommon{
2266 goName: fname,
William Kurkiandaa6bb22019-03-07 12:26:28 -05002267 getterName: "Get"+fname,
khenaidooac637102019-01-14 15:44:34 -05002268 goType: dname,
2269 tags: tag,
2270 protoName: odp.GetName(),
2271 fullPath: oneofFullPath,
2272 },
2273 comment: c,
2274 }
2275 topLevelFields = append(topLevelFields, &of)
2276 oFields[*field.OneofIndex] = &of
2277 }
2278
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)
2287
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())
2298 default:
2299 valType = strings.TrimPrefix(valType, "*")
2300 }
2301
2302 typename = fmt.Sprintf("map[%s]%s", keyType, valType)
2303 mapFieldTypes[field] = typename // record for the getter generation
2304
2305 tag += fmt.Sprintf(" protobuf_key:%s protobuf_val:%s", keyTag, valTag)
2306 }
2307 }
2308
William Kurkiandaa6bb22019-03-07 12:26:28 -05002309 fieldDeprecated := ""
2310 if field.GetOptions().GetDeprecated() {
2311 fieldDeprecated = deprecationComment
2312 }
2313
khenaidooac637102019-01-14 15:44:34 -05002314 dvalue := g.getterDefault(field, goTypeName)
2315 if oneof {
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.
2319 for {
2320 ok := true
2321 for _, desc := range message.nested {
2322 if CamelCaseSlice(desc.TypeName()) == tname {
2323 ok = false
2324 break
2325 }
2326 }
2327 for _, enum := range message.enums {
2328 if CamelCaseSlice(enum.TypeName()) == tname {
2329 ok = false
2330 break
2331 }
2332 }
2333 if !ok {
2334 tname += "_"
2335 continue
2336 }
2337 break
2338 }
2339
2340 oneofField := oFields[*field.OneofIndex]
2341 tag := "protobuf:" + g.goTag(message, field, wiretype)
2342 sf := oneofSubField{
2343 fieldCommon: fieldCommon{
2344 goName: fieldName,
2345 getterName: fieldGetterName,
2346 goType: typename,
2347 tags: tag,
2348 protoName: field.GetName(),
2349 fullPath: fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i),
2350 },
2351 protoTypeName: field.GetTypeName(),
2352 fieldNumber: int(*field.Number),
2353 protoType: *field.Type,
2354 getterDef: dvalue,
2355 protoDef: field.GetDefaultValue(),
2356 oneofTypeName: tname,
William Kurkiandaa6bb22019-03-07 12:26:28 -05002357 deprecated: fieldDeprecated,
khenaidooac637102019-01-14 15:44:34 -05002358 }
2359 oneofField.subFields = append(oneofField.subFields, &sf)
2360 g.RecordTypeUse(field.GetTypeName())
2361 continue
2362 }
2363
khenaidooac637102019-01-14 15:44:34 -05002364 fieldFullPath := fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i)
2365 c, ok := g.makeComments(fieldFullPath)
2366 if ok {
2367 c += "\n"
2368 }
2369 rf := simpleField{
2370 fieldCommon: fieldCommon{
2371 goName: fieldName,
2372 getterName: fieldGetterName,
2373 goType: typename,
2374 tags: tag,
2375 protoName: field.GetName(),
2376 fullPath: fieldFullPath,
2377 },
2378 protoTypeName: field.GetTypeName(),
2379 protoType: *field.Type,
2380 deprecated: fieldDeprecated,
2381 getterDef: dvalue,
2382 protoDef: field.GetDefaultValue(),
2383 comment: c,
2384 }
2385 var pf topLevelField = &rf
2386
2387 topLevelFields = append(topLevelFields, pf)
2388 g.RecordTypeUse(field.GetTypeName())
2389 }
2390
2391 mc := &msgCtx{
2392 goName: goTypeName,
2393 message: message,
2394 }
2395
2396 g.generateMessageStruct(mc, topLevelFields)
2397 g.P()
2398 g.generateCommonMethods(mc)
2399 g.P()
2400 g.generateDefaultConstants(mc, topLevelFields)
2401 g.P()
2402 g.generateGetters(mc, topLevelFields)
2403 g.P()
2404 g.generateSetters(mc, topLevelFields)
2405 g.P()
2406 g.generateOneofFuncs(mc, topLevelFields)
2407 g.P()
2408
William Kurkiandaa6bb22019-03-07 12:26:28 -05002409 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)
khenaidooac637102019-01-14 15:44:34 -05002414 }
2415 }
khenaidooac637102019-01-14 15:44:34 -05002416 }
2417
William Kurkiandaa6bb22019-03-07 12:26:28 -05002418 opts := message.Options
2419 ms := &messageSymbol{
2420 sym: goTypeName,
2421 hasExtensions: len(message.ExtensionRange) > 0,
2422 isMessageSet: opts != nil && opts.GetMessageSetWireFormat(),
2423 oneofTypes: oneofTypes,
2424 }
2425 g.file.addExport(message, ms)
2426
khenaidooac637102019-01-14 15:44:34 -05002427 for _, ext := range message.ext {
2428 g.generateExtension(ext)
2429 }
2430
2431 fullName := strings.Join(message.TypeName(), ".")
2432 if g.file.Package != nil {
2433 fullName = *g.file.Package + "." + fullName
2434 }
2435
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)
2441 }
2442
2443}
2444
2445type byTypeName []*descriptor.FieldDescriptorProto
2446
2447func (a byTypeName) Len() int { return len(a) }
2448func (a byTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
2449func (a byTypeName) Less(i, j int) bool { return *a[i].TypeName < *a[j].TypeName }
2450
2451// mapFieldKeys returns the keys of m in a consistent order.
2452func mapFieldKeys(m map[*descriptor.FieldDescriptorProto]string) []*descriptor.FieldDescriptorProto {
2453 keys := make([]*descriptor.FieldDescriptorProto, 0, len(m))
2454 for k := range m {
2455 keys = append(keys, k)
2456 }
2457 sort.Sort(byTypeName(keys))
2458 return keys
2459}
2460
2461var escapeChars = [256]byte{
2462 'a': '\a', 'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t', 'v': '\v', '\\': '\\', '"': '"', '\'': '\'', '?': '?',
2463}
2464
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.
2468func 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).
2472
2473 var out []byte
2474 for len(s) > 0 {
2475 // regular character, or too short to be valid escape
2476 if s[0] != '\\' || len(s) < 2 {
2477 out = append(out, s[0])
2478 s = s[1:]
2479 } else if c := escapeChars[s[1]]; c != 0 {
2480 // escape sequence
2481 out = append(out, c)
2482 s = s[2:]
2483 } else if s[1] == 'x' || s[1] == 'X' {
2484 // hex escape, e.g. "\x80
2485 if len(s) < 4 {
2486 // too short to be valid
2487 out = append(out, s[:2]...)
2488 s = s[2:]
2489 continue
2490 }
2491 v, err := strconv.ParseUint(s[2:4], 16, 8)
2492 if err != nil {
2493 out = append(out, s[:4]...)
2494 } else {
2495 out = append(out, byte(v))
2496 }
2497 s = s[4:]
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"))
2502 if n > 3 {
2503 n = 3
2504 }
2505 v, err := strconv.ParseUint(s[1:1+n], 8, 8)
2506 if err != nil {
2507 out = append(out, s[:1+n]...)
2508 } else {
2509 out = append(out, byte(v))
2510 }
2511 s = s[1+n:]
2512 } else {
2513 // bad escape, just propagate the slash as-is
2514 out = append(out, s[0])
2515 s = s[1:]
2516 }
2517 }
2518
2519 return string(out)
2520}
2521
2522func (g *Generator) generateExtension(ext *ExtensionDescriptor) {
2523 ccTypeName := ext.DescName()
2524
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)
2531 } else {
2532 extDesc = extObj.(*Descriptor)
2533 }
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
2541 g.RecordTypeUse(*n)
2542 }
2543
2544 typeName := ext.TypeName()
2545
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.
2549 //
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
khenaidooac637102019-01-14 15:44:34 -05002554 if extDesc.GetOptions().GetMessageSetWireFormat() && typeName[len(typeName)-1] == "message_set_extension" {
2555 typeName = typeName[:len(typeName)-1]
khenaidooac637102019-01-14 15:44:34 -05002556 }
2557
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
2563 }
2564
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(), `",`)
2572
2573 g.P("}")
2574 g.P()
2575
William Kurkiandaa6bb22019-03-07 12:26:28 -05002576 g.addInitf("%s.RegisterExtension(%s)", g.Pkg["proto"], ext.DescName())
khenaidooac637102019-01-14 15:44:34 -05002577
2578 g.file.addExport(ext, constOrVarSymbol{ccTypeName, "var", ""})
2579}
2580
2581func (g *Generator) generateInitFunction() {
khenaidooac637102019-01-14 15:44:34 -05002582 if len(g.init) == 0 {
2583 return
2584 }
2585 g.P("func init() {")
2586 for _, l := range g.init {
2587 g.P(l)
2588 }
2589 g.P("}")
2590 g.init = nil
2591}
2592
2593func (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
2598
2599 b, err := proto.Marshal(pb)
2600 if err != nil {
2601 g.Fail(err.Error())
2602 }
2603
2604 var buf bytes.Buffer
2605 w, _ := gzip.NewWriterLevel(&buf, gzip.BestCompression)
2606 w.Write(b)
2607 w.Close()
2608 b = buf.Bytes()
2609
2610 v := file.VarName()
2611 g.P()
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")
2615 for len(b) > 0 {
2616 n := 16
2617 if n > len(b) {
2618 n = len(b)
2619 }
2620
2621 s := ""
2622 for _, c := range b[:n] {
2623 s += fmt.Sprintf("0x%02x,", c)
2624 }
2625 g.P(s)
2626
2627 b = b[n:]
2628 }
2629 g.P("}")
2630}
2631
2632func (g *Generator) generateEnumRegistration(enum *EnumDescriptor) {
2633 // // We always print the full (proto-world) package name here.
2634 pkg := enum.File().GetPackage()
2635 if pkg != "" {
2636 pkg += "."
2637 }
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)
2643}
2644
khenaidooac637102019-01-14 15:44:34 -05002645// And now lots of helper functions.
2646
2647// Is c an ASCII lower-case letter?
2648func isASCIILower(c byte) bool {
2649 return 'a' <= c && c <= 'z'
2650}
2651
2652// Is c an ASCII digit?
2653func isASCIIDigit(c byte) bool {
2654 return '0' <= c && c <= '9'
2655}
2656
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.
2665func CamelCase(s string) string {
2666 if s == "" {
2667 return ""
2668 }
2669 t := make([]byte, 0, 32)
2670 i := 0
2671 if s[0] == '_' {
2672 // Need a capital letter; drop the '_'.
2673 t = append(t, 'X')
2674 i++
2675 }
2676 // Invariant: if the next letter is lower case, it must be converted
2677 // to upper case.
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++ {
2681 c := s[i]
2682 if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) {
2683 continue // Skip the underscore in s.
2684 }
2685 if isASCIIDigit(c) {
2686 t = append(t, c)
2687 continue
2688 }
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.
2693 }
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]) {
2697 i++
2698 t = append(t, s[i])
2699 }
2700 }
2701 return string(t)
2702}
2703
2704// CamelCaseSlice is like CamelCase, but the argument is a slice of strings to
2705// be joined with "_".
2706func CamelCaseSlice(elem []string) string { return CamelCase(strings.Join(elem, "_")) }
2707
2708// dottedSlice turns a sliced name into a dotted name.
2709func dottedSlice(elem []string) string { return strings.Join(elem, ".") }
2710
2711// Is this field optional?
2712func isOptional(field *descriptor.FieldDescriptorProto) bool {
2713 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_OPTIONAL
2714}
2715
2716// Is this field required?
2717func isRequired(field *descriptor.FieldDescriptorProto) bool {
2718 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REQUIRED
2719}
2720
2721// Is this field repeated?
2722func isRepeated(field *descriptor.FieldDescriptorProto) bool {
2723 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED
2724}
2725
2726// Is this field a scalar numeric type?
2727func isScalar(field *descriptor.FieldDescriptorProto) bool {
2728 if field.Type == nil {
2729 return false
2730 }
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:
2746 return true
2747 default:
2748 return false
2749 }
2750}
2751
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.
2755func badToUnderscore(r rune) rune {
2756 if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' {
2757 return r
2758 }
2759 return '_'
2760}
2761
2762// baseName returns the last path element of the name, with the last dotted suffix removed.
2763func baseName(name string) string {
2764 // First, find the last element
2765 if i := strings.LastIndex(name, "/"); i >= 0 {
2766 name = name[i+1:]
2767 }
2768 // Now drop the suffix
2769 if i := strings.LastIndex(name, "."); i >= 0 {
2770 name = name[0:i]
2771 }
2772 return name
2773}
2774
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
2780// are used.
2781//
2782// See descriptor.proto for more information about this.
2783const (
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
2795)
2796
2797var supportTypeAliases bool
2798
2799func init() {
2800 for _, tag := range build.Default.ReleaseTags {
2801 if tag == "go1.9" {
2802 supportTypeAliases = true
2803 return
2804 }
2805 }
2806}