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