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