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 = 3 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 g.addedImports = make(map[GoImportPath]bool) 486 return g 487} 488 489// Error reports a problem, including an error, and exits the program. 490func (g *Generator) Error(err error, msgs ...string) { 491 s := strings.Join(msgs, " ") + ":" + err.Error() 492 log.Print("protoc-gen-gogo: error:", s) 493 os.Exit(1) 494} 495 496// Fail reports a problem and exits the program. 497func (g *Generator) Fail(msgs ...string) { 498 s := strings.Join(msgs, " ") 499 log.Print("protoc-gen-gogo: error:", s) 500 os.Exit(1) 501} 502 503// CommandLineParameters breaks the comma-separated list of key=value pairs 504// in the parameter (a member of the request protobuf) into a key/value map. 505// It then sets file name mappings defined by those entries. 506func (g *Generator) CommandLineParameters(parameter string) { 507 g.Param = make(map[string]string) 508 for _, p := range strings.Split(parameter, ",") { 509 if i := strings.Index(p, "="); i < 0 { 510 g.Param[p] = "" 511 } else { 512 g.Param[p[0:i]] = p[i+1:] 513 } 514 } 515 516 g.ImportMap = make(map[string]string) 517 pluginList := "none" // Default list of plugin names to enable (empty means all). 518 for k, v := range g.Param { 519 switch k { 520 case "import_prefix": 521 g.ImportPrefix = v 522 case "import_path": 523 g.PackageImportPath = v 524 case "paths": 525 switch v { 526 case "import": 527 g.pathType = pathTypeImport 528 case "source_relative": 529 g.pathType = pathTypeSourceRelative 530 default: 531 g.Fail(fmt.Sprintf(`Unknown path type %q: want "import" or "source_relative".`, v)) 532 } 533 case "plugins": 534 pluginList = v 535 case "annotate_code": 536 if v == "true" { 537 g.annotateCode = true 538 } 539 default: 540 if len(k) > 0 && k[0] == 'M' { 541 g.ImportMap[k[1:]] = v 542 } 543 } 544 } 545 if pluginList == "" { 546 return 547 } 548 if pluginList == "none" { 549 pluginList = "" 550 } 551 gogoPluginNames := []string{"unmarshal", "unsafeunmarshaler", "union", "stringer", "size", "protosizer", "populate", "marshalto", "unsafemarshaler", "gostring", "face", "equal", "enumstringer", "embedcheck", "description", "defaultcheck", "oneofcheck", "compare"} 552 pluginList = strings.Join(append(gogoPluginNames, pluginList), "+") 553 if pluginList != "" { 554 // Amend the set of plugins. 555 enabled := make(map[string]bool) 556 for _, name := range strings.Split(pluginList, "+") { 557 enabled[name] = true 558 } 559 var nplugins pluginSlice 560 for _, p := range plugins { 561 if enabled[p.Name()] { 562 nplugins = append(nplugins, p) 563 } 564 } 565 sort.Sort(nplugins) 566 plugins = nplugins 567 } 568} 569 570// DefaultPackageName returns the package name printed for the object. 571// If its file is in a different package, it returns the package name we're using for this file, plus ".". 572// Otherwise it returns the empty string. 573func (g *Generator) DefaultPackageName(obj Object) string { 574 importPath := obj.GoImportPath() 575 if importPath == g.outputImportPath { 576 return "" 577 } 578 return string(g.GoPackageName(importPath)) + "." 579} 580 581// GoPackageName returns the name used for a package. 582func (g *Generator) GoPackageName(importPath GoImportPath) GoPackageName { 583 if name, ok := g.packageNames[importPath]; ok { 584 return name 585 } 586 name := cleanPackageName(baseName(string(importPath))) 587 for i, orig := 1, name; g.usedPackageNames[name] || isGoPredeclaredIdentifier[string(name)]; i++ { 588 name = orig + GoPackageName(strconv.Itoa(i)) 589 } 590 if g.packageNames == nil { 591 g.packageNames = make(map[GoImportPath]GoPackageName) 592 } 593 g.packageNames[importPath] = name 594 if g.usedPackageNames == nil { 595 g.usedPackageNames = make(map[GoPackageName]bool) 596 } 597 g.usedPackageNames[name] = true 598 return name 599} 600 601// AddImport adds a package to the generated file's import section. 602// It returns the name used for the package. 603func (g *Generator) AddImport(importPath GoImportPath) GoPackageName { 604 g.addedImports[importPath] = true 605 return g.GoPackageName(importPath) 606} 607 608var globalPackageNames = map[GoPackageName]bool{ 609 "fmt": true, 610 "math": true, 611 "proto": true, 612} 613 614// Create and remember a guaranteed unique package name. Pkg is the candidate name. 615// The FileDescriptor parameter is unused. 616func RegisterUniquePackageName(pkg string, f *FileDescriptor) string { 617 name := cleanPackageName(pkg) 618 for i, orig := 1, name; globalPackageNames[name]; i++ { 619 name = orig + GoPackageName(strconv.Itoa(i)) 620 } 621 globalPackageNames[name] = true 622 return string(name) 623} 624 625var isGoKeyword = map[string]bool{ 626 "break": true, 627 "case": true, 628 "chan": true, 629 "const": true, 630 "continue": true, 631 "default": true, 632 "else": true, 633 "defer": true, 634 "fallthrough": true, 635 "for": true, 636 "func": true, 637 "go": true, 638 "goto": true, 639 "if": true, 640 "import": true, 641 "interface": true, 642 "map": true, 643 "package": true, 644 "range": true, 645 "return": true, 646 "select": true, 647 "struct": true, 648 "switch": true, 649 "type": true, 650 "var": true, 651} 652 653var isGoPredeclaredIdentifier = map[string]bool{ 654 "append": true, 655 "bool": true, 656 "byte": true, 657 "cap": true, 658 "close": true, 659 "complex": true, 660 "complex128": true, 661 "complex64": true, 662 "copy": true, 663 "delete": true, 664 "error": true, 665 "false": true, 666 "float32": true, 667 "float64": true, 668 "imag": true, 669 "int": true, 670 "int16": true, 671 "int32": true, 672 "int64": true, 673 "int8": true, 674 "iota": true, 675 "len": true, 676 "make": true, 677 "new": true, 678 "nil": true, 679 "panic": true, 680 "print": true, 681 "println": true, 682 "real": true, 683 "recover": true, 684 "rune": true, 685 "string": true, 686 "true": true, 687 "uint": true, 688 "uint16": true, 689 "uint32": true, 690 "uint64": true, 691 "uint8": true, 692 "uintptr": true, 693} 694 695func cleanPackageName(name string) GoPackageName { 696 name = strings.Map(badToUnderscore, name) 697 // Identifier must not be keyword: insert _. 698 if isGoKeyword[name] { 699 name = "_" + name 700 } 701 // Identifier must not begin with digit: insert _. 702 if r, _ := utf8.DecodeRuneInString(name); unicode.IsDigit(r) { 703 name = "_" + name 704 } 705 return GoPackageName(name) 706} 707 708// defaultGoPackage returns the package name to use, 709// derived from the import path of the package we're building code for. 710func (g *Generator) defaultGoPackage() GoPackageName { 711 p := g.PackageImportPath 712 if i := strings.LastIndex(p, "/"); i >= 0 { 713 p = p[i+1:] 714 } 715 return cleanPackageName(p) 716} 717 718// SetPackageNames sets the package name for this run. 719// The package name must agree across all files being generated. 720// It also defines unique package names for all imported files. 721func (g *Generator) SetPackageNames() { 722 g.outputImportPath = g.genFiles[0].importPath 723 724 defaultPackageNames := make(map[GoImportPath]GoPackageName) 725 for _, f := range g.genFiles { 726 if _, p, ok := f.goPackageOption(); ok { 727 defaultPackageNames[f.importPath] = p 728 } 729 } 730 for _, f := range g.genFiles { 731 if _, p, ok := f.goPackageOption(); ok { 732 // Source file: option go_package = "quux/bar"; 733 f.packageName = p 734 } else if p, ok := defaultPackageNames[f.importPath]; ok { 735 // A go_package option in another file in the same package. 736 // 737 // This is a poor choice in general, since every source file should 738 // contain a go_package option. Supported mainly for historical 739 // compatibility. 740 f.packageName = p 741 } else if p := g.defaultGoPackage(); p != "" { 742 // Command-line: import_path=quux/bar. 743 // 744 // The import_path flag sets a package name for files which don't 745 // contain a go_package option. 746 f.packageName = p 747 } else if p := f.GetPackage(); p != "" { 748 // Source file: package quux.bar; 749 f.packageName = cleanPackageName(p) 750 } else { 751 // Source filename. 752 f.packageName = cleanPackageName(baseName(f.GetName())) 753 } 754 } 755 756 // Check that all files have a consistent package name and import path. 757 for _, f := range g.genFiles[1:] { 758 if a, b := g.genFiles[0].importPath, f.importPath; a != b { 759 g.Fail(fmt.Sprintf("inconsistent package import paths: %v, %v", a, b)) 760 } 761 if a, b := g.genFiles[0].packageName, f.packageName; a != b { 762 g.Fail(fmt.Sprintf("inconsistent package names: %v, %v", a, b)) 763 } 764 } 765 766 // Names of support packages. These never vary (if there are conflicts, 767 // we rename the conflicting package), so this could be removed someday. 768 g.Pkg = map[string]string{ 769 "fmt": "fmt", 770 "math": "math", 771 "proto": "proto", 772 "golang_proto": "golang_proto", 773 } 774} 775 776// WrapTypes walks the incoming data, wrapping DescriptorProtos, EnumDescriptorProtos 777// and FileDescriptorProtos into file-referenced objects within the Generator. 778// It also creates the list of files to generate and so should be called before GenerateAllFiles. 779func (g *Generator) WrapTypes() { 780 g.allFiles = make([]*FileDescriptor, 0, len(g.Request.ProtoFile)) 781 g.allFilesByName = make(map[string]*FileDescriptor, len(g.allFiles)) 782 genFileNames := make(map[string]bool) 783 for _, n := range g.Request.FileToGenerate { 784 genFileNames[n] = true 785 } 786 for _, f := range g.Request.ProtoFile { 787 fd := &FileDescriptor{ 788 FileDescriptorProto: f, 789 exported: make(map[Object][]symbol), 790 proto3: fileIsProto3(f), 791 } 792 // The import path may be set in a number of ways. 793 if substitution, ok := g.ImportMap[f.GetName()]; ok { 794 // Command-line: M=foo.proto=quux/bar. 795 // 796 // Explicit mapping of source file to import path. 797 fd.importPath = GoImportPath(substitution) 798 } else if genFileNames[f.GetName()] && g.PackageImportPath != "" { 799 // Command-line: import_path=quux/bar. 800 // 801 // The import_path flag sets the import path for every file that 802 // we generate code for. 803 fd.importPath = GoImportPath(g.PackageImportPath) 804 } else if p, _, _ := fd.goPackageOption(); p != "" { 805 // Source file: option go_package = "quux/bar"; 806 // 807 // The go_package option sets the import path. Most users should use this. 808 fd.importPath = p 809 } else { 810 // Source filename. 811 // 812 // Last resort when nothing else is available. 813 fd.importPath = GoImportPath(path.Dir(f.GetName())) 814 } 815 // We must wrap the descriptors before we wrap the enums 816 fd.desc = wrapDescriptors(fd) 817 g.buildNestedDescriptors(fd.desc) 818 fd.enum = wrapEnumDescriptors(fd, fd.desc) 819 g.buildNestedEnums(fd.desc, fd.enum) 820 fd.ext = wrapExtensions(fd) 821 extractComments(fd) 822 g.allFiles = append(g.allFiles, fd) 823 g.allFilesByName[f.GetName()] = fd 824 } 825 for _, fd := range g.allFiles { 826 fd.imp = wrapImported(fd, g) 827 } 828 829 g.genFiles = make([]*FileDescriptor, 0, len(g.Request.FileToGenerate)) 830 for _, fileName := range g.Request.FileToGenerate { 831 fd := g.allFilesByName[fileName] 832 if fd == nil { 833 g.Fail("could not find file named", fileName) 834 } 835 g.genFiles = append(g.genFiles, fd) 836 } 837} 838 839// Scan the descriptors in this file. For each one, build the slice of nested descriptors 840func (g *Generator) buildNestedDescriptors(descs []*Descriptor) { 841 for _, desc := range descs { 842 if len(desc.NestedType) != 0 { 843 for _, nest := range descs { 844 if nest.parent == desc { 845 desc.nested = append(desc.nested, nest) 846 } 847 } 848 if len(desc.nested) != len(desc.NestedType) { 849 g.Fail("internal error: nesting failure for", desc.GetName()) 850 } 851 } 852 } 853} 854 855func (g *Generator) buildNestedEnums(descs []*Descriptor, enums []*EnumDescriptor) { 856 for _, desc := range descs { 857 if len(desc.EnumType) != 0 { 858 for _, enum := range enums { 859 if enum.parent == desc { 860 desc.enums = append(desc.enums, enum) 861 } 862 } 863 if len(desc.enums) != len(desc.EnumType) { 864 g.Fail("internal error: enum nesting failure for", desc.GetName()) 865 } 866 } 867 } 868} 869 870// Construct the Descriptor 871func newDescriptor(desc *descriptor.DescriptorProto, parent *Descriptor, file *FileDescriptor, index int) *Descriptor { 872 d := &Descriptor{ 873 common: common{file}, 874 DescriptorProto: desc, 875 parent: parent, 876 index: index, 877 } 878 if parent == nil { 879 d.path = fmt.Sprintf("%d,%d", messagePath, index) 880 } else { 881 d.path = fmt.Sprintf("%s,%d,%d", parent.path, messageMessagePath, index) 882 } 883 884 // The only way to distinguish a group from a message is whether 885 // the containing message has a TYPE_GROUP field that matches. 886 if parent != nil { 887 parts := d.TypeName() 888 if file.Package != nil { 889 parts = append([]string{*file.Package}, parts...) 890 } 891 exp := "." + strings.Join(parts, ".") 892 for _, field := range parent.Field { 893 if field.GetType() == descriptor.FieldDescriptorProto_TYPE_GROUP && field.GetTypeName() == exp { 894 d.group = true 895 break 896 } 897 } 898 } 899 900 for _, field := range desc.Extension { 901 d.ext = append(d.ext, &ExtensionDescriptor{common{file}, field, d}) 902 } 903 904 return d 905} 906 907// Return a slice of all the Descriptors defined within this file 908func wrapDescriptors(file *FileDescriptor) []*Descriptor { 909 sl := make([]*Descriptor, 0, len(file.MessageType)+10) 910 for i, desc := range file.MessageType { 911 sl = wrapThisDescriptor(sl, desc, nil, file, i) 912 } 913 return sl 914} 915 916// Wrap this Descriptor, recursively 917func wrapThisDescriptor(sl []*Descriptor, desc *descriptor.DescriptorProto, parent *Descriptor, file *FileDescriptor, index int) []*Descriptor { 918 sl = append(sl, newDescriptor(desc, parent, file, index)) 919 me := sl[len(sl)-1] 920 for i, nested := range desc.NestedType { 921 sl = wrapThisDescriptor(sl, nested, me, file, i) 922 } 923 return sl 924} 925 926// Construct the EnumDescriptor 927func newEnumDescriptor(desc *descriptor.EnumDescriptorProto, parent *Descriptor, file *FileDescriptor, index int) *EnumDescriptor { 928 ed := &EnumDescriptor{ 929 common: common{file}, 930 EnumDescriptorProto: desc, 931 parent: parent, 932 index: index, 933 } 934 if parent == nil { 935 ed.path = fmt.Sprintf("%d,%d", enumPath, index) 936 } else { 937 ed.path = fmt.Sprintf("%s,%d,%d", parent.path, messageEnumPath, index) 938 } 939 return ed 940} 941 942// Return a slice of all the EnumDescriptors defined within this file 943func wrapEnumDescriptors(file *FileDescriptor, descs []*Descriptor) []*EnumDescriptor { 944 sl := make([]*EnumDescriptor, 0, len(file.EnumType)+10) 945 // Top-level enums. 946 for i, enum := range file.EnumType { 947 sl = append(sl, newEnumDescriptor(enum, nil, file, i)) 948 } 949 // Enums within messages. Enums within embedded messages appear in the outer-most message. 950 for _, nested := range descs { 951 for i, enum := range nested.EnumType { 952 sl = append(sl, newEnumDescriptor(enum, nested, file, i)) 953 } 954 } 955 return sl 956} 957 958// Return a slice of all the top-level ExtensionDescriptors defined within this file. 959func wrapExtensions(file *FileDescriptor) []*ExtensionDescriptor { 960 var sl []*ExtensionDescriptor 961 for _, field := range file.Extension { 962 sl = append(sl, &ExtensionDescriptor{common{file}, field, nil}) 963 } 964 return sl 965} 966 967// Return a slice of all the types that are publicly imported into this file. 968func wrapImported(file *FileDescriptor, g *Generator) (sl []*ImportedDescriptor) { 969 for _, index := range file.PublicDependency { 970 df := g.fileByName(file.Dependency[index]) 971 for _, d := range df.desc { 972 if d.GetOptions().GetMapEntry() { 973 continue 974 } 975 sl = append(sl, &ImportedDescriptor{common{file}, d}) 976 } 977 for _, e := range df.enum { 978 sl = append(sl, &ImportedDescriptor{common{file}, e}) 979 } 980 for _, ext := range df.ext { 981 sl = append(sl, &ImportedDescriptor{common{file}, ext}) 982 } 983 } 984 return 985} 986 987func extractComments(file *FileDescriptor) { 988 file.comments = make(map[string]*descriptor.SourceCodeInfo_Location) 989 for _, loc := range file.GetSourceCodeInfo().GetLocation() { 990 if loc.LeadingComments == nil { 991 continue 992 } 993 var p []string 994 for _, n := range loc.Path { 995 p = append(p, strconv.Itoa(int(n))) 996 } 997 file.comments[strings.Join(p, ",")] = loc 998 } 999} 1000 1001// BuildTypeNameMap builds the map from fully qualified type names to objects. 1002// The key names for the map come from the input data, which puts a period at the beginning. 1003// It should be called after SetPackageNames and before GenerateAllFiles. 1004func (g *Generator) BuildTypeNameMap() { 1005 g.typeNameToObject = make(map[string]Object) 1006 for _, f := range g.allFiles { 1007 // The names in this loop are defined by the proto world, not us, so the 1008 // package name may be empty. If so, the dotted package name of X will 1009 // be ".X"; otherwise it will be ".pkg.X". 1010 dottedPkg := "." + f.GetPackage() 1011 if dottedPkg != "." { 1012 dottedPkg += "." 1013 } 1014 for _, enum := range f.enum { 1015 name := dottedPkg + dottedSlice(enum.TypeName()) 1016 g.typeNameToObject[name] = enum 1017 } 1018 for _, desc := range f.desc { 1019 name := dottedPkg + dottedSlice(desc.TypeName()) 1020 g.typeNameToObject[name] = desc 1021 } 1022 } 1023} 1024 1025// ObjectNamed, given a fully-qualified input type name as it appears in the input data, 1026// returns the descriptor for the message or enum with that name. 1027func (g *Generator) ObjectNamed(typeName string) Object { 1028 o, ok := g.typeNameToObject[typeName] 1029 if !ok { 1030 g.Fail("can't find object with type", typeName) 1031 } 1032 return o 1033} 1034 1035// AnnotatedAtoms is a list of atoms (as consumed by P) that records the file name and proto AST path from which they originated. 1036type AnnotatedAtoms struct { 1037 source string 1038 path string 1039 atoms []interface{} 1040} 1041 1042// Annotate records the file name and proto AST path of a list of atoms 1043// so that a later call to P can emit a link from each atom to its origin. 1044func Annotate(file *FileDescriptor, path string, atoms ...interface{}) *AnnotatedAtoms { 1045 return &AnnotatedAtoms{source: *file.Name, path: path, atoms: atoms} 1046} 1047 1048// printAtom prints the (atomic, non-annotation) argument to the generated output. 1049func (g *Generator) printAtom(v interface{}) { 1050 switch v := v.(type) { 1051 case string: 1052 g.WriteString(v) 1053 case *string: 1054 g.WriteString(*v) 1055 case bool: 1056 fmt.Fprint(g, v) 1057 case *bool: 1058 fmt.Fprint(g, *v) 1059 case int: 1060 fmt.Fprint(g, v) 1061 case *int32: 1062 fmt.Fprint(g, *v) 1063 case *int64: 1064 fmt.Fprint(g, *v) 1065 case float64: 1066 fmt.Fprint(g, v) 1067 case *float64: 1068 fmt.Fprint(g, *v) 1069 case GoPackageName: 1070 g.WriteString(string(v)) 1071 case GoImportPath: 1072 g.WriteString(strconv.Quote(string(v))) 1073 default: 1074 g.Fail(fmt.Sprintf("unknown type in printer: %T", v)) 1075 } 1076} 1077 1078// P prints the arguments to the generated output. It handles strings and int32s, plus 1079// handling indirections because they may be *string, etc. Any inputs of type AnnotatedAtoms may emit 1080// annotations in a .meta file in addition to outputting the atoms themselves (if g.annotateCode 1081// is true). 1082func (g *Generator) P(str ...interface{}) { 1083 if !g.writeOutput { 1084 return 1085 } 1086 g.WriteString(g.indent) 1087 for _, v := range str { 1088 switch v := v.(type) { 1089 case *AnnotatedAtoms: 1090 begin := int32(g.Len()) 1091 for _, v := range v.atoms { 1092 g.printAtom(v) 1093 } 1094 if g.annotateCode { 1095 end := int32(g.Len()) 1096 var path []int32 1097 for _, token := range strings.Split(v.path, ",") { 1098 val, err := strconv.ParseInt(token, 10, 32) 1099 if err != nil { 1100 g.Fail("could not parse proto AST path: ", err.Error()) 1101 } 1102 path = append(path, int32(val)) 1103 } 1104 g.annotations = append(g.annotations, &descriptor.GeneratedCodeInfo_Annotation{ 1105 Path: path, 1106 SourceFile: &v.source, 1107 Begin: &begin, 1108 End: &end, 1109 }) 1110 } 1111 default: 1112 g.printAtom(v) 1113 } 1114 } 1115 g.WriteByte('\n') 1116} 1117 1118// addInitf stores the given statement to be printed inside the file's init function. 1119// The statement is given as a format specifier and arguments. 1120func (g *Generator) addInitf(stmt string, a ...interface{}) { 1121 g.init = append(g.init, fmt.Sprintf(stmt, a...)) 1122} 1123 1124func (g *Generator) PrintImport(alias GoPackageName, pkg GoImportPath) { 1125 statement := string(alias) + " " + strconv.Quote(string(pkg)) 1126 if g.writtenImports[statement] { 1127 return 1128 } 1129 g.P(statement) 1130 g.writtenImports[statement] = true 1131} 1132 1133// In Indents the output one tab stop. 1134func (g *Generator) In() { g.indent += "\t" } 1135 1136// Out unindents the output one tab stop. 1137func (g *Generator) Out() { 1138 if len(g.indent) > 0 { 1139 g.indent = g.indent[1:] 1140 } 1141} 1142 1143// GenerateAllFiles generates the output for all the files we're outputting. 1144func (g *Generator) GenerateAllFiles() { 1145 // Initialize the plugins 1146 for _, p := range plugins { 1147 p.Init(g) 1148 } 1149 // Generate the output. The generator runs for every file, even the files 1150 // that we don't generate output for, so that we can collate the full list 1151 // of exported symbols to support public imports. 1152 genFileMap := make(map[*FileDescriptor]bool, len(g.genFiles)) 1153 for _, file := range g.genFiles { 1154 genFileMap[file] = true 1155 } 1156 for _, file := range g.allFiles { 1157 g.Reset() 1158 g.annotations = nil 1159 g.writeOutput = genFileMap[file] 1160 g.generate(file) 1161 if !g.writeOutput { 1162 continue 1163 } 1164 fname := file.goFileName(g.pathType) 1165 g.Response.File = append(g.Response.File, &plugin.CodeGeneratorResponse_File{ 1166 Name: proto.String(fname), 1167 Content: proto.String(g.String()), 1168 }) 1169 if g.annotateCode { 1170 // Store the generated code annotations in text, as the protoc plugin protocol requires that 1171 // strings contain valid UTF-8. 1172 g.Response.File = append(g.Response.File, &plugin.CodeGeneratorResponse_File{ 1173 Name: proto.String(file.goFileName(g.pathType) + ".meta"), 1174 Content: proto.String(proto.CompactTextString(&descriptor.GeneratedCodeInfo{Annotation: g.annotations})), 1175 }) 1176 } 1177 } 1178} 1179 1180// Run all the plugins associated with the file. 1181func (g *Generator) runPlugins(file *FileDescriptor) { 1182 for _, p := range plugins { 1183 p.Generate(file) 1184 } 1185} 1186 1187// Fill the response protocol buffer with the generated output for all the files we're 1188// supposed to generate. 1189func (g *Generator) generate(file *FileDescriptor) { 1190 g.customImports = make([]string, 0) 1191 g.file = file 1192 g.usedPackages = make(map[GoImportPath]bool) 1193 g.packageNames = make(map[GoImportPath]GoPackageName) 1194 g.usedPackageNames = make(map[GoPackageName]bool) 1195 g.addedImports = make(map[GoImportPath]bool) 1196 for name := range globalPackageNames { 1197 g.usedPackageNames[name] = true 1198 } 1199 1200 g.P("// This is a compile-time assertion to ensure that this generated file") 1201 g.P("// is compatible with the proto package it is being compiled against.") 1202 g.P("// A compilation error at this line likely means your copy of the") 1203 g.P("// proto package needs to be updated.") 1204 if gogoproto.ImportsGoGoProto(file.FileDescriptorProto) { 1205 g.P("const _ = ", g.Pkg["proto"], ".GoGoProtoPackageIsVersion", generatedCodeVersion, " // please upgrade the proto package") 1206 } else { 1207 g.P("const _ = ", g.Pkg["proto"], ".ProtoPackageIsVersion", generatedCodeVersion, " // please upgrade the proto package") 1208 } 1209 g.P() 1210 // Reset on each file 1211 g.writtenImports = make(map[string]bool) 1212 for _, td := range g.file.imp { 1213 g.generateImported(td) 1214 } 1215 for _, enum := range g.file.enum { 1216 g.generateEnum(enum) 1217 } 1218 for _, desc := range g.file.desc { 1219 // Don't generate virtual messages for maps. 1220 if desc.GetOptions().GetMapEntry() { 1221 continue 1222 } 1223 g.generateMessage(desc) 1224 } 1225 for _, ext := range g.file.ext { 1226 g.generateExtension(ext) 1227 } 1228 g.generateInitFunction() 1229 g.generateFileDescriptor(file) 1230 1231 // Run the plugins before the imports so we know which imports are necessary. 1232 g.runPlugins(file) 1233 1234 // Generate header and imports last, though they appear first in the output. 1235 rem := g.Buffer 1236 remAnno := g.annotations 1237 g.Buffer = new(bytes.Buffer) 1238 g.annotations = nil 1239 g.generateHeader() 1240 g.generateImports() 1241 if !g.writeOutput { 1242 return 1243 } 1244 // Adjust the offsets for annotations displaced by the header and imports. 1245 for _, anno := range remAnno { 1246 *anno.Begin += int32(g.Len()) 1247 *anno.End += int32(g.Len()) 1248 g.annotations = append(g.annotations, anno) 1249 } 1250 g.Write(rem.Bytes()) 1251 1252 // Reformat generated code and patch annotation locations. 1253 fset := token.NewFileSet() 1254 original := g.Bytes() 1255 if g.annotateCode { 1256 // make a copy independent of g; we'll need it after Reset. 1257 original = append([]byte(nil), original...) 1258 } 1259 fileAST, err := parser.ParseFile(fset, "", original, parser.ParseComments) 1260 if err != nil { 1261 // Print out the bad code with line numbers. 1262 // This should never happen in practice, but it can while changing generated code, 1263 // so consider this a debugging aid. 1264 var src bytes.Buffer 1265 s := bufio.NewScanner(bytes.NewReader(original)) 1266 for line := 1; s.Scan(); line++ { 1267 fmt.Fprintf(&src, "%5d\t%s\n", line, s.Bytes()) 1268 } 1269 if serr := s.Err(); serr != nil { 1270 g.Fail("bad Go source code was generated:", err.Error(), "\n"+string(original)) 1271 } else { 1272 g.Fail("bad Go source code was generated:", err.Error(), "\n"+src.String()) 1273 } 1274 } 1275 ast.SortImports(fset, fileAST) 1276 g.Reset() 1277 err = (&printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}).Fprint(g, fset, fileAST) 1278 if err != nil { 1279 g.Fail("generated Go source code could not be reformatted:", err.Error()) 1280 } 1281 if g.annotateCode { 1282 m, err := remap.Compute(original, g.Bytes()) 1283 if err != nil { 1284 g.Fail("formatted generated Go source code could not be mapped back to the original code:", err.Error()) 1285 } 1286 for _, anno := range g.annotations { 1287 new, ok := m.Find(int(*anno.Begin), int(*anno.End)) 1288 if !ok { 1289 g.Fail("span in formatted generated Go source code could not be mapped back to the original code") 1290 } 1291 *anno.Begin = int32(new.Pos) 1292 *anno.End = int32(new.End) 1293 } 1294 } 1295} 1296 1297// Generate the header, including package definition 1298func (g *Generator) generateHeader() { 1299 g.P("// Code generated by protoc-gen-gogo. DO NOT EDIT.") 1300 if g.file.GetOptions().GetDeprecated() { 1301 g.P("// ", *g.file.Name, " is a deprecated file.") 1302 } else { 1303 g.P("// source: ", *g.file.Name) 1304 } 1305 g.P() 1306 g.PrintComments(strconv.Itoa(packagePath)) 1307 g.P() 1308 g.P("package ", g.file.packageName) 1309 g.P() 1310} 1311 1312// deprecationComment is the standard comment added to deprecated 1313// messages, fields, enums, and enum values. 1314var deprecationComment = "// Deprecated: Do not use." 1315 1316// PrintComments prints any comments from the source .proto file. 1317// The path is a comma-separated list of integers. 1318// It returns an indication of whether any comments were printed. 1319// See descriptor.proto for its format. 1320func (g *Generator) PrintComments(path string) bool { 1321 if !g.writeOutput { 1322 return false 1323 } 1324 if c, ok := g.makeComments(path); ok { 1325 g.P(c) 1326 return true 1327 } 1328 return false 1329} 1330 1331// makeComments generates the comment string for the field, no "\n" at the end 1332func (g *Generator) makeComments(path string) (string, bool) { 1333 loc, ok := g.file.comments[path] 1334 if !ok { 1335 return "", false 1336 } 1337 w := new(bytes.Buffer) 1338 nl := "" 1339 for _, line := range strings.Split(strings.TrimSuffix(loc.GetLeadingComments(), "\n"), "\n") { 1340 fmt.Fprintf(w, "%s//%s", nl, line) 1341 nl = "\n" 1342 } 1343 return w.String(), true 1344} 1345 1346// Comments returns any comments from the source .proto file and empty string if comments not found. 1347// The path is a comma-separated list of intergers. 1348// See descriptor.proto for its format. 1349func (g *Generator) Comments(path string) string { 1350 loc, ok := g.file.comments[path] 1351 if !ok { 1352 return "" 1353 } 1354 text := strings.TrimSuffix(loc.GetLeadingComments(), "\n") 1355 return text 1356} 1357 1358func (g *Generator) fileByName(filename string) *FileDescriptor { 1359 return g.allFilesByName[filename] 1360} 1361 1362// weak returns whether the ith import of the current file is a weak import. 1363func (g *Generator) weak(i int32) bool { 1364 for _, j := range g.file.WeakDependency { 1365 if j == i { 1366 return true 1367 } 1368 } 1369 return false 1370} 1371 1372// Generate the imports 1373func (g *Generator) generateImports() { 1374 imports := make(map[GoImportPath]GoPackageName) 1375 for i, s := range g.file.Dependency { 1376 fd := g.fileByName(s) 1377 importPath := fd.importPath 1378 // Do not import our own package. 1379 if importPath == g.file.importPath { 1380 continue 1381 } 1382 // Do not import weak imports. 1383 if g.weak(int32(i)) { 1384 continue 1385 } 1386 // Do not import a package twice. 1387 if _, ok := imports[importPath]; ok { 1388 continue 1389 } 1390 // We need to import all the dependencies, even if we don't reference them, 1391 // because other code and tools depend on having the full transitive closure 1392 // of protocol buffer types in the binary. 1393 packageName := g.GoPackageName(importPath) 1394 if _, ok := g.usedPackages[importPath]; !ok { 1395 packageName = "_" 1396 } 1397 imports[importPath] = packageName 1398 } 1399 for importPath := range g.addedImports { 1400 imports[importPath] = g.GoPackageName(importPath) 1401 } 1402 // We almost always need a proto import. Rather than computing when we 1403 // do, which is tricky when there's a plugin, just import it and 1404 // reference it later. The same argument applies to the fmt and math packages. 1405 g.P("import (") 1406 g.PrintImport(GoPackageName(g.Pkg["fmt"]), "fmt") 1407 g.PrintImport(GoPackageName(g.Pkg["math"]), "math") 1408 if gogoproto.ImportsGoGoProto(g.file.FileDescriptorProto) { 1409 g.PrintImport(GoPackageName(g.Pkg["proto"]), GoImportPath(g.ImportPrefix)+GoImportPath("github.com/gogo/protobuf/proto")) 1410 if gogoproto.RegistersGolangProto(g.file.FileDescriptorProto) { 1411 g.PrintImport(GoPackageName(g.Pkg["golang_proto"]), GoImportPath(g.ImportPrefix)+GoImportPath("github.com/golang/protobuf/proto")) 1412 } 1413 } else { 1414 g.PrintImport(GoPackageName(g.Pkg["proto"]), GoImportPath(g.ImportPrefix)+GoImportPath("github.com/golang/protobuf/proto")) 1415 } 1416 for importPath, packageName := range imports { 1417 g.P(packageName, " ", GoImportPath(g.ImportPrefix)+importPath) 1418 } 1419 // Custom gogo imports 1420 for _, s := range g.customImports { 1421 s1 := strings.Map(badToUnderscore, s) 1422 g.PrintImport(GoPackageName(s1), GoImportPath(s)) 1423 } 1424 // gogo plugin imports 1425 // TODO: may need to worry about uniqueness across plugins and could change this 1426 // to use the `addedImports` technique 1427 for _, p := range plugins { 1428 p.GenerateImports(g.file) 1429 } 1430 g.P(")") 1431 1432 g.P("// Reference imports to suppress errors if they are not otherwise used.") 1433 g.P("var _ = ", g.Pkg["proto"], ".Marshal") 1434 if gogoproto.ImportsGoGoProto(g.file.FileDescriptorProto) && gogoproto.RegistersGolangProto(g.file.FileDescriptorProto) { 1435 g.P("var _ = ", g.Pkg["golang_proto"], ".Marshal") 1436 } 1437 g.P("var _ = ", g.Pkg["fmt"], ".Errorf") 1438 g.P("var _ = ", g.Pkg["math"], ".Inf") 1439 for _, cimport := range g.customImports { 1440 if cimport == "time" { 1441 g.P("var _ = time.Kitchen") 1442 break 1443 } 1444 } 1445 g.P() 1446} 1447 1448func (g *Generator) generateImported(id *ImportedDescriptor) { 1449 df := id.o.File() 1450 filename := *df.Name 1451 if df.importPath == g.file.importPath { 1452 // Don't generate type aliases for files in the same Go package as this one. 1453 return 1454 } 1455 if !supportTypeAliases { 1456 g.Fail(fmt.Sprintf("%s: public imports require at least go1.9", filename)) 1457 } 1458 g.usedPackages[df.importPath] = true 1459 1460 for _, sym := range df.exported[id.o] { 1461 sym.GenerateAlias(g, filename, g.GoPackageName(df.importPath)) 1462 } 1463 g.P() 1464} 1465 1466// Generate the enum definitions for this EnumDescriptor. 1467func (g *Generator) generateEnum(enum *EnumDescriptor) { 1468 // The full type name 1469 typeName := enum.alias() 1470 // The full type name, CamelCased. 1471 ccTypeName := CamelCaseSlice(typeName) 1472 ccPrefix := enum.prefix() 1473 1474 deprecatedEnum := "" 1475 if enum.GetOptions().GetDeprecated() { 1476 deprecatedEnum = deprecationComment 1477 } 1478 1479 g.PrintComments(enum.path) 1480 if !gogoproto.EnabledGoEnumPrefix(enum.file.FileDescriptorProto, enum.EnumDescriptorProto) { 1481 ccPrefix = "" 1482 } 1483 1484 if gogoproto.HasEnumDecl(enum.file.FileDescriptorProto, enum.EnumDescriptorProto) { 1485 g.P("type ", Annotate(enum.file, enum.path, ccTypeName), " int32", deprecatedEnum) 1486 g.file.addExport(enum, enumSymbol{ccTypeName, enum.proto3()}) 1487 g.P("const (") 1488 g.In() 1489 for i, e := range enum.Value { 1490 etorPath := fmt.Sprintf("%s,%d,%d", enum.path, enumValuePath, i) 1491 g.PrintComments(etorPath) 1492 1493 deprecatedValue := "" 1494 if e.GetOptions().GetDeprecated() { 1495 deprecatedValue = deprecationComment 1496 } 1497 name := *e.Name 1498 if gogoproto.IsEnumValueCustomName(e) { 1499 name = gogoproto.GetEnumValueCustomName(e) 1500 } 1501 name = ccPrefix + name 1502 1503 g.P(Annotate(enum.file, etorPath, name), " ", ccTypeName, " = ", e.Number, " ", deprecatedValue) 1504 g.file.addExport(enum, constOrVarSymbol{name, "const", ccTypeName}) 1505 } 1506 g.Out() 1507 g.P(")") 1508 } 1509 g.P() 1510 g.P("var ", ccTypeName, "_name = map[int32]string{") 1511 g.In() 1512 generated := make(map[int32]bool) // avoid duplicate values 1513 for _, e := range enum.Value { 1514 duplicate := "" 1515 if _, present := generated[*e.Number]; present { 1516 duplicate = "// Duplicate value: " 1517 } 1518 g.P(duplicate, e.Number, ": ", strconv.Quote(*e.Name), ",") 1519 generated[*e.Number] = true 1520 } 1521 g.Out() 1522 g.P("}") 1523 g.P() 1524 g.P("var ", ccTypeName, "_value = map[string]int32{") 1525 g.In() 1526 for _, e := range enum.Value { 1527 g.P(strconv.Quote(*e.Name), ": ", e.Number, ",") 1528 } 1529 g.Out() 1530 g.P("}") 1531 g.P() 1532 1533 if !enum.proto3() { 1534 g.P("func (x ", ccTypeName, ") Enum() *", ccTypeName, " {") 1535 g.In() 1536 g.P("p := new(", ccTypeName, ")") 1537 g.P("*p = x") 1538 g.P("return p") 1539 g.Out() 1540 g.P("}") 1541 g.P() 1542 } 1543 1544 if gogoproto.IsGoEnumStringer(g.file.FileDescriptorProto, enum.EnumDescriptorProto) { 1545 g.P("func (x ", ccTypeName, ") String() string {") 1546 g.In() 1547 g.P("return ", g.Pkg["proto"], ".EnumName(", ccTypeName, "_name, int32(x))") 1548 g.Out() 1549 g.P("}") 1550 g.P() 1551 } 1552 1553 if !enum.proto3() && !gogoproto.IsGoEnumStringer(g.file.FileDescriptorProto, enum.EnumDescriptorProto) { 1554 g.P("func (x ", ccTypeName, ") MarshalJSON() ([]byte, error) {") 1555 g.In() 1556 g.P("return ", g.Pkg["proto"], ".MarshalJSONEnum(", ccTypeName, "_name, int32(x))") 1557 g.Out() 1558 g.P("}") 1559 g.P() 1560 } 1561 if !enum.proto3() { 1562 g.P("func (x *", ccTypeName, ") UnmarshalJSON(data []byte) error {") 1563 g.In() 1564 g.P("value, err := ", g.Pkg["proto"], ".UnmarshalJSONEnum(", ccTypeName, `_value, data, "`, ccTypeName, `")`) 1565 g.P("if err != nil {") 1566 g.In() 1567 g.P("return err") 1568 g.Out() 1569 g.P("}") 1570 g.P("*x = ", ccTypeName, "(value)") 1571 g.P("return nil") 1572 g.Out() 1573 g.P("}") 1574 g.P() 1575 } 1576 1577 var indexes []string 1578 for m := enum.parent; m != nil; m = m.parent { 1579 // XXX: skip groups? 1580 indexes = append([]string{strconv.Itoa(m.index)}, indexes...) 1581 } 1582 indexes = append(indexes, strconv.Itoa(enum.index)) 1583 g.P("func (", ccTypeName, ") EnumDescriptor() ([]byte, []int) {") 1584 g.In() 1585 g.P("return ", g.file.VarName(), ", []int{", strings.Join(indexes, ", "), "}") 1586 g.Out() 1587 g.P("}") 1588 g.P() 1589 if enum.file.GetPackage() == "google.protobuf" && enum.GetName() == "NullValue" { 1590 g.P("func (", ccTypeName, `) XXX_WellKnownType() string { return "`, enum.GetName(), `" }`) 1591 g.P() 1592 } 1593 1594 g.generateEnumRegistration(enum) 1595} 1596 1597// The tag is a string like "varint,2,opt,name=fieldname,def=7" that 1598// identifies details of the field for the protocol buffer marshaling and unmarshaling 1599// code. The fields are: 1600// wire encoding 1601// protocol tag number 1602// opt,req,rep for optional, required, or repeated 1603// packed whether the encoding is "packed" (optional; repeated primitives only) 1604// name= the original declared name 1605// enum= the name of the enum type if it is an enum-typed field. 1606// proto3 if this field is in a proto3 message 1607// def= string representation of the default value, if any. 1608// The default value must be in a representation that can be used at run-time 1609// to generate the default value. Thus bools become 0 and 1, for instance. 1610func (g *Generator) goTag(message *Descriptor, field *descriptor.FieldDescriptorProto, wiretype string) string { 1611 optrepreq := "" 1612 switch { 1613 case isOptional(field): 1614 optrepreq = "opt" 1615 case isRequired(field): 1616 optrepreq = "req" 1617 case isRepeated(field): 1618 optrepreq = "rep" 1619 } 1620 var defaultValue string 1621 if dv := field.DefaultValue; dv != nil { // set means an explicit default 1622 defaultValue = *dv 1623 // Some types need tweaking. 1624 switch *field.Type { 1625 case descriptor.FieldDescriptorProto_TYPE_BOOL: 1626 if defaultValue == "true" { 1627 defaultValue = "1" 1628 } else { 1629 defaultValue = "0" 1630 } 1631 case descriptor.FieldDescriptorProto_TYPE_STRING, 1632 descriptor.FieldDescriptorProto_TYPE_BYTES: 1633 // Nothing to do. Quoting is done for the whole tag. 1634 case descriptor.FieldDescriptorProto_TYPE_ENUM: 1635 // For enums we need to provide the integer constant. 1636 obj := g.ObjectNamed(field.GetTypeName()) 1637 if id, ok := obj.(*ImportedDescriptor); ok { 1638 // It is an enum that was publicly imported. 1639 // We need the underlying type. 1640 obj = id.o 1641 } 1642 enum, ok := obj.(*EnumDescriptor) 1643 if !ok { 1644 log.Printf("obj is a %T", obj) 1645 if id, ok := obj.(*ImportedDescriptor); ok { 1646 log.Printf("id.o is a %T", id.o) 1647 } 1648 g.Fail("unknown enum type", CamelCaseSlice(obj.TypeName())) 1649 } 1650 defaultValue = enum.integerValueAsString(defaultValue) 1651 case descriptor.FieldDescriptorProto_TYPE_FLOAT: 1652 if def := defaultValue; def != "inf" && def != "-inf" && def != "nan" { 1653 if f, err := strconv.ParseFloat(defaultValue, 32); err == nil { 1654 defaultValue = fmt.Sprint(float32(f)) 1655 } 1656 } 1657 case descriptor.FieldDescriptorProto_TYPE_DOUBLE: 1658 if def := defaultValue; def != "inf" && def != "-inf" && def != "nan" { 1659 if f, err := strconv.ParseFloat(defaultValue, 64); err == nil { 1660 defaultValue = fmt.Sprint(f) 1661 } 1662 } 1663 } 1664 defaultValue = ",def=" + defaultValue 1665 } 1666 enum := "" 1667 if *field.Type == descriptor.FieldDescriptorProto_TYPE_ENUM { 1668 // We avoid using obj.goPackageNamehe 1669 // original (proto-world) package name. 1670 obj := g.ObjectNamed(field.GetTypeName()) 1671 if id, ok := obj.(*ImportedDescriptor); ok { 1672 obj = id.o 1673 } 1674 enum = ",enum=" 1675 if pkg := obj.File().GetPackage(); pkg != "" { 1676 enum += pkg + "." 1677 } 1678 enum += CamelCaseSlice(obj.TypeName()) 1679 } 1680 packed := "" 1681 if (field.Options != nil && field.Options.GetPacked()) || 1682 // Per https://developers.google.com/protocol-buffers/docs/proto3#simple: 1683 // "In proto3, repeated fields of scalar numeric types use packed encoding by default." 1684 (message.proto3() && (field.Options == nil || field.Options.Packed == nil) && 1685 isRepeated(field) && IsScalar(field)) { 1686 packed = ",packed" 1687 } 1688 fieldName := field.GetName() 1689 name := fieldName 1690 if *field.Type == descriptor.FieldDescriptorProto_TYPE_GROUP { 1691 // We must use the type name for groups instead of 1692 // the field name to preserve capitalization. 1693 // type_name in FieldDescriptorProto is fully-qualified, 1694 // but we only want the local part. 1695 name = *field.TypeName 1696 if i := strings.LastIndex(name, "."); i >= 0 { 1697 name = name[i+1:] 1698 } 1699 } 1700 if json := field.GetJsonName(); field.Extendee == nil && json != "" && json != name { 1701 // TODO: escaping might be needed, in which case 1702 // perhaps this should be in its own "json" tag. 1703 name += ",json=" + json 1704 } 1705 name = ",name=" + name 1706 1707 embed := "" 1708 if gogoproto.IsEmbed(field) { 1709 embed = ",embedded=" + fieldName 1710 } 1711 1712 ctype := "" 1713 if gogoproto.IsCustomType(field) { 1714 ctype = ",customtype=" + gogoproto.GetCustomType(field) 1715 } 1716 1717 casttype := "" 1718 if gogoproto.IsCastType(field) { 1719 casttype = ",casttype=" + gogoproto.GetCastType(field) 1720 } 1721 1722 castkey := "" 1723 if gogoproto.IsCastKey(field) { 1724 castkey = ",castkey=" + gogoproto.GetCastKey(field) 1725 } 1726 1727 castvalue := "" 1728 if gogoproto.IsCastValue(field) { 1729 castvalue = ",castvalue=" + gogoproto.GetCastValue(field) 1730 // record the original message type for jsonpb reconstruction 1731 desc := g.ObjectNamed(field.GetTypeName()) 1732 if d, ok := desc.(*Descriptor); ok && d.GetOptions().GetMapEntry() { 1733 valueField := d.Field[1] 1734 if valueField.IsMessage() { 1735 castvalue += ",castvaluetype=" + strings.TrimPrefix(valueField.GetTypeName(), ".") 1736 } 1737 } 1738 } 1739 1740 if message.proto3() { 1741 name += ",proto3" 1742 } 1743 oneof := "" 1744 if field.OneofIndex != nil { 1745 oneof = ",oneof" 1746 } 1747 stdtime := "" 1748 if gogoproto.IsStdTime(field) { 1749 stdtime = ",stdtime" 1750 } 1751 stdduration := "" 1752 if gogoproto.IsStdDuration(field) { 1753 stdduration = ",stdduration" 1754 } 1755 wktptr := "" 1756 if gogoproto.IsWktPtr(field) { 1757 wktptr = ",wktptr" 1758 } 1759 return strconv.Quote(fmt.Sprintf("%s,%d,%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 1760 wiretype, 1761 field.GetNumber(), 1762 optrepreq, 1763 packed, 1764 name, 1765 enum, 1766 oneof, 1767 defaultValue, 1768 embed, 1769 ctype, 1770 casttype, 1771 castkey, 1772 castvalue, 1773 stdtime, 1774 stdduration, 1775 wktptr)) 1776} 1777 1778func needsStar(field *descriptor.FieldDescriptorProto, proto3 bool, allowOneOf bool) bool { 1779 if isRepeated(field) && 1780 (*field.Type != descriptor.FieldDescriptorProto_TYPE_MESSAGE || gogoproto.IsCustomType(field)) && 1781 (*field.Type != descriptor.FieldDescriptorProto_TYPE_GROUP) { 1782 return false 1783 } 1784 if *field.Type == descriptor.FieldDescriptorProto_TYPE_BYTES && !gogoproto.IsCustomType(field) { 1785 return false 1786 } 1787 if !gogoproto.IsNullable(field) { 1788 return false 1789 } 1790 if field.OneofIndex != nil && allowOneOf && 1791 (*field.Type != descriptor.FieldDescriptorProto_TYPE_MESSAGE) && 1792 (*field.Type != descriptor.FieldDescriptorProto_TYPE_GROUP) { 1793 return false 1794 } 1795 if proto3 && 1796 (*field.Type != descriptor.FieldDescriptorProto_TYPE_MESSAGE) && 1797 (*field.Type != descriptor.FieldDescriptorProto_TYPE_GROUP) && 1798 !gogoproto.IsCustomType(field) { 1799 return false 1800 } 1801 return true 1802} 1803 1804// TypeName is the printed name appropriate for an item. If the object is in the current file, 1805// TypeName drops the package name and underscores the rest. 1806// Otherwise the object is from another package; and the result is the underscored 1807// package name followed by the item name. 1808// The result always has an initial capital. 1809func (g *Generator) TypeName(obj Object) string { 1810 return g.DefaultPackageName(obj) + CamelCaseSlice(obj.TypeName()) 1811} 1812 1813// GoType returns a string representing the type name, and the wire type 1814func (g *Generator) GoType(message *Descriptor, field *descriptor.FieldDescriptorProto) (typ string, wire string) { 1815 // TODO: Options. 1816 switch *field.Type { 1817 case descriptor.FieldDescriptorProto_TYPE_DOUBLE: 1818 typ, wire = "float64", "fixed64" 1819 case descriptor.FieldDescriptorProto_TYPE_FLOAT: 1820 typ, wire = "float32", "fixed32" 1821 case descriptor.FieldDescriptorProto_TYPE_INT64: 1822 typ, wire = "int64", "varint" 1823 case descriptor.FieldDescriptorProto_TYPE_UINT64: 1824 typ, wire = "uint64", "varint" 1825 case descriptor.FieldDescriptorProto_TYPE_INT32: 1826 typ, wire = "int32", "varint" 1827 case descriptor.FieldDescriptorProto_TYPE_UINT32: 1828 typ, wire = "uint32", "varint" 1829 case descriptor.FieldDescriptorProto_TYPE_FIXED64: 1830 typ, wire = "uint64", "fixed64" 1831 case descriptor.FieldDescriptorProto_TYPE_FIXED32: 1832 typ, wire = "uint32", "fixed32" 1833 case descriptor.FieldDescriptorProto_TYPE_BOOL: 1834 typ, wire = "bool", "varint" 1835 case descriptor.FieldDescriptorProto_TYPE_STRING: 1836 typ, wire = "string", "bytes" 1837 case descriptor.FieldDescriptorProto_TYPE_GROUP: 1838 desc := g.ObjectNamed(field.GetTypeName()) 1839 typ, wire = g.TypeName(desc), "group" 1840 case descriptor.FieldDescriptorProto_TYPE_MESSAGE: 1841 desc := g.ObjectNamed(field.GetTypeName()) 1842 typ, wire = g.TypeName(desc), "bytes" 1843 case descriptor.FieldDescriptorProto_TYPE_BYTES: 1844 typ, wire = "[]byte", "bytes" 1845 case descriptor.FieldDescriptorProto_TYPE_ENUM: 1846 desc := g.ObjectNamed(field.GetTypeName()) 1847 typ, wire = g.TypeName(desc), "varint" 1848 case descriptor.FieldDescriptorProto_TYPE_SFIXED32: 1849 typ, wire = "int32", "fixed32" 1850 case descriptor.FieldDescriptorProto_TYPE_SFIXED64: 1851 typ, wire = "int64", "fixed64" 1852 case descriptor.FieldDescriptorProto_TYPE_SINT32: 1853 typ, wire = "int32", "zigzag32" 1854 case descriptor.FieldDescriptorProto_TYPE_SINT64: 1855 typ, wire = "int64", "zigzag64" 1856 default: 1857 g.Fail("unknown type for", field.GetName()) 1858 } 1859 switch { 1860 case gogoproto.IsCustomType(field) && gogoproto.IsCastType(field): 1861 g.Fail(field.GetName() + " cannot be custom type and cast type") 1862 case gogoproto.IsCustomType(field): 1863 var packageName string 1864 var err error 1865 packageName, typ, err = getCustomType(field) 1866 if err != nil { 1867 g.Fail(err.Error()) 1868 } 1869 if len(packageName) > 0 { 1870 g.customImports = append(g.customImports, packageName) 1871 } 1872 case gogoproto.IsCastType(field): 1873 var packageName string 1874 var err error 1875 packageName, typ, err = getCastType(field) 1876 if err != nil { 1877 g.Fail(err.Error()) 1878 } 1879 if len(packageName) > 0 { 1880 g.customImports = append(g.customImports, packageName) 1881 } 1882 case gogoproto.IsStdTime(field): 1883 g.customImports = append(g.customImports, "time") 1884 typ = "time.Time" 1885 case gogoproto.IsStdDuration(field): 1886 g.customImports = append(g.customImports, "time") 1887 typ = "time.Duration" 1888 case gogoproto.IsStdDouble(field): 1889 typ = "float64" 1890 case gogoproto.IsStdFloat(field): 1891 typ = "float32" 1892 case gogoproto.IsStdInt64(field): 1893 typ = "int64" 1894 case gogoproto.IsStdUInt64(field): 1895 typ = "uint64" 1896 case gogoproto.IsStdInt32(field): 1897 typ = "int32" 1898 case gogoproto.IsStdUInt32(field): 1899 typ = "uint32" 1900 case gogoproto.IsStdBool(field): 1901 typ = "bool" 1902 case gogoproto.IsStdString(field): 1903 typ = "string" 1904 case gogoproto.IsStdBytes(field): 1905 typ = "[]byte" 1906 } 1907 if needsStar(field, g.file.proto3 && field.Extendee == nil, message != nil && message.allowOneof()) { 1908 typ = "*" + typ 1909 } 1910 if isRepeated(field) { 1911 typ = "[]" + typ 1912 } 1913 return 1914} 1915 1916// GoMapDescriptor is a full description of the map output struct. 1917type GoMapDescriptor struct { 1918 GoType string 1919 1920 KeyField *descriptor.FieldDescriptorProto 1921 KeyAliasField *descriptor.FieldDescriptorProto 1922 KeyTag string 1923 1924 ValueField *descriptor.FieldDescriptorProto 1925 ValueAliasField *descriptor.FieldDescriptorProto 1926 ValueTag string 1927} 1928 1929func (g *Generator) GoMapType(d *Descriptor, field *descriptor.FieldDescriptorProto) *GoMapDescriptor { 1930 if d == nil { 1931 byName := g.ObjectNamed(field.GetTypeName()) 1932 desc, ok := byName.(*Descriptor) 1933 if byName == nil || !ok || !desc.GetOptions().GetMapEntry() { 1934 g.Fail(fmt.Sprintf("field %s is not a map", field.GetTypeName())) 1935 return nil 1936 } 1937 d = desc 1938 } 1939 1940 m := &GoMapDescriptor{ 1941 KeyField: d.Field[0], 1942 ValueField: d.Field[1], 1943 } 1944 1945 // Figure out the Go types and tags for the key and value types. 1946 m.KeyAliasField, m.ValueAliasField = g.GetMapKeyField(field, m.KeyField), g.GetMapValueField(field, m.ValueField) 1947 keyType, keyWire := g.GoType(d, m.KeyAliasField) 1948 valType, valWire := g.GoType(d, m.ValueAliasField) 1949 1950 m.KeyTag, m.ValueTag = g.goTag(d, m.KeyField, keyWire), g.goTag(d, m.ValueField, valWire) 1951 1952 if gogoproto.IsCastType(field) { 1953 var packageName string 1954 var err error 1955 packageName, typ, err := getCastType(field) 1956 if err != nil { 1957 g.Fail(err.Error()) 1958 } 1959 if len(packageName) > 0 { 1960 g.customImports = append(g.customImports, packageName) 1961 } 1962 m.GoType = typ 1963 return m 1964 } 1965 1966 // We don't use stars, except for message-typed values. 1967 // Message and enum types are the only two possibly foreign types used in maps, 1968 // so record their use. They are not permitted as map keys. 1969 keyType = strings.TrimPrefix(keyType, "*") 1970 switch *m.ValueAliasField.Type { 1971 case descriptor.FieldDescriptorProto_TYPE_ENUM: 1972 valType = strings.TrimPrefix(valType, "*") 1973 g.RecordTypeUse(m.ValueAliasField.GetTypeName()) 1974 case descriptor.FieldDescriptorProto_TYPE_MESSAGE: 1975 if !gogoproto.IsNullable(m.ValueAliasField) { 1976 valType = strings.TrimPrefix(valType, "*") 1977 } 1978 if !gogoproto.IsStdType(m.ValueAliasField) && !gogoproto.IsCustomType(field) && !gogoproto.IsCastType(field) { 1979 g.RecordTypeUse(m.ValueAliasField.GetTypeName()) 1980 } 1981 default: 1982 if gogoproto.IsCustomType(m.ValueAliasField) { 1983 if !gogoproto.IsNullable(m.ValueAliasField) { 1984 valType = strings.TrimPrefix(valType, "*") 1985 } 1986 if !gogoproto.IsStdType(field) { 1987 g.RecordTypeUse(m.ValueAliasField.GetTypeName()) 1988 } 1989 } else { 1990 valType = strings.TrimPrefix(valType, "*") 1991 } 1992 } 1993 1994 m.GoType = fmt.Sprintf("map[%s]%s", keyType, valType) 1995 return m 1996} 1997 1998func (g *Generator) RecordTypeUse(t string) { 1999 if _, ok := g.typeNameToObject[t]; !ok { 2000 return 2001 } 2002 importPath := g.ObjectNamed(t).GoImportPath() 2003 if importPath == g.outputImportPath { 2004 // Don't record use of objects in our package. 2005 return 2006 } 2007 g.AddImport(importPath) 2008 g.usedPackages[importPath] = true 2009} 2010 2011// Method names that may be generated. Fields with these names get an 2012// underscore appended. Any change to this set is a potential incompatible 2013// API change because it changes generated field names. 2014var methodNames = [...]string{ 2015 "Reset", 2016 "String", 2017 "ProtoMessage", 2018 "Marshal", 2019 "Unmarshal", 2020 "ExtensionRangeArray", 2021 "ExtensionMap", 2022 "Descriptor", 2023 "MarshalTo", 2024 "Equal", 2025 "VerboseEqual", 2026 "GoString", 2027 "ProtoSize", 2028} 2029 2030// Names of messages in the `google.protobuf` package for which 2031// we will generate XXX_WellKnownType methods. 2032var wellKnownTypes = map[string]bool{ 2033 "Any": true, 2034 "Duration": true, 2035 "Empty": true, 2036 "Struct": true, 2037 "Timestamp": true, 2038 2039 "Value": true, 2040 "ListValue": true, 2041 "DoubleValue": true, 2042 "FloatValue": true, 2043 "Int64Value": true, 2044 "UInt64Value": true, 2045 "Int32Value": true, 2046 "UInt32Value": true, 2047 "BoolValue": true, 2048 "StringValue": true, 2049 "BytesValue": true, 2050} 2051 2052// getterDefault finds the default value for the field to return from a getter, 2053// regardless of if it's a built in default or explicit from the source. Returns e.g. "nil", `""`, "Default_MessageType_FieldName" 2054func (g *Generator) getterDefault(field *descriptor.FieldDescriptorProto, goMessageType, goTypeName string) string { 2055 if isRepeated(field) { 2056 return "nil" 2057 } 2058 if def := field.GetDefaultValue(); def != "" { 2059 defaultConstant := g.defaultConstantName(goMessageType, field.GetName()) 2060 if *field.Type != descriptor.FieldDescriptorProto_TYPE_BYTES { 2061 return defaultConstant 2062 } 2063 return "append([]byte(nil), " + defaultConstant + "...)" 2064 } 2065 switch *field.Type { 2066 case descriptor.FieldDescriptorProto_TYPE_GROUP, 2067 descriptor.FieldDescriptorProto_TYPE_MESSAGE: 2068 if field.OneofIndex != nil { 2069 return "nil" 2070 } else { 2071 if !gogoproto.IsNullable(field) && (gogoproto.IsStdDuration(field) || 2072 gogoproto.IsStdDouble(field) || gogoproto.IsStdFloat(field) || 2073 gogoproto.IsStdInt64(field) || gogoproto.IsStdUInt64(field) || 2074 gogoproto.IsStdInt32(field) || gogoproto.IsStdUInt32(field)) { 2075 return "0" 2076 } else if !gogoproto.IsNullable(field) && gogoproto.IsStdBool(field) { 2077 return "false" 2078 } else if !gogoproto.IsNullable(field) && gogoproto.IsStdString(field) { 2079 return "\"\"" 2080 } else if !gogoproto.IsNullable(field) && gogoproto.IsStdBytes(field) { 2081 return "[]byte{}" 2082 } else { 2083 return goTypeName + "{}" 2084 } 2085 } 2086 case descriptor.FieldDescriptorProto_TYPE_BOOL: 2087 return "false" 2088 case descriptor.FieldDescriptorProto_TYPE_STRING: 2089 return "\"\"" 2090 case descriptor.FieldDescriptorProto_TYPE_BYTES: 2091 // This is only possible for oneof fields. 2092 return "nil" 2093 case descriptor.FieldDescriptorProto_TYPE_ENUM: 2094 // The default default for an enum is the first value in the enum, 2095 // not zero. 2096 obj := g.ObjectNamed(field.GetTypeName()) 2097 var enum *EnumDescriptor 2098 if id, ok := obj.(*ImportedDescriptor); ok { 2099 // The enum type has been publicly imported. 2100 enum, _ = id.o.(*EnumDescriptor) 2101 } else { 2102 enum, _ = obj.(*EnumDescriptor) 2103 } 2104 if enum == nil { 2105 log.Printf("don't know how to generate getter for %s", field.GetName()) 2106 return "nil" 2107 } 2108 if len(enum.Value) == 0 { 2109 return "0 // empty enum" 2110 } else { 2111 first := enum.Value[0].GetName() 2112 if gogoproto.IsEnumValueCustomName(enum.Value[0]) { 2113 first = gogoproto.GetEnumValueCustomName(enum.Value[0]) 2114 } 2115 if gogoproto.EnabledGoEnumPrefix(enum.file.FileDescriptorProto, enum.EnumDescriptorProto) { 2116 return g.DefaultPackageName(obj) + enum.prefix() + first 2117 } else { 2118 return g.DefaultPackageName(obj) + first 2119 } 2120 } 2121 default: 2122 return "0" 2123 } 2124} 2125 2126// defaultConstantName builds the name of the default constant from the message 2127// type name and the untouched field name, e.g. "Default_MessageType_FieldName" 2128func (g *Generator) defaultConstantName(goMessageType, protoFieldName string) string { 2129 return "Default_" + goMessageType + "_" + CamelCase(protoFieldName) 2130} 2131 2132// The different types of fields in a message and how to actually print them 2133// Most of the logic for generateMessage is in the methods of these types. 2134// 2135// Note that the content of the field is irrelevant, a simpleField can contain 2136// anything from a scalar to a group (which is just a message). 2137// 2138// Extension fields (and message sets) are however handled separately. 2139// 2140// simpleField - a field that is neiter weak nor oneof, possibly repeated 2141// oneofField - field containing list of subfields: 2142// - oneofSubField - a field within the oneof 2143 2144// msgCtx contains the context for the generator functions. 2145type msgCtx struct { 2146 goName string // Go struct name of the message, e.g. MessageName 2147 message *Descriptor // The descriptor for the message 2148} 2149 2150// fieldCommon contains data common to all types of fields. 2151type fieldCommon struct { 2152 goName string // Go name of field, e.g. "FieldName" or "Descriptor_" 2153 protoName string // Name of field in proto language, e.g. "field_name" or "descriptor" 2154 getterName string // Name of the getter, e.g. "GetFieldName" or "GetDescriptor_" 2155 goType string // The Go type as a string, e.g. "*int32" or "*OtherMessage" 2156 tags string // The tag string/annotation for the type, e.g. `protobuf:"varint,8,opt,name=region_id,json=regionId"` 2157 fullPath string // The full path of the field as used by Annotate etc, e.g. "4,0,2,0" 2158 protoField *descriptor.FieldDescriptorProto // gogo. Passing in the fieldDescriptor in for gogo options. TODO rethink this, we might need a better way of getting options. 2159} 2160 2161// getProtoName gets the proto name of a field, e.g. "field_name" or "descriptor". 2162func (f *fieldCommon) getProtoName() string { 2163 return f.protoName 2164} 2165 2166// getGoType returns the go type of the field as a string, e.g. "*int32". 2167func (f *fieldCommon) getGoType() string { 2168 return f.goType 2169} 2170 2171// simpleField is not weak, not a oneof, not an extension. Can be required, optional or repeated. 2172type simpleField struct { 2173 fieldCommon 2174 protoTypeName string // Proto type name, empty if primitive, e.g. ".google.protobuf.Duration" 2175 protoType descriptor.FieldDescriptorProto_Type // Actual type enum value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64 2176 deprecated string // Deprecation comment, if any, e.g. "// Deprecated: Do not use." 2177 getterDef string // Default for getters, e.g. "nil", `""` or "Default_MessageType_FieldName" 2178 protoDef string // Default value as defined in the proto file, e.g "yoshi" or "5" 2179 comment string // The full comment for the field, e.g. "// Useful information" 2180} 2181 2182// decl prints the declaration of the field in the struct (if any). 2183func (f *simpleField) decl(g *Generator, mc *msgCtx) { 2184 g.P(f.comment, Annotate(mc.message.file, f.fullPath, f.goName), "\t", f.goType, "\t`", f.tags, "`", f.deprecated) 2185} 2186 2187// getter prints the getter for the field. 2188func (f *simpleField) getter(g *Generator, mc *msgCtx) { 2189 oneof := false 2190 if !oneof && !gogoproto.HasGoGetters(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2191 return 2192 } 2193 if gogoproto.IsEmbed(f.protoField) || gogoproto.IsCustomType(f.protoField) { 2194 return 2195 } 2196 if f.deprecated != "" { 2197 g.P(f.deprecated) 2198 } 2199 g.generateGet(mc, f.protoField, f.protoType, false, f.goName, f.goType, "", "", f.fullPath, f.getterName, f.getterDef) 2200} 2201 2202// setter prints the setter method of the field. 2203func (f *simpleField) setter(g *Generator, mc *msgCtx) { 2204 // No setter for regular fields yet 2205} 2206 2207// getProtoDef returns the default value explicitly stated in the proto file, e.g "yoshi" or "5". 2208func (f *simpleField) getProtoDef() string { 2209 return f.protoDef 2210} 2211 2212// getProtoTypeName returns the protobuf type name for the field as returned by field.GetTypeName(), e.g. ".google.protobuf.Duration". 2213func (f *simpleField) getProtoTypeName() string { 2214 return f.protoTypeName 2215} 2216 2217// getProtoType returns the *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64. 2218func (f *simpleField) getProtoType() descriptor.FieldDescriptorProto_Type { 2219 return f.protoType 2220} 2221 2222func (f *simpleField) getProto() *descriptor.FieldDescriptorProto { 2223 return f.protoField 2224} 2225 2226// oneofSubFields are kept slize held by each oneofField. They do not appear in the top level slize of fields for the message. 2227type oneofSubField struct { 2228 fieldCommon 2229 protoTypeName string // Proto type name, empty if primitive, e.g. ".google.protobuf.Duration" 2230 protoType descriptor.FieldDescriptorProto_Type // Actual type enum value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64 2231 oneofTypeName string // Type name of the enclosing struct, e.g. "MessageName_FieldName" 2232 fieldNumber int // Actual field number, as defined in proto, e.g. 12 2233 getterDef string // Default for getters, e.g. "nil", `""` or "Default_MessageType_FieldName" 2234 protoDef string // Default value as defined in the proto file, e.g "yoshi" or "5" 2235 deprecated string // Deprecation comment, if any. 2236} 2237 2238// typedNil prints a nil casted to the pointer to this field. 2239// - for XXX_OneofWrappers 2240func (f *oneofSubField) typedNil(g *Generator) { 2241 g.P("(*", f.oneofTypeName, ")(nil),") 2242} 2243 2244// getProtoDef returns the default value explicitly stated in the proto file, e.g "yoshi" or "5". 2245func (f *oneofSubField) getProtoDef() string { 2246 return f.protoDef 2247} 2248 2249// getProtoTypeName returns the protobuf type name for the field as returned by field.GetTypeName(), e.g. ".google.protobuf.Duration". 2250func (f *oneofSubField) getProtoTypeName() string { 2251 return f.protoTypeName 2252} 2253 2254// getProtoType returns the *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64. 2255func (f *oneofSubField) getProtoType() descriptor.FieldDescriptorProto_Type { 2256 return f.protoType 2257} 2258 2259func (f *oneofSubField) getProto() *descriptor.FieldDescriptorProto { 2260 return f.protoField 2261} 2262 2263// oneofField represents the oneof on top level. 2264// The alternative fields within the oneof are represented by oneofSubField. 2265type oneofField struct { 2266 fieldCommon 2267 subFields []*oneofSubField // All the possible oneof fields 2268 comment string // The full comment for the field, e.g. "// Types that are valid to be assigned to MyOneof:\n\\" 2269} 2270 2271// decl prints the declaration of the field in the struct (if any). 2272func (f *oneofField) decl(g *Generator, mc *msgCtx) { 2273 comment := f.comment 2274 for _, sf := range f.subFields { 2275 comment += "//\t*" + sf.oneofTypeName + "\n" 2276 } 2277 g.P(comment, Annotate(mc.message.file, f.fullPath, f.goName), " ", f.goType, " `", f.tags, "`") 2278} 2279 2280// getter for a oneof field will print additional discriminators and interfaces for the oneof, 2281// also it prints all the getters for the sub fields. 2282func (f *oneofField) getter(g *Generator, mc *msgCtx) { 2283 oneof := true 2284 if !oneof && !gogoproto.HasGoGetters(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2285 return 2286 } 2287 2288 for _, sf := range f.subFields { 2289 if gogoproto.IsEmbed(sf.protoField) || gogoproto.IsCustomType(sf.protoField) { 2290 continue 2291 } 2292 if sf.deprecated != "" { 2293 g.P(sf.deprecated) 2294 } 2295 g.generateGet(mc, sf.protoField, sf.protoType, true, sf.goName, sf.goType, f.goName, sf.oneofTypeName, sf.fullPath, sf.getterName, sf.getterDef) 2296 } 2297} 2298 2299// setter prints the setter method of the field. 2300func (f *oneofField) setter(g *Generator, mc *msgCtx) { 2301 // No setters for oneof yet 2302} 2303 2304// topLevelField interface implemented by all types of fields on the top level (not oneofSubField). 2305type topLevelField interface { 2306 decl(g *Generator, mc *msgCtx) // print declaration within the struct 2307 getter(g *Generator, mc *msgCtx) // print getter 2308 setter(g *Generator, mc *msgCtx) // print setter if applicable 2309} 2310 2311// defField interface implemented by all types of fields that can have defaults (not oneofField, but instead oneofSubField). 2312type defField interface { 2313 getProtoDef() string // default value explicitly stated in the proto file, e.g "yoshi" or "5" 2314 getProtoName() string // proto name of a field, e.g. "field_name" or "descriptor" 2315 getGoType() string // go type of the field as a string, e.g. "*int32" 2316 getProtoTypeName() string // protobuf type name for the field, e.g. ".google.protobuf.Duration" 2317 getProtoType() descriptor.FieldDescriptorProto_Type // *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64 2318 getProto() *descriptor.FieldDescriptorProto 2319} 2320 2321// generateDefaultConstants adds constants for default values if needed, which is only if the default value is. 2322// explicit in the proto. 2323func (g *Generator) generateDefaultConstants(mc *msgCtx, topLevelFields []topLevelField) { 2324 // Collect fields that can have defaults 2325 dFields := []defField{} 2326 for _, pf := range topLevelFields { 2327 if f, ok := pf.(*oneofField); ok { 2328 for _, osf := range f.subFields { 2329 dFields = append(dFields, osf) 2330 } 2331 continue 2332 } 2333 dFields = append(dFields, pf.(defField)) 2334 } 2335 for _, df := range dFields { 2336 def := df.getProtoDef() 2337 if def == "" { 2338 continue 2339 } 2340 if !gogoproto.IsNullable(df.getProto()) { 2341 g.Fail("illegal default value: ", df.getProtoName(), " in ", mc.message.GetName(), " is not nullable and is thus not allowed to have a default value") 2342 } 2343 fieldname := g.defaultConstantName(mc.goName, df.getProtoName()) 2344 typename := df.getGoType() 2345 if typename[0] == '*' { 2346 typename = typename[1:] 2347 } 2348 kind := "const " 2349 switch { 2350 case typename == "bool": 2351 case typename == "string": 2352 def = strconv.Quote(def) 2353 case typename == "[]byte": 2354 def = "[]byte(" + strconv.Quote(unescape(def)) + ")" 2355 kind = "var " 2356 case def == "inf", def == "-inf", def == "nan": 2357 // These names are known to, and defined by, the protocol language. 2358 switch def { 2359 case "inf": 2360 def = "math.Inf(1)" 2361 case "-inf": 2362 def = "math.Inf(-1)" 2363 case "nan": 2364 def = "math.NaN()" 2365 } 2366 if df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_FLOAT { 2367 def = "float32(" + def + ")" 2368 } 2369 kind = "var " 2370 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_FLOAT: 2371 if f, err := strconv.ParseFloat(def, 32); err == nil { 2372 def = fmt.Sprint(float32(f)) 2373 } 2374 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_DOUBLE: 2375 if f, err := strconv.ParseFloat(def, 64); err == nil { 2376 def = fmt.Sprint(f) 2377 } 2378 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_ENUM: 2379 // Must be an enum. Need to construct the prefixed name. 2380 obj := g.ObjectNamed(df.getProtoTypeName()) 2381 var enum *EnumDescriptor 2382 if id, ok := obj.(*ImportedDescriptor); ok { 2383 // The enum type has been publicly imported. 2384 enum, _ = id.o.(*EnumDescriptor) 2385 } else { 2386 enum, _ = obj.(*EnumDescriptor) 2387 } 2388 if enum == nil { 2389 log.Printf("don't know how to generate constant for %s", fieldname) 2390 continue 2391 } 2392 2393 // hunt down the actual enum corresponding to the default 2394 var enumValue *descriptor.EnumValueDescriptorProto 2395 for _, ev := range enum.Value { 2396 if def == ev.GetName() { 2397 enumValue = ev 2398 } 2399 } 2400 2401 if enumValue != nil { 2402 if gogoproto.IsEnumValueCustomName(enumValue) { 2403 def = gogoproto.GetEnumValueCustomName(enumValue) 2404 } 2405 } else { 2406 g.Fail(fmt.Sprintf("could not resolve default enum value for %v.%v", g.DefaultPackageName(obj), def)) 2407 } 2408 2409 if gogoproto.EnabledGoEnumPrefix(enum.file.FileDescriptorProto, enum.EnumDescriptorProto) { 2410 def = g.DefaultPackageName(obj) + enum.prefix() + def 2411 } else { 2412 def = g.DefaultPackageName(obj) + def 2413 } 2414 } 2415 g.P(kind, fieldname, " ", typename, " = ", def) 2416 g.file.addExport(mc.message, constOrVarSymbol{fieldname, kind, ""}) 2417 } 2418 g.P() 2419} 2420 2421// generateGet generates the getter for both the simpleField and oneofSubField. 2422// We did not want to duplicate the code since it is quite intricate so we came 2423// up with this ugly method. At least the logic is in one place. This can be reworked. 2424func (g *Generator) generateGet(mc *msgCtx, protoField *descriptor.FieldDescriptorProto, protoType descriptor.FieldDescriptorProto_Type, 2425 oneof bool, fname, tname, uname, oneoftname, fullpath, gname, def string) { 2426 star := "" 2427 if (protoType != descriptor.FieldDescriptorProto_TYPE_MESSAGE) && 2428 (protoType != descriptor.FieldDescriptorProto_TYPE_GROUP) && 2429 needsStar(protoField, g.file.proto3, mc.message != nil && mc.message.allowOneof()) && tname[0] == '*' { 2430 tname = tname[1:] 2431 star = "*" 2432 } 2433 typeDefaultIsNil := false // whether this field type's default value is a literal nil unless specified 2434 switch protoType { 2435 case descriptor.FieldDescriptorProto_TYPE_BYTES: 2436 typeDefaultIsNil = def == "nil" 2437 case descriptor.FieldDescriptorProto_TYPE_GROUP, descriptor.FieldDescriptorProto_TYPE_MESSAGE: 2438 typeDefaultIsNil = gogoproto.IsNullable(protoField) 2439 } 2440 if isRepeated(protoField) { 2441 typeDefaultIsNil = true 2442 } 2443 g.P("func (m *", mc.goName, ") ", Annotate(mc.message.file, fullpath, gname), "() "+tname+" {") 2444 if !oneof && typeDefaultIsNil { 2445 // A bytes field with no explicit default needs less generated code, 2446 // as does a message or group field, or a repeated field. 2447 g.P("if m != nil {") 2448 g.In() 2449 g.P("return m." + fname) 2450 g.Out() 2451 g.P("}") 2452 g.P("return nil") 2453 g.Out() 2454 g.P("}") 2455 g.P() 2456 return 2457 } 2458 if !gogoproto.IsNullable(protoField) { 2459 g.P("if m != nil {") 2460 g.In() 2461 g.P("return m." + fname) 2462 g.Out() 2463 g.P("}") 2464 } else if !oneof { 2465 if mc.message.proto3() { 2466 g.P("if m != nil {") 2467 } else { 2468 g.P("if m != nil && m." + fname + " != nil {") 2469 } 2470 g.In() 2471 g.P("return " + star + "m." + fname) 2472 g.Out() 2473 g.P("}") 2474 } else { 2475 uname := uname 2476 tname := oneoftname 2477 g.P("if x, ok := m.Get", uname, "().(*", tname, "); ok {") 2478 g.P("return x.", fname) 2479 g.P("}") 2480 } 2481 g.P("return ", def) 2482 g.Out() 2483 g.P("}") 2484 g.P() 2485} 2486 2487// generateInternalStructFields just adds the XXX_<something> fields to the message struct. 2488func (g *Generator) generateInternalStructFields(mc *msgCtx, topLevelFields []topLevelField) { 2489 if gogoproto.HasUnkeyed(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2490 g.P("XXX_NoUnkeyedLiteral\tstruct{} `json:\"-\"`") // prevent unkeyed struct literals 2491 } 2492 if len(mc.message.ExtensionRange) > 0 { 2493 if gogoproto.HasExtensionsMap(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2494 messageset := "" 2495 if opts := mc.message.Options; opts != nil && opts.GetMessageSetWireFormat() { 2496 messageset = "protobuf_messageset:\"1\" " 2497 } 2498 g.P(g.Pkg["proto"], ".XXX_InternalExtensions `", messageset, "json:\"-\"`") 2499 } else { 2500 g.P("XXX_extensions\t\t[]byte `protobuf:\"bytes,0,opt\" json:\"-\"`") 2501 } 2502 } 2503 if gogoproto.HasUnrecognized(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2504 g.P("XXX_unrecognized\t[]byte `json:\"-\"`") 2505 } 2506 if gogoproto.HasSizecache(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2507 g.P("XXX_sizecache\tint32 `json:\"-\"`") 2508 } 2509} 2510 2511// generateOneofFuncs adds all the utility functions for oneof, including marshalling, unmarshalling and sizer. 2512func (g *Generator) generateOneofFuncs(mc *msgCtx, topLevelFields []topLevelField) { 2513 ofields := []*oneofField{} 2514 for _, f := range topLevelFields { 2515 if o, ok := f.(*oneofField); ok { 2516 ofields = append(ofields, o) 2517 } 2518 } 2519 if len(ofields) == 0 { 2520 return 2521 } 2522 2523 // OneofFuncs 2524 g.P("// XXX_OneofWrappers is for the internal use of the proto package.") 2525 g.P("func (*", mc.goName, ") XXX_OneofWrappers() []interface{} {") 2526 g.P("return []interface{}{") 2527 for _, of := range ofields { 2528 for _, sf := range of.subFields { 2529 sf.typedNil(g) 2530 } 2531 } 2532 g.P("}") 2533 g.P("}") 2534 g.P() 2535} 2536 2537func (g *Generator) generateOneofDecls(mc *msgCtx, topLevelFields []topLevelField) { 2538 ofields := []*oneofField{} 2539 for _, f := range topLevelFields { 2540 if o, ok := f.(*oneofField); ok { 2541 ofields = append(ofields, o) 2542 } 2543 } 2544 if len(ofields) == 0 { 2545 return 2546 } 2547 // Oneof per-field types, discriminants and getters. 2548 // Generate unexported named types for the discriminant interfaces. 2549 // We shouldn't have to do this, but there was (~19 Aug 2015) a compiler/linker bug 2550 // that was triggered by using anonymous interfaces here. 2551 // TODO: Revisit this and consider reverting back to anonymous interfaces. 2552 // for oi := range message.OneofDecl { 2553 for _, of := range ofields { 2554 dname := of.goType 2555 g.P("type ", dname, " interface {") 2556 g.In() 2557 g.P(dname, "()") 2558 if gogoproto.HasEqual(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2559 g.P(`Equal(interface{}) bool`) 2560 } 2561 if gogoproto.HasVerboseEqual(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2562 g.P(`VerboseEqual(interface{}) error`) 2563 } 2564 if gogoproto.IsMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) || 2565 gogoproto.IsUnsafeMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) || 2566 gogoproto.IsStableMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2567 g.P(`MarshalTo([]byte) (int, error)`) 2568 } 2569 if gogoproto.IsSizer(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2570 g.P(`Size() int`) 2571 } 2572 if gogoproto.IsProtoSizer(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2573 g.P(`ProtoSize() int`) 2574 } 2575 if gogoproto.HasCompare(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2576 g.P(`Compare(interface{}) int`) 2577 } 2578 g.Out() 2579 g.P("}") 2580 } 2581 g.P() 2582 for _, of := range ofields { 2583 for i, sf := range of.subFields { 2584 fieldFullPath := fmt.Sprintf("%s,%d,%d", mc.message.path, messageFieldPath, i) 2585 g.P("type ", Annotate(mc.message.file, fieldFullPath, sf.oneofTypeName), " struct{ ", Annotate(mc.message.file, fieldFullPath, sf.goName), " ", sf.goType, " `", sf.tags, "` }") 2586 if !gogoproto.IsStdType(sf.protoField) && !gogoproto.IsCustomType(sf.protoField) && !gogoproto.IsCastType(sf.protoField) { 2587 g.RecordTypeUse(sf.protoField.GetTypeName()) 2588 } 2589 } 2590 } 2591 g.P() 2592 for _, of := range ofields { 2593 for _, sf := range of.subFields { 2594 g.P("func (*", sf.oneofTypeName, ") ", of.goType, "() {}") 2595 } 2596 } 2597 g.P() 2598 for _, of := range ofields { 2599 fname := of.goName 2600 g.P("func (m *", mc.goName, ") Get", fname, "() ", of.goType, " {") 2601 g.P("if m != nil { return m.", fname, " }") 2602 g.P("return nil") 2603 g.P("}") 2604 } 2605 g.P() 2606} 2607 2608// generateMessageStruct adds the actual struct with it's members (but not methods) to the output. 2609func (g *Generator) generateMessageStruct(mc *msgCtx, topLevelFields []topLevelField) { 2610 comments := g.PrintComments(mc.message.path) 2611 2612 // Guarantee deprecation comments appear after user-provided comments. 2613 if mc.message.GetOptions().GetDeprecated() { 2614 if comments { 2615 // Convention: Separate deprecation comments from original 2616 // comments with an empty line. 2617 g.P("//") 2618 } 2619 g.P(deprecationComment) 2620 } 2621 g.P("type ", Annotate(mc.message.file, mc.message.path, mc.goName), " struct {") 2622 for _, pf := range topLevelFields { 2623 pf.decl(g, mc) 2624 } 2625 g.generateInternalStructFields(mc, topLevelFields) 2626 g.P("}") 2627} 2628 2629// generateGetters adds getters for all fields, including oneofs and weak fields when applicable. 2630func (g *Generator) generateGetters(mc *msgCtx, topLevelFields []topLevelField) { 2631 for _, pf := range topLevelFields { 2632 pf.getter(g, mc) 2633 2634 } 2635} 2636 2637// generateSetters add setters for all fields, including oneofs and weak fields when applicable. 2638func (g *Generator) generateSetters(mc *msgCtx, topLevelFields []topLevelField) { 2639 for _, pf := range topLevelFields { 2640 pf.setter(g, mc) 2641 } 2642} 2643 2644// generateCommonMethods adds methods to the message that are not on a per field basis. 2645func (g *Generator) generateCommonMethods(mc *msgCtx) { 2646 // Reset, String and ProtoMessage methods. 2647 g.P("func (m *", mc.goName, ") Reset() { *m = ", mc.goName, "{} }") 2648 if gogoproto.EnabledGoStringer(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2649 g.P("func (m *", mc.goName, ") String() string { return ", g.Pkg["proto"], ".CompactTextString(m) }") 2650 } 2651 g.P("func (*", mc.goName, ") ProtoMessage() {}") 2652 var indexes []string 2653 for m := mc.message; m != nil; m = m.parent { 2654 indexes = append([]string{strconv.Itoa(m.index)}, indexes...) 2655 } 2656 g.P("func (*", mc.goName, ") Descriptor() ([]byte, []int) {") 2657 g.P("return ", g.file.VarName(), ", []int{", strings.Join(indexes, ", "), "}") 2658 g.P("}") 2659 // TODO: Revisit the decision to use a XXX_WellKnownType method 2660 // if we change proto.MessageName to work with multiple equivalents. 2661 if mc.message.file.GetPackage() == "google.protobuf" && wellKnownTypes[mc.message.GetName()] { 2662 g.P("func (*", mc.goName, `) XXX_WellKnownType() string { return "`, mc.message.GetName(), `" }`) 2663 } 2664 2665 // Extension support methods 2666 if len(mc.message.ExtensionRange) > 0 { 2667 g.P() 2668 g.P("var extRange_", mc.goName, " = []", g.Pkg["proto"], ".ExtensionRange{") 2669 g.In() 2670 for _, r := range mc.message.ExtensionRange { 2671 end := fmt.Sprint(*r.End - 1) // make range inclusive on both ends 2672 g.P("{Start: ", r.Start, ", End: ", end, "},") 2673 } 2674 g.Out() 2675 g.P("}") 2676 g.P("func (*", mc.goName, ") ExtensionRangeArray() []", g.Pkg["proto"], ".ExtensionRange {") 2677 g.In() 2678 g.P("return extRange_", mc.goName) 2679 g.Out() 2680 g.P("}") 2681 g.P() 2682 if !gogoproto.HasExtensionsMap(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2683 g.P("func (m *", mc.goName, ") GetExtensions() *[]byte {") 2684 g.In() 2685 g.P("if m.XXX_extensions == nil {") 2686 g.In() 2687 g.P("m.XXX_extensions = make([]byte, 0)") 2688 g.Out() 2689 g.P("}") 2690 g.P("return &m.XXX_extensions") 2691 g.Out() 2692 g.P("}") 2693 } 2694 } 2695 2696 // TODO: It does not scale to keep adding another method for every 2697 // operation on protos that we want to switch over to using the 2698 // table-driven approach. Instead, we should only add a single method 2699 // that allows getting access to the *InternalMessageInfo struct and then 2700 // calling Unmarshal, Marshal, Merge, Size, and Discard directly on that. 2701 2702 // Wrapper for table-driven marshaling and unmarshaling. 2703 g.P("func (m *", mc.goName, ") XXX_Unmarshal(b []byte) error {") 2704 g.In() 2705 if gogoproto.IsUnmarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2706 g.P("return m.Unmarshal(b)") 2707 } else { 2708 g.P("return xxx_messageInfo_", mc.goName, ".Unmarshal(m, b)") 2709 } 2710 g.Out() 2711 g.P("}") 2712 2713 g.P("func (m *", mc.goName, ") XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {") 2714 g.In() 2715 if gogoproto.IsMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) || 2716 gogoproto.IsUnsafeMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2717 if gogoproto.IsStableMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2718 g.P("b = b[:cap(b)]") 2719 g.P("n, err := m.MarshalToSizedBuffer(b)") 2720 g.P("if err != nil {") 2721 g.In() 2722 g.P("return nil, err") 2723 g.Out() 2724 g.P("}") 2725 g.P("return b[:n], nil") 2726 } else { 2727 g.P("if deterministic {") 2728 g.In() 2729 g.P("return xxx_messageInfo_", mc.goName, ".Marshal(b, m, deterministic)") 2730 g.P("} else {") 2731 g.In() 2732 g.P("b = b[:cap(b)]") 2733 g.P("n, err := m.MarshalToSizedBuffer(b)") 2734 g.P("if err != nil {") 2735 g.In() 2736 g.P("return nil, err") 2737 g.Out() 2738 g.P("}") 2739 g.Out() 2740 g.P("return b[:n], nil") 2741 g.Out() 2742 g.P("}") 2743 } 2744 } else { 2745 g.P("return xxx_messageInfo_", mc.goName, ".Marshal(b, m, deterministic)") 2746 } 2747 g.Out() 2748 g.P("}") 2749 2750 g.P("func (m *", mc.goName, ") XXX_Merge(src ", g.Pkg["proto"], ".Message) {") 2751 g.In() 2752 g.P("xxx_messageInfo_", mc.goName, ".Merge(m, src)") 2753 g.Out() 2754 g.P("}") 2755 2756 g.P("func (m *", mc.goName, ") XXX_Size() int {") // avoid name clash with "Size" field in some message 2757 g.In() 2758 if (gogoproto.IsMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) || 2759 gogoproto.IsUnsafeMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto)) && 2760 gogoproto.IsSizer(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2761 g.P("return m.Size()") 2762 } else if (gogoproto.IsMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) || 2763 gogoproto.IsUnsafeMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto)) && 2764 gogoproto.IsProtoSizer(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2765 g.P("return m.ProtoSize()") 2766 } else { 2767 g.P("return xxx_messageInfo_", mc.goName, ".Size(m)") 2768 } 2769 g.Out() 2770 g.P("}") 2771 2772 g.P("func (m *", mc.goName, ") XXX_DiscardUnknown() {") 2773 g.In() 2774 g.P("xxx_messageInfo_", mc.goName, ".DiscardUnknown(m)") 2775 g.Out() 2776 g.P("}") 2777 2778 g.P("var xxx_messageInfo_", mc.goName, " ", g.Pkg["proto"], ".InternalMessageInfo") 2779} 2780 2781// Generate the type and default constant definitions for this Descriptor. 2782func (g *Generator) generateMessage(message *Descriptor) { 2783 topLevelFields := []topLevelField{} 2784 oFields := make(map[int32]*oneofField) 2785 // The full type name 2786 typeName := message.TypeName() 2787 // The full type name, CamelCased. 2788 goTypeName := CamelCaseSlice(typeName) 2789 2790 usedNames := make(map[string]bool) 2791 for _, n := range methodNames { 2792 usedNames[n] = true 2793 } 2794 if !gogoproto.IsProtoSizer(message.file.FileDescriptorProto, message.DescriptorProto) { 2795 usedNames["Size"] = true 2796 } 2797 2798 // allocNames finds a conflict-free variation of the given strings, 2799 // consistently mutating their suffixes. 2800 // It returns the same number of strings. 2801 allocNames := func(ns ...string) []string { 2802 Loop: 2803 for { 2804 for _, n := range ns { 2805 if usedNames[n] { 2806 for i := range ns { 2807 ns[i] += "_" 2808 } 2809 continue Loop 2810 } 2811 } 2812 for _, n := range ns { 2813 usedNames[n] = true 2814 } 2815 return ns 2816 } 2817 } 2818 2819 mapFieldTypes := make(map[*descriptor.FieldDescriptorProto]string) // keep track of the map fields to be added later 2820 2821 for i, field := range message.Field { 2822 // Allocate the getter and the field at the same time so name 2823 // collisions create field/method consistent names. 2824 // TODO: This allocation occurs based on the order of the fields 2825 // in the proto file, meaning that a change in the field 2826 // ordering can change generated Method/Field names. 2827 base := CamelCase(*field.Name) 2828 if gogoproto.IsCustomName(field) { 2829 base = gogoproto.GetCustomName(field) 2830 } 2831 ns := allocNames(base, "Get"+base) 2832 fieldName, fieldGetterName := ns[0], ns[1] 2833 2834 typename, wiretype := g.GoType(message, field) 2835 jsonName := *field.Name 2836 jsonTag := jsonName + ",omitempty" 2837 repeatedNativeType := (!field.IsMessage() && !gogoproto.IsCustomType(field) && field.IsRepeated()) 2838 if !gogoproto.IsNullable(field) && !repeatedNativeType { 2839 jsonTag = jsonName 2840 } 2841 gogoJsonTag := gogoproto.GetJsonTag(field) 2842 if gogoJsonTag != nil { 2843 jsonTag = *gogoJsonTag 2844 } 2845 gogoMoreTags := gogoproto.GetMoreTags(field) 2846 moreTags := "" 2847 if gogoMoreTags != nil { 2848 moreTags = " " + *gogoMoreTags 2849 } 2850 tag := fmt.Sprintf("protobuf:%s json:%q%s", g.goTag(message, field, wiretype), jsonTag, moreTags) 2851 if *field.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE && gogoproto.IsEmbed(field) { 2852 fieldName = "" 2853 } 2854 2855 oneof := field.OneofIndex != nil && message.allowOneof() 2856 if oneof && oFields[*field.OneofIndex] == nil { 2857 odp := message.OneofDecl[int(*field.OneofIndex)] 2858 base := CamelCase(odp.GetName()) 2859 names := allocNames(base, "Get"+base) 2860 fname, gname := names[0], names[1] 2861 2862 // This is the first field of a oneof we haven't seen before. 2863 // Generate the union field. 2864 oneofFullPath := fmt.Sprintf("%s,%d,%d", message.path, messageOneofPath, *field.OneofIndex) 2865 c, ok := g.makeComments(oneofFullPath) 2866 if ok { 2867 c += "\n//\n" 2868 } 2869 c += "// Types that are valid to be assigned to " + fname + ":\n" 2870 // Generate the rest of this comment later, 2871 // when we've computed any disambiguation. 2872 2873 dname := "is" + goTypeName + "_" + fname 2874 oneOftag := `protobuf_oneof:"` + odp.GetName() + `"` 2875 of := oneofField{ 2876 fieldCommon: fieldCommon{ 2877 goName: fname, 2878 getterName: gname, 2879 goType: dname, 2880 tags: oneOftag, 2881 protoName: odp.GetName(), 2882 fullPath: oneofFullPath, 2883 protoField: field, 2884 }, 2885 comment: c, 2886 } 2887 topLevelFields = append(topLevelFields, &of) 2888 oFields[*field.OneofIndex] = &of 2889 } 2890 2891 if *field.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE { 2892 desc := g.ObjectNamed(field.GetTypeName()) 2893 if d, ok := desc.(*Descriptor); ok && d.GetOptions().GetMapEntry() { 2894 m := g.GoMapType(d, field) 2895 typename = m.GoType 2896 mapFieldTypes[field] = typename // record for the getter generation 2897 2898 tag += fmt.Sprintf(" protobuf_key:%s protobuf_val:%s", m.KeyTag, m.ValueTag) 2899 } 2900 } 2901 goTyp, _ := g.GoType(message, field) 2902 fieldDeprecated := "" 2903 if field.GetOptions().GetDeprecated() { 2904 fieldDeprecated = deprecationComment 2905 } 2906 dvalue := g.getterDefault(field, goTypeName, GoTypeToName(goTyp)) 2907 if oneof { 2908 tname := goTypeName + "_" + fieldName 2909 // It is possible for this to collide with a message or enum 2910 // nested in this message. Check for collisions. 2911 for { 2912 ok := true 2913 for _, desc := range message.nested { 2914 if CamelCaseSlice(desc.TypeName()) == tname { 2915 ok = false 2916 break 2917 } 2918 } 2919 for _, enum := range message.enums { 2920 if CamelCaseSlice(enum.TypeName()) == tname { 2921 ok = false 2922 break 2923 } 2924 } 2925 if !ok { 2926 tname += "_" 2927 continue 2928 } 2929 break 2930 } 2931 2932 oneofField := oFields[*field.OneofIndex] 2933 sf := oneofSubField{ 2934 fieldCommon: fieldCommon{ 2935 goName: fieldName, 2936 getterName: fieldGetterName, 2937 goType: typename, 2938 tags: tag, 2939 protoName: field.GetName(), 2940 fullPath: fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i), 2941 protoField: field, 2942 }, 2943 protoTypeName: field.GetTypeName(), 2944 fieldNumber: int(*field.Number), 2945 protoType: *field.Type, 2946 getterDef: dvalue, 2947 protoDef: field.GetDefaultValue(), 2948 oneofTypeName: tname, 2949 deprecated: fieldDeprecated, 2950 } 2951 2952 oneofField.subFields = append(oneofField.subFields, &sf) 2953 if !gogoproto.IsStdType(field) && !gogoproto.IsCustomType(field) && !gogoproto.IsCastType(field) { 2954 g.RecordTypeUse(field.GetTypeName()) 2955 } 2956 continue 2957 } 2958 2959 fieldFullPath := fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i) 2960 c, ok := g.makeComments(fieldFullPath) 2961 if ok { 2962 c += "\n" 2963 } 2964 rf := simpleField{ 2965 fieldCommon: fieldCommon{ 2966 goName: fieldName, 2967 getterName: fieldGetterName, 2968 goType: typename, 2969 tags: tag, 2970 protoName: field.GetName(), 2971 fullPath: fieldFullPath, 2972 protoField: field, 2973 }, 2974 protoTypeName: field.GetTypeName(), 2975 protoType: *field.Type, 2976 deprecated: fieldDeprecated, 2977 getterDef: dvalue, 2978 protoDef: field.GetDefaultValue(), 2979 comment: c, 2980 } 2981 var pf topLevelField = &rf 2982 2983 topLevelFields = append(topLevelFields, pf) 2984 2985 if gogoproto.HasTypeDecl(message.file.FileDescriptorProto, message.DescriptorProto) { 2986 if !gogoproto.IsStdType(field) && !gogoproto.IsCustomType(field) && !gogoproto.IsCastType(field) { 2987 g.RecordTypeUse(field.GetTypeName()) 2988 } 2989 } else { 2990 // Even if the type does not need to be generated, we need to iterate 2991 // over all its fields to be able to mark as used any imported types 2992 // used by those fields. 2993 for _, mfield := range message.Field { 2994 if !gogoproto.IsStdType(mfield) && !gogoproto.IsCustomType(mfield) && !gogoproto.IsCastType(mfield) { 2995 g.RecordTypeUse(mfield.GetTypeName()) 2996 } 2997 } 2998 } 2999 } 3000 3001 mc := &msgCtx{ 3002 goName: goTypeName, 3003 message: message, 3004 } 3005 3006 if gogoproto.HasTypeDecl(message.file.FileDescriptorProto, message.DescriptorProto) { 3007 g.generateMessageStruct(mc, topLevelFields) 3008 g.P() 3009 } 3010 g.generateCommonMethods(mc) 3011 g.P() 3012 g.generateDefaultConstants(mc, topLevelFields) 3013 g.P() 3014 g.generateOneofDecls(mc, topLevelFields) 3015 g.P() 3016 g.generateGetters(mc, topLevelFields) 3017 g.P() 3018 g.generateSetters(mc, topLevelFields) 3019 g.P() 3020 g.generateOneofFuncs(mc, topLevelFields) 3021 g.P() 3022 3023 var oneofTypes []string 3024 for _, f := range topLevelFields { 3025 if of, ok := f.(*oneofField); ok { 3026 for _, osf := range of.subFields { 3027 oneofTypes = append(oneofTypes, osf.oneofTypeName) 3028 } 3029 } 3030 } 3031 3032 opts := message.Options 3033 ms := &messageSymbol{ 3034 sym: goTypeName, 3035 hasExtensions: len(message.ExtensionRange) > 0, 3036 isMessageSet: opts != nil && opts.GetMessageSetWireFormat(), 3037 oneofTypes: oneofTypes, 3038 } 3039 g.file.addExport(message, ms) 3040 3041 for _, ext := range message.ext { 3042 g.generateExtension(ext) 3043 } 3044 3045 fullName := strings.Join(message.TypeName(), ".") 3046 if g.file.Package != nil { 3047 fullName = *g.file.Package + "." + fullName 3048 } 3049 3050 g.addInitf("%s.RegisterType((*%s)(nil), %q)", g.Pkg["proto"], goTypeName, fullName) 3051 if gogoproto.ImportsGoGoProto(g.file.FileDescriptorProto) && gogoproto.RegistersGolangProto(g.file.FileDescriptorProto) { 3052 g.addInitf("%s.RegisterType((*%s)(nil), %q)", g.Pkg["golang_proto"], goTypeName, fullName) 3053 } 3054 if gogoproto.HasMessageName(g.file.FileDescriptorProto, message.DescriptorProto) { 3055 g.P("func (*", goTypeName, ") XXX_MessageName() string {") 3056 g.In() 3057 g.P("return ", strconv.Quote(fullName)) 3058 g.Out() 3059 g.P("}") 3060 } 3061 // Register types for native map types. 3062 for _, k := range mapFieldKeys(mapFieldTypes) { 3063 fullName := strings.TrimPrefix(*k.TypeName, ".") 3064 g.addInitf("%s.RegisterMapType((%s)(nil), %q)", g.Pkg["proto"], mapFieldTypes[k], fullName) 3065 if gogoproto.ImportsGoGoProto(g.file.FileDescriptorProto) && gogoproto.RegistersGolangProto(g.file.FileDescriptorProto) { 3066 g.addInitf("%s.RegisterMapType((%s)(nil), %q)", g.Pkg["golang_proto"], mapFieldTypes[k], fullName) 3067 } 3068 } 3069} 3070 3071type byTypeName []*descriptor.FieldDescriptorProto 3072 3073func (a byTypeName) Len() int { return len(a) } 3074func (a byTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 3075func (a byTypeName) Less(i, j int) bool { return *a[i].TypeName < *a[j].TypeName } 3076 3077// mapFieldKeys returns the keys of m in a consistent order. 3078func mapFieldKeys(m map[*descriptor.FieldDescriptorProto]string) []*descriptor.FieldDescriptorProto { 3079 keys := make([]*descriptor.FieldDescriptorProto, 0, len(m)) 3080 for k := range m { 3081 keys = append(keys, k) 3082 } 3083 sort.Sort(byTypeName(keys)) 3084 return keys 3085} 3086 3087var escapeChars = [256]byte{ 3088 'a': '\a', 'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t', 'v': '\v', '\\': '\\', '"': '"', '\'': '\'', '?': '?', 3089} 3090 3091// unescape reverses the "C" escaping that protoc does for default values of bytes fields. 3092// It is best effort in that it effectively ignores malformed input. Seemingly invalid escape 3093// sequences are conveyed, unmodified, into the decoded result. 3094func unescape(s string) string { 3095 // NB: Sadly, we can't use strconv.Unquote because protoc will escape both 3096 // single and double quotes, but strconv.Unquote only allows one or the 3097 // other (based on actual surrounding quotes of its input argument). 3098 3099 var out []byte 3100 for len(s) > 0 { 3101 // regular character, or too short to be valid escape 3102 if s[0] != '\\' || len(s) < 2 { 3103 out = append(out, s[0]) 3104 s = s[1:] 3105 } else if c := escapeChars[s[1]]; c != 0 { 3106 // escape sequence 3107 out = append(out, c) 3108 s = s[2:] 3109 } else if s[1] == 'x' || s[1] == 'X' { 3110 // hex escape, e.g. "\x80 3111 if len(s) < 4 { 3112 // too short to be valid 3113 out = append(out, s[:2]...) 3114 s = s[2:] 3115 continue 3116 } 3117 v, err := strconv.ParseUint(s[2:4], 16, 8) 3118 if err != nil { 3119 out = append(out, s[:4]...) 3120 } else { 3121 out = append(out, byte(v)) 3122 } 3123 s = s[4:] 3124 } else if '0' <= s[1] && s[1] <= '7' { 3125 // octal escape, can vary from 1 to 3 octal digits; e.g., "\0" "\40" or "\164" 3126 // so consume up to 2 more bytes or up to end-of-string 3127 n := len(s[1:]) - len(strings.TrimLeft(s[1:], "01234567")) 3128 if n > 3 { 3129 n = 3 3130 } 3131 v, err := strconv.ParseUint(s[1:1+n], 8, 8) 3132 if err != nil { 3133 out = append(out, s[:1+n]...) 3134 } else { 3135 out = append(out, byte(v)) 3136 } 3137 s = s[1+n:] 3138 } else { 3139 // bad escape, just propagate the slash as-is 3140 out = append(out, s[0]) 3141 s = s[1:] 3142 } 3143 } 3144 3145 return string(out) 3146} 3147 3148func (g *Generator) generateExtension(ext *ExtensionDescriptor) { 3149 ccTypeName := ext.DescName() 3150 3151 extObj := g.ObjectNamed(*ext.Extendee) 3152 var extDesc *Descriptor 3153 if id, ok := extObj.(*ImportedDescriptor); ok { 3154 // This is extending a publicly imported message. 3155 // We need the underlying type for goTag. 3156 extDesc = id.o.(*Descriptor) 3157 } else { 3158 extDesc = extObj.(*Descriptor) 3159 } 3160 extendedType := "*" + g.TypeName(extObj) // always use the original 3161 field := ext.FieldDescriptorProto 3162 fieldType, wireType := g.GoType(ext.parent, field) 3163 tag := g.goTag(extDesc, field, wireType) 3164 g.RecordTypeUse(*ext.Extendee) 3165 if n := ext.FieldDescriptorProto.TypeName; n != nil { 3166 // foreign extension type 3167 g.RecordTypeUse(*n) 3168 } 3169 3170 typeName := ext.TypeName() 3171 3172 // Special case for proto2 message sets: If this extension is extending 3173 // proto2.bridge.MessageSet, and its final name component is "message_set_extension", 3174 // then drop that last component. 3175 // 3176 // TODO: This should be implemented in the text formatter rather than the generator. 3177 // In addition, the situation for when to apply this special case is implemented 3178 // differently in other languages: 3179 // https://github.com/google/protobuf/blob/aff10976/src/google/protobuf/text_format.cc#L1560 3180 if extDesc.GetOptions().GetMessageSetWireFormat() && typeName[len(typeName)-1] == "message_set_extension" { 3181 typeName = typeName[:len(typeName)-1] 3182 } 3183 3184 // For text formatting, the package must be exactly what the .proto file declares, 3185 // ignoring overrides such as the go_package option, and with no dot/underscore mapping. 3186 extName := strings.Join(typeName, ".") 3187 if g.file.Package != nil { 3188 extName = *g.file.Package + "." + extName 3189 } 3190 3191 g.P("var ", ccTypeName, " = &", g.Pkg["proto"], ".ExtensionDesc{") 3192 g.In() 3193 g.P("ExtendedType: (", extendedType, ")(nil),") 3194 g.P("ExtensionType: (", fieldType, ")(nil),") 3195 g.P("Field: ", field.Number, ",") 3196 g.P(`Name: "`, extName, `",`) 3197 g.P("Tag: ", tag, ",") 3198 g.P(`Filename: "`, g.file.GetName(), `",`) 3199 3200 g.Out() 3201 g.P("}") 3202 g.P() 3203 3204 g.addInitf("%s.RegisterExtension(%s)", g.Pkg["proto"], ext.DescName()) 3205 3206 g.file.addExport(ext, constOrVarSymbol{ccTypeName, "var", ""}) 3207} 3208 3209func (g *Generator) generateInitFunction() { 3210 if len(g.init) == 0 { 3211 return 3212 } 3213 g.P("func init() {") 3214 g.In() 3215 for _, l := range g.init { 3216 g.P(l) 3217 } 3218 g.Out() 3219 g.P("}") 3220 g.init = nil 3221} 3222 3223func (g *Generator) generateFileDescriptor(file *FileDescriptor) { 3224 // Make a copy and trim source_code_info data. 3225 // TODO: Trim this more when we know exactly what we need. 3226 pb := proto.Clone(file.FileDescriptorProto).(*descriptor.FileDescriptorProto) 3227 pb.SourceCodeInfo = nil 3228 3229 b, err := proto.Marshal(pb) 3230 if err != nil { 3231 g.Fail(err.Error()) 3232 } 3233 3234 var buf bytes.Buffer 3235 w, _ := gzip.NewWriterLevel(&buf, gzip.BestCompression) 3236 w.Write(b) 3237 w.Close() 3238 b = buf.Bytes() 3239 3240 v := file.VarName() 3241 g.P() 3242 g.P("func init() { ", g.Pkg["proto"], ".RegisterFile(", strconv.Quote(*file.Name), ", ", v, ") }") 3243 if gogoproto.ImportsGoGoProto(g.file.FileDescriptorProto) && gogoproto.RegistersGolangProto(g.file.FileDescriptorProto) { 3244 g.P("func init() { ", g.Pkg["golang_proto"], ".RegisterFile(", strconv.Quote(*file.Name), ", ", v, ") }") 3245 } 3246 g.P("var ", v, " = []byte{") 3247 g.In() 3248 g.P("// ", len(b), " bytes of a gzipped FileDescriptorProto") 3249 for len(b) > 0 { 3250 n := 16 3251 if n > len(b) { 3252 n = len(b) 3253 } 3254 3255 s := "" 3256 for _, c := range b[:n] { 3257 s += fmt.Sprintf("0x%02x,", c) 3258 } 3259 g.P(s) 3260 3261 b = b[n:] 3262 } 3263 g.Out() 3264 g.P("}") 3265} 3266 3267func (g *Generator) generateEnumRegistration(enum *EnumDescriptor) { 3268 // // We always print the full (proto-world) package name here. 3269 pkg := enum.File().GetPackage() 3270 if pkg != "" { 3271 pkg += "." 3272 } 3273 // The full type name 3274 typeName := enum.TypeName() 3275 // The full type name, CamelCased. 3276 ccTypeName := CamelCaseSlice(typeName) 3277 g.addInitf("%s.RegisterEnum(%q, %[3]s_name, %[3]s_value)", g.Pkg["proto"], pkg+ccTypeName, ccTypeName) 3278 if gogoproto.ImportsGoGoProto(g.file.FileDescriptorProto) && gogoproto.RegistersGolangProto(g.file.FileDescriptorProto) { 3279 g.addInitf("%s.RegisterEnum(%q, %[3]s_name, %[3]s_value)", g.Pkg["golang_proto"], pkg+ccTypeName, ccTypeName) 3280 } 3281} 3282 3283// And now lots of helper functions. 3284 3285// Is c an ASCII lower-case letter? 3286func isASCIILower(c byte) bool { 3287 return 'a' <= c && c <= 'z' 3288} 3289 3290// Is c an ASCII digit? 3291func isASCIIDigit(c byte) bool { 3292 return '0' <= c && c <= '9' 3293} 3294 3295// CamelCase returns the CamelCased name. 3296// If there is an interior underscore followed by a lower case letter, 3297// drop the underscore and convert the letter to upper case. 3298// There is a remote possibility of this rewrite causing a name collision, 3299// but it's so remote we're prepared to pretend it's nonexistent - since the 3300// C++ generator lowercases names, it's extremely unlikely to have two fields 3301// with different capitalizations. 3302// In short, _my_field_name_2 becomes XMyFieldName_2. 3303func CamelCase(s string) string { 3304 if s == "" { 3305 return "" 3306 } 3307 t := make([]byte, 0, 32) 3308 i := 0 3309 if s[0] == '_' { 3310 // Need a capital letter; drop the '_'. 3311 t = append(t, 'X') 3312 i++ 3313 } 3314 // Invariant: if the next letter is lower case, it must be converted 3315 // to upper case. 3316 // That is, we process a word at a time, where words are marked by _ or 3317 // upper case letter. Digits are treated as words. 3318 for ; i < len(s); i++ { 3319 c := s[i] 3320 if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) { 3321 continue // Skip the underscore in s. 3322 } 3323 if isASCIIDigit(c) { 3324 t = append(t, c) 3325 continue 3326 } 3327 // Assume we have a letter now - if not, it's a bogus identifier. 3328 // The next word is a sequence of characters that must start upper case. 3329 if isASCIILower(c) { 3330 c ^= ' ' // Make it a capital letter. 3331 } 3332 t = append(t, c) // Guaranteed not lower case. 3333 // Accept lower case sequence that follows. 3334 for i+1 < len(s) && isASCIILower(s[i+1]) { 3335 i++ 3336 t = append(t, s[i]) 3337 } 3338 } 3339 return string(t) 3340} 3341 3342// CamelCaseSlice is like CamelCase, but the argument is a slice of strings to 3343// be joined with "_". 3344func CamelCaseSlice(elem []string) string { return CamelCase(strings.Join(elem, "_")) } 3345 3346// dottedSlice turns a sliced name into a dotted name. 3347func dottedSlice(elem []string) string { return strings.Join(elem, ".") } 3348 3349// Is this field optional? 3350func isOptional(field *descriptor.FieldDescriptorProto) bool { 3351 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_OPTIONAL 3352} 3353 3354// Is this field required? 3355func isRequired(field *descriptor.FieldDescriptorProto) bool { 3356 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REQUIRED 3357} 3358 3359// Is this field repeated? 3360func isRepeated(field *descriptor.FieldDescriptorProto) bool { 3361 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED 3362} 3363 3364// Is this field a scalar numeric type? 3365func IsScalar(field *descriptor.FieldDescriptorProto) bool { 3366 if field.Type == nil { 3367 return false 3368 } 3369 switch *field.Type { 3370 case descriptor.FieldDescriptorProto_TYPE_DOUBLE, 3371 descriptor.FieldDescriptorProto_TYPE_FLOAT, 3372 descriptor.FieldDescriptorProto_TYPE_INT64, 3373 descriptor.FieldDescriptorProto_TYPE_UINT64, 3374 descriptor.FieldDescriptorProto_TYPE_INT32, 3375 descriptor.FieldDescriptorProto_TYPE_FIXED64, 3376 descriptor.FieldDescriptorProto_TYPE_FIXED32, 3377 descriptor.FieldDescriptorProto_TYPE_BOOL, 3378 descriptor.FieldDescriptorProto_TYPE_UINT32, 3379 descriptor.FieldDescriptorProto_TYPE_ENUM, 3380 descriptor.FieldDescriptorProto_TYPE_SFIXED32, 3381 descriptor.FieldDescriptorProto_TYPE_SFIXED64, 3382 descriptor.FieldDescriptorProto_TYPE_SINT32, 3383 descriptor.FieldDescriptorProto_TYPE_SINT64: 3384 return true 3385 default: 3386 return false 3387 } 3388} 3389 3390// badToUnderscore is the mapping function used to generate Go names from package names, 3391// which can be dotted in the input .proto file. It replaces non-identifier characters such as 3392// dot or dash with underscore. 3393func badToUnderscore(r rune) rune { 3394 if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' { 3395 return r 3396 } 3397 return '_' 3398} 3399 3400// baseName returns the last path element of the name, with the last dotted suffix removed. 3401func baseName(name string) string { 3402 // First, find the last element 3403 if i := strings.LastIndex(name, "/"); i >= 0 { 3404 name = name[i+1:] 3405 } 3406 // Now drop the suffix 3407 if i := strings.LastIndex(name, "."); i >= 0 { 3408 name = name[0:i] 3409 } 3410 return name 3411} 3412 3413// The SourceCodeInfo message describes the location of elements of a parsed 3414// .proto file by way of a "path", which is a sequence of integers that 3415// describe the route from a FileDescriptorProto to the relevant submessage. 3416// The path alternates between a field number of a repeated field, and an index 3417// into that repeated field. The constants below define the field numbers that 3418// are used. 3419// 3420// See descriptor.proto for more information about this. 3421const ( 3422 // tag numbers in FileDescriptorProto 3423 packagePath = 2 // package 3424 messagePath = 4 // message_type 3425 enumPath = 5 // enum_type 3426 // tag numbers in DescriptorProto 3427 messageFieldPath = 2 // field 3428 messageMessagePath = 3 // nested_type 3429 messageEnumPath = 4 // enum_type 3430 messageOneofPath = 8 // oneof_decl 3431 // tag numbers in EnumDescriptorProto 3432 enumValuePath = 2 // value 3433) 3434 3435var supportTypeAliases bool 3436 3437func init() { 3438 for _, tag := range build.Default.ReleaseTags { 3439 if tag == "go1.9" { 3440 supportTypeAliases = true 3441 return 3442 } 3443 } 3444} 3445