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 c, ok := g.makeComments(path); ok { 1339 g.P(c) 1340 return true 1341 } 1342 return false 1343} 1344 1345// makeComments generates the comment string for the field, no "\n" at the end 1346func (g *Generator) makeComments(path string) (string, bool) { 1347 loc, ok := g.file.comments[path] 1348 if !ok { 1349 return "", false 1350 } 1351 w := new(bytes.Buffer) 1352 nl := "" 1353 for _, line := range strings.Split(strings.TrimSuffix(loc.GetLeadingComments(), "\n"), "\n") { 1354 fmt.Fprintf(w, "%s// %s", nl, strings.TrimPrefix(line, " ")) 1355 nl = "\n" 1356 } 1357 return w.String(), true 1358} 1359 1360// Comments returns any comments from the source .proto file and empty string if comments not found. 1361// The path is a comma-separated list of intergers. 1362// See descriptor.proto for its format. 1363func (g *Generator) Comments(path string) string { 1364 loc, ok := g.file.comments[path] 1365 if !ok { 1366 return "" 1367 } 1368 text := strings.TrimSuffix(loc.GetLeadingComments(), "\n") 1369 return text 1370} 1371 1372func (g *Generator) fileByName(filename string) *FileDescriptor { 1373 return g.allFilesByName[filename] 1374} 1375 1376// weak returns whether the ith import of the current file is a weak import. 1377func (g *Generator) weak(i int32) bool { 1378 for _, j := range g.file.WeakDependency { 1379 if j == i { 1380 return true 1381 } 1382 } 1383 return false 1384} 1385 1386// Generate the imports 1387func (g *Generator) generateImports() { 1388 // We almost always need a proto import. Rather than computing when we 1389 // do, which is tricky when there's a plugin, just import it and 1390 // reference it later. The same argument applies to the fmt and math packages. 1391 if gogoproto.ImportsGoGoProto(g.file.FileDescriptorProto) { 1392 g.PrintImport(GoPackageName(g.Pkg["proto"]), GoImportPath(g.ImportPrefix)+GoImportPath("github.com/gogo/protobuf/proto")) 1393 if gogoproto.RegistersGolangProto(g.file.FileDescriptorProto) { 1394 g.PrintImport(GoPackageName(g.Pkg["golang_proto"]), GoImportPath(g.ImportPrefix)+GoImportPath("github.com/golang/protobuf/proto")) 1395 } 1396 } else { 1397 g.PrintImport(GoPackageName(g.Pkg["proto"]), GoImportPath(g.ImportPrefix)+GoImportPath("github.com/golang/protobuf/proto")) 1398 } 1399 g.PrintImport(GoPackageName(g.Pkg["fmt"]), "fmt") 1400 g.PrintImport(GoPackageName(g.Pkg["math"]), "math") 1401 1402 var ( 1403 imports = make(map[GoImportPath]bool) 1404 strongImports = make(map[GoImportPath]bool) 1405 importPaths []string 1406 ) 1407 for i, s := range g.file.Dependency { 1408 fd := g.fileByName(s) 1409 importPath := fd.importPath 1410 // Do not import our own package. 1411 if importPath == g.file.importPath { 1412 continue 1413 } 1414 if !imports[importPath] { 1415 importPaths = append(importPaths, string(importPath)) 1416 } 1417 imports[importPath] = true 1418 if !g.weak(int32(i)) { 1419 strongImports[importPath] = true 1420 } 1421 } 1422 sort.Strings(importPaths) 1423 for i := range importPaths { 1424 importPath := GoImportPath(importPaths[i]) 1425 packageName := g.GoPackageName(importPath) 1426 fullPath := GoImportPath(g.ImportPrefix) + importPath 1427 // Skip weak imports. 1428 if !strongImports[importPath] { 1429 g.P("// skipping weak import ", packageName, " ", fullPath) 1430 continue 1431 } 1432 // We need to import all the dependencies, even if we don't reference them, 1433 // because other code and tools depend on having the full transitive closure 1434 // of protocol buffer types in the binary. 1435 if _, ok := g.usedPackages[importPath]; ok { 1436 g.PrintImport(packageName, fullPath) 1437 } else { 1438 g.P("import _ ", fullPath) 1439 } 1440 } 1441 g.P() 1442 for _, s := range g.customImports { 1443 s1 := strings.Map(badToUnderscore, s) 1444 g.PrintImport(GoPackageName(s1), GoImportPath(s)) 1445 } 1446 g.P() 1447 // TODO: may need to worry about uniqueness across plugins 1448 for _, p := range plugins { 1449 p.GenerateImports(g.file) 1450 g.P() 1451 } 1452 g.P("// Reference imports to suppress errors if they are not otherwise used.") 1453 g.P("var _ = ", g.Pkg["proto"], ".Marshal") 1454 if gogoproto.ImportsGoGoProto(g.file.FileDescriptorProto) && gogoproto.RegistersGolangProto(g.file.FileDescriptorProto) { 1455 g.P("var _ = ", g.Pkg["golang_proto"], ".Marshal") 1456 } 1457 g.P("var _ = ", g.Pkg["fmt"], ".Errorf") 1458 g.P("var _ = ", g.Pkg["math"], ".Inf") 1459 for _, cimport := range g.customImports { 1460 if cimport == "time" { 1461 g.P("var _ = time.Kitchen") 1462 break 1463 } 1464 } 1465 g.P() 1466} 1467 1468func (g *Generator) generateImported(id *ImportedDescriptor) { 1469 tn := id.TypeName() 1470 sn := tn[len(tn)-1] 1471 df := id.o.File() 1472 filename := *df.Name 1473 if df.importPath == g.file.importPath { 1474 // Don't generate type aliases for files in the same Go package as this one. 1475 g.P("// Ignoring public import of ", sn, " from ", filename) 1476 g.P() 1477 return 1478 } 1479 if !supportTypeAliases { 1480 g.Fail(fmt.Sprintf("%s: public imports require at least go1.9", filename)) 1481 } 1482 g.P("// ", sn, " from public import ", filename) 1483 g.usedPackages[df.importPath] = true 1484 1485 for _, sym := range df.exported[id.o] { 1486 sym.GenerateAlias(g, g.GoPackageName(df.importPath)) 1487 } 1488 1489 g.P() 1490} 1491 1492// Generate the enum definitions for this EnumDescriptor. 1493func (g *Generator) generateEnum(enum *EnumDescriptor) { 1494 // The full type name 1495 typeName := enum.alias() 1496 // The full type name, CamelCased. 1497 ccTypeName := CamelCaseSlice(typeName) 1498 ccPrefix := enum.prefix() 1499 1500 deprecatedEnum := "" 1501 if enum.GetOptions().GetDeprecated() { 1502 deprecatedEnum = deprecationComment 1503 } 1504 1505 g.PrintComments(enum.path) 1506 if !gogoproto.EnabledGoEnumPrefix(enum.file.FileDescriptorProto, enum.EnumDescriptorProto) { 1507 ccPrefix = "" 1508 } 1509 1510 if gogoproto.HasEnumDecl(enum.file.FileDescriptorProto, enum.EnumDescriptorProto) { 1511 g.P("type ", Annotate(enum.file, enum.path, ccTypeName), " int32", deprecatedEnum) 1512 g.file.addExport(enum, enumSymbol{ccTypeName, enum.proto3()}) 1513 g.P("const (") 1514 g.In() 1515 for i, e := range enum.Value { 1516 etorPath := fmt.Sprintf("%s,%d,%d", enum.path, enumValuePath, i) 1517 g.PrintComments(etorPath) 1518 1519 deprecatedValue := "" 1520 if e.GetOptions().GetDeprecated() { 1521 deprecatedValue = deprecationComment 1522 } 1523 name := *e.Name 1524 if gogoproto.IsEnumValueCustomName(e) { 1525 name = gogoproto.GetEnumValueCustomName(e) 1526 } 1527 name = ccPrefix + name 1528 1529 g.P(Annotate(enum.file, etorPath, name), " ", ccTypeName, " = ", e.Number, " ", deprecatedValue) 1530 g.file.addExport(enum, constOrVarSymbol{name, "const", ccTypeName}) 1531 } 1532 g.Out() 1533 g.P(")") 1534 } 1535 1536 g.P("var ", ccTypeName, "_name = map[int32]string{") 1537 g.In() 1538 generated := make(map[int32]bool) // avoid duplicate values 1539 for _, e := range enum.Value { 1540 duplicate := "" 1541 if _, present := generated[*e.Number]; present { 1542 duplicate = "// Duplicate value: " 1543 } 1544 g.P(duplicate, e.Number, ": ", strconv.Quote(*e.Name), ",") 1545 generated[*e.Number] = true 1546 } 1547 g.Out() 1548 g.P("}") 1549 g.P("var ", ccTypeName, "_value = map[string]int32{") 1550 g.In() 1551 for _, e := range enum.Value { 1552 g.P(strconv.Quote(*e.Name), ": ", e.Number, ",") 1553 } 1554 g.Out() 1555 g.P("}") 1556 1557 if !enum.proto3() { 1558 g.P("func (x ", ccTypeName, ") Enum() *", ccTypeName, " {") 1559 g.In() 1560 g.P("p := new(", ccTypeName, ")") 1561 g.P("*p = x") 1562 g.P("return p") 1563 g.Out() 1564 g.P("}") 1565 } 1566 1567 if gogoproto.IsGoEnumStringer(g.file.FileDescriptorProto, enum.EnumDescriptorProto) { 1568 g.P("func (x ", ccTypeName, ") String() string {") 1569 g.In() 1570 g.P("return ", g.Pkg["proto"], ".EnumName(", ccTypeName, "_name, int32(x))") 1571 g.Out() 1572 g.P("}") 1573 } 1574 1575 if !enum.proto3() && !gogoproto.IsGoEnumStringer(g.file.FileDescriptorProto, enum.EnumDescriptorProto) { 1576 g.P("func (x ", ccTypeName, ") MarshalJSON() ([]byte, error) {") 1577 g.In() 1578 g.P("return ", g.Pkg["proto"], ".MarshalJSONEnum(", ccTypeName, "_name, int32(x))") 1579 g.Out() 1580 g.P("}") 1581 } 1582 if !enum.proto3() { 1583 g.P("func (x *", ccTypeName, ") UnmarshalJSON(data []byte) error {") 1584 g.In() 1585 g.P("value, err := ", g.Pkg["proto"], ".UnmarshalJSONEnum(", ccTypeName, `_value, data, "`, ccTypeName, `")`) 1586 g.P("if err != nil {") 1587 g.In() 1588 g.P("return err") 1589 g.Out() 1590 g.P("}") 1591 g.P("*x = ", ccTypeName, "(value)") 1592 g.P("return nil") 1593 g.Out() 1594 g.P("}") 1595 } 1596 1597 var indexes []string 1598 for m := enum.parent; m != nil; m = m.parent { 1599 // XXX: skip groups? 1600 indexes = append([]string{strconv.Itoa(m.index)}, indexes...) 1601 } 1602 indexes = append(indexes, strconv.Itoa(enum.index)) 1603 g.P("func (", ccTypeName, ") EnumDescriptor() ([]byte, []int) {") 1604 g.In() 1605 g.P("return ", g.file.VarName(), ", []int{", strings.Join(indexes, ", "), "}") 1606 g.Out() 1607 g.P("}") 1608 if enum.file.GetPackage() == "google.protobuf" && enum.GetName() == "NullValue" { 1609 g.P("func (", ccTypeName, `) XXX_WellKnownType() string { return "`, enum.GetName(), `" }`) 1610 } 1611 1612 g.P() 1613} 1614 1615// The tag is a string like "varint,2,opt,name=fieldname,def=7" that 1616// identifies details of the field for the protocol buffer marshaling and unmarshaling 1617// code. The fields are: 1618// wire encoding 1619// protocol tag number 1620// opt,req,rep for optional, required, or repeated 1621// packed whether the encoding is "packed" (optional; repeated primitives only) 1622// name= the original declared name 1623// enum= the name of the enum type if it is an enum-typed field. 1624// proto3 if this field is in a proto3 message 1625// def= string representation of the default value, if any. 1626// The default value must be in a representation that can be used at run-time 1627// to generate the default value. Thus bools become 0 and 1, for instance. 1628func (g *Generator) goTag(message *Descriptor, field *descriptor.FieldDescriptorProto, wiretype string) string { 1629 optrepreq := "" 1630 switch { 1631 case isOptional(field): 1632 optrepreq = "opt" 1633 case isRequired(field): 1634 optrepreq = "req" 1635 case isRepeated(field): 1636 optrepreq = "rep" 1637 } 1638 var defaultValue string 1639 if dv := field.DefaultValue; dv != nil { // set means an explicit default 1640 defaultValue = *dv 1641 // Some types need tweaking. 1642 switch *field.Type { 1643 case descriptor.FieldDescriptorProto_TYPE_BOOL: 1644 if defaultValue == "true" { 1645 defaultValue = "1" 1646 } else { 1647 defaultValue = "0" 1648 } 1649 case descriptor.FieldDescriptorProto_TYPE_STRING, 1650 descriptor.FieldDescriptorProto_TYPE_BYTES: 1651 // Nothing to do. Quoting is done for the whole tag. 1652 case descriptor.FieldDescriptorProto_TYPE_ENUM: 1653 // For enums we need to provide the integer constant. 1654 obj := g.ObjectNamed(field.GetTypeName()) 1655 if id, ok := obj.(*ImportedDescriptor); ok { 1656 // It is an enum that was publicly imported. 1657 // We need the underlying type. 1658 obj = id.o 1659 } 1660 enum, ok := obj.(*EnumDescriptor) 1661 if !ok { 1662 log.Printf("obj is a %T", obj) 1663 if id, ok := obj.(*ImportedDescriptor); ok { 1664 log.Printf("id.o is a %T", id.o) 1665 } 1666 g.Fail("unknown enum type", CamelCaseSlice(obj.TypeName())) 1667 } 1668 defaultValue = enum.integerValueAsString(defaultValue) 1669 } 1670 defaultValue = ",def=" + defaultValue 1671 } 1672 enum := "" 1673 if *field.Type == descriptor.FieldDescriptorProto_TYPE_ENUM { 1674 // We avoid using obj.goPackageNamehe 1675 // original (proto-world) package name. 1676 obj := g.ObjectNamed(field.GetTypeName()) 1677 if id, ok := obj.(*ImportedDescriptor); ok { 1678 obj = id.o 1679 } 1680 enum = ",enum=" 1681 if pkg := obj.File().GetPackage(); pkg != "" { 1682 enum += pkg + "." 1683 } 1684 enum += CamelCaseSlice(obj.TypeName()) 1685 } 1686 packed := "" 1687 if (field.Options != nil && field.Options.GetPacked()) || 1688 // Per https://developers.google.com/protocol-buffers/docs/proto3#simple: 1689 // "In proto3, repeated fields of scalar numeric types use packed encoding by default." 1690 (message.proto3() && (field.Options == nil || field.Options.Packed == nil) && 1691 isRepeated(field) && IsScalar(field)) { 1692 packed = ",packed" 1693 } 1694 fieldName := field.GetName() 1695 name := fieldName 1696 if *field.Type == descriptor.FieldDescriptorProto_TYPE_GROUP { 1697 // We must use the type name for groups instead of 1698 // the field name to preserve capitalization. 1699 // type_name in FieldDescriptorProto is fully-qualified, 1700 // but we only want the local part. 1701 name = *field.TypeName 1702 if i := strings.LastIndex(name, "."); i >= 0 { 1703 name = name[i+1:] 1704 } 1705 } 1706 if json := field.GetJsonName(); json != "" && json != name { 1707 // TODO: escaping might be needed, in which case 1708 // perhaps this should be in its own "json" tag. 1709 name += ",json=" + json 1710 } 1711 name = ",name=" + name 1712 1713 embed := "" 1714 if gogoproto.IsEmbed(field) { 1715 embed = ",embedded=" + fieldName 1716 } 1717 1718 ctype := "" 1719 if gogoproto.IsCustomType(field) { 1720 ctype = ",customtype=" + gogoproto.GetCustomType(field) 1721 } 1722 1723 casttype := "" 1724 if gogoproto.IsCastType(field) { 1725 casttype = ",casttype=" + gogoproto.GetCastType(field) 1726 } 1727 1728 castkey := "" 1729 if gogoproto.IsCastKey(field) { 1730 castkey = ",castkey=" + gogoproto.GetCastKey(field) 1731 } 1732 1733 castvalue := "" 1734 if gogoproto.IsCastValue(field) { 1735 castvalue = ",castvalue=" + gogoproto.GetCastValue(field) 1736 // record the original message type for jsonpb reconstruction 1737 desc := g.ObjectNamed(field.GetTypeName()) 1738 if d, ok := desc.(*Descriptor); ok && d.GetOptions().GetMapEntry() { 1739 valueField := d.Field[1] 1740 if valueField.IsMessage() { 1741 castvalue += ",castvaluetype=" + strings.TrimPrefix(valueField.GetTypeName(), ".") 1742 } 1743 } 1744 } 1745 1746 if message.proto3() { 1747 name += ",proto3" 1748 } 1749 oneof := "" 1750 if field.OneofIndex != nil { 1751 oneof = ",oneof" 1752 } 1753 stdtime := "" 1754 if gogoproto.IsStdTime(field) { 1755 stdtime = ",stdtime" 1756 } 1757 stdduration := "" 1758 if gogoproto.IsStdDuration(field) { 1759 stdduration = ",stdduration" 1760 } 1761 wktptr := "" 1762 if gogoproto.IsWktPtr(field) { 1763 wktptr = ",wktptr" 1764 } 1765 return strconv.Quote(fmt.Sprintf("%s,%d,%s%s%s%s%s%s%s%s%s%s%s%s%s%s", 1766 wiretype, 1767 field.GetNumber(), 1768 optrepreq, 1769 packed, 1770 name, 1771 enum, 1772 oneof, 1773 defaultValue, 1774 embed, 1775 ctype, 1776 casttype, 1777 castkey, 1778 castvalue, 1779 stdtime, 1780 stdduration, 1781 wktptr)) 1782} 1783 1784func needsStar(field *descriptor.FieldDescriptorProto, proto3 bool, allowOneOf bool) bool { 1785 if isRepeated(field) && 1786 (*field.Type != descriptor.FieldDescriptorProto_TYPE_MESSAGE || gogoproto.IsCustomType(field)) && 1787 (*field.Type != descriptor.FieldDescriptorProto_TYPE_GROUP) { 1788 return false 1789 } 1790 if *field.Type == descriptor.FieldDescriptorProto_TYPE_BYTES && !gogoproto.IsCustomType(field) { 1791 return false 1792 } 1793 if !gogoproto.IsNullable(field) { 1794 return false 1795 } 1796 if field.OneofIndex != nil && allowOneOf && 1797 (*field.Type != descriptor.FieldDescriptorProto_TYPE_MESSAGE) && 1798 (*field.Type != descriptor.FieldDescriptorProto_TYPE_GROUP) { 1799 return false 1800 } 1801 if proto3 && 1802 (*field.Type != descriptor.FieldDescriptorProto_TYPE_MESSAGE) && 1803 (*field.Type != descriptor.FieldDescriptorProto_TYPE_GROUP) && 1804 !gogoproto.IsCustomType(field) { 1805 return false 1806 } 1807 return true 1808} 1809 1810// TypeName is the printed name appropriate for an item. If the object is in the current file, 1811// TypeName drops the package name and underscores the rest. 1812// Otherwise the object is from another package; and the result is the underscored 1813// package name followed by the item name. 1814// The result always has an initial capital. 1815func (g *Generator) TypeName(obj Object) string { 1816 return g.DefaultPackageName(obj) + CamelCaseSlice(obj.TypeName()) 1817} 1818 1819// GoType returns a string representing the type name, and the wire type 1820func (g *Generator) GoType(message *Descriptor, field *descriptor.FieldDescriptorProto) (typ string, wire string) { 1821 // TODO: Options. 1822 switch *field.Type { 1823 case descriptor.FieldDescriptorProto_TYPE_DOUBLE: 1824 typ, wire = "float64", "fixed64" 1825 case descriptor.FieldDescriptorProto_TYPE_FLOAT: 1826 typ, wire = "float32", "fixed32" 1827 case descriptor.FieldDescriptorProto_TYPE_INT64: 1828 typ, wire = "int64", "varint" 1829 case descriptor.FieldDescriptorProto_TYPE_UINT64: 1830 typ, wire = "uint64", "varint" 1831 case descriptor.FieldDescriptorProto_TYPE_INT32: 1832 typ, wire = "int32", "varint" 1833 case descriptor.FieldDescriptorProto_TYPE_UINT32: 1834 typ, wire = "uint32", "varint" 1835 case descriptor.FieldDescriptorProto_TYPE_FIXED64: 1836 typ, wire = "uint64", "fixed64" 1837 case descriptor.FieldDescriptorProto_TYPE_FIXED32: 1838 typ, wire = "uint32", "fixed32" 1839 case descriptor.FieldDescriptorProto_TYPE_BOOL: 1840 typ, wire = "bool", "varint" 1841 case descriptor.FieldDescriptorProto_TYPE_STRING: 1842 typ, wire = "string", "bytes" 1843 case descriptor.FieldDescriptorProto_TYPE_GROUP: 1844 desc := g.ObjectNamed(field.GetTypeName()) 1845 typ, wire = g.TypeName(desc), "group" 1846 case descriptor.FieldDescriptorProto_TYPE_MESSAGE: 1847 desc := g.ObjectNamed(field.GetTypeName()) 1848 typ, wire = g.TypeName(desc), "bytes" 1849 case descriptor.FieldDescriptorProto_TYPE_BYTES: 1850 typ, wire = "[]byte", "bytes" 1851 case descriptor.FieldDescriptorProto_TYPE_ENUM: 1852 desc := g.ObjectNamed(field.GetTypeName()) 1853 typ, wire = g.TypeName(desc), "varint" 1854 case descriptor.FieldDescriptorProto_TYPE_SFIXED32: 1855 typ, wire = "int32", "fixed32" 1856 case descriptor.FieldDescriptorProto_TYPE_SFIXED64: 1857 typ, wire = "int64", "fixed64" 1858 case descriptor.FieldDescriptorProto_TYPE_SINT32: 1859 typ, wire = "int32", "zigzag32" 1860 case descriptor.FieldDescriptorProto_TYPE_SINT64: 1861 typ, wire = "int64", "zigzag64" 1862 default: 1863 g.Fail("unknown type for", field.GetName()) 1864 } 1865 switch { 1866 case gogoproto.IsCustomType(field) && gogoproto.IsCastType(field): 1867 g.Fail(field.GetName() + " cannot be custom type and cast type") 1868 case gogoproto.IsCustomType(field): 1869 var packageName string 1870 var err error 1871 packageName, typ, err = getCustomType(field) 1872 if err != nil { 1873 g.Fail(err.Error()) 1874 } 1875 if len(packageName) > 0 { 1876 g.customImports = append(g.customImports, packageName) 1877 } 1878 case gogoproto.IsCastType(field): 1879 var packageName string 1880 var err error 1881 packageName, typ, err = getCastType(field) 1882 if err != nil { 1883 g.Fail(err.Error()) 1884 } 1885 if len(packageName) > 0 { 1886 g.customImports = append(g.customImports, packageName) 1887 } 1888 case gogoproto.IsStdTime(field): 1889 g.customImports = append(g.customImports, "time") 1890 typ = "time.Time" 1891 case gogoproto.IsStdDuration(field): 1892 g.customImports = append(g.customImports, "time") 1893 typ = "time.Duration" 1894 case gogoproto.IsStdDouble(field): 1895 typ = "float64" 1896 case gogoproto.IsStdFloat(field): 1897 typ = "float32" 1898 case gogoproto.IsStdInt64(field): 1899 typ = "int64" 1900 case gogoproto.IsStdUInt64(field): 1901 typ = "uint64" 1902 case gogoproto.IsStdInt32(field): 1903 typ = "int32" 1904 case gogoproto.IsStdUInt32(field): 1905 typ = "uint32" 1906 case gogoproto.IsStdBool(field): 1907 typ = "bool" 1908 case gogoproto.IsStdString(field): 1909 typ = "string" 1910 case gogoproto.IsStdBytes(field): 1911 typ = "[]byte" 1912 } 1913 if needsStar(field, g.file.proto3 && field.Extendee == nil, message != nil && message.allowOneof()) { 1914 typ = "*" + typ 1915 } 1916 if isRepeated(field) { 1917 typ = "[]" + typ 1918 } 1919 return 1920} 1921 1922// GoMapDescriptor is a full description of the map output struct. 1923type GoMapDescriptor struct { 1924 GoType string 1925 1926 KeyField *descriptor.FieldDescriptorProto 1927 KeyAliasField *descriptor.FieldDescriptorProto 1928 KeyTag string 1929 1930 ValueField *descriptor.FieldDescriptorProto 1931 ValueAliasField *descriptor.FieldDescriptorProto 1932 ValueTag string 1933} 1934 1935func (g *Generator) GoMapType(d *Descriptor, field *descriptor.FieldDescriptorProto) *GoMapDescriptor { 1936 if d == nil { 1937 byName := g.ObjectNamed(field.GetTypeName()) 1938 desc, ok := byName.(*Descriptor) 1939 if byName == nil || !ok || !desc.GetOptions().GetMapEntry() { 1940 g.Fail(fmt.Sprintf("field %s is not a map", field.GetTypeName())) 1941 return nil 1942 } 1943 d = desc 1944 } 1945 1946 m := &GoMapDescriptor{ 1947 KeyField: d.Field[0], 1948 ValueField: d.Field[1], 1949 } 1950 1951 // Figure out the Go types and tags for the key and value types. 1952 m.KeyAliasField, m.ValueAliasField = g.GetMapKeyField(field, m.KeyField), g.GetMapValueField(field, m.ValueField) 1953 keyType, keyWire := g.GoType(d, m.KeyAliasField) 1954 valType, valWire := g.GoType(d, m.ValueAliasField) 1955 1956 m.KeyTag, m.ValueTag = g.goTag(d, m.KeyField, keyWire), g.goTag(d, m.ValueField, valWire) 1957 1958 if gogoproto.IsCastType(field) { 1959 var packageName string 1960 var err error 1961 packageName, typ, err := getCastType(field) 1962 if err != nil { 1963 g.Fail(err.Error()) 1964 } 1965 if len(packageName) > 0 { 1966 g.customImports = append(g.customImports, packageName) 1967 } 1968 m.GoType = typ 1969 return m 1970 } 1971 1972 // We don't use stars, except for message-typed values. 1973 // Message and enum types are the only two possibly foreign types used in maps, 1974 // so record their use. They are not permitted as map keys. 1975 keyType = strings.TrimPrefix(keyType, "*") 1976 switch *m.ValueAliasField.Type { 1977 case descriptor.FieldDescriptorProto_TYPE_ENUM: 1978 valType = strings.TrimPrefix(valType, "*") 1979 g.RecordTypeUse(m.ValueAliasField.GetTypeName()) 1980 case descriptor.FieldDescriptorProto_TYPE_MESSAGE: 1981 if !gogoproto.IsNullable(m.ValueAliasField) { 1982 valType = strings.TrimPrefix(valType, "*") 1983 } 1984 if !gogoproto.IsStdType(m.ValueAliasField) && !gogoproto.IsCustomType(field) && !gogoproto.IsCastType(field) { 1985 g.RecordTypeUse(m.ValueAliasField.GetTypeName()) 1986 } 1987 default: 1988 if gogoproto.IsCustomType(m.ValueAliasField) { 1989 if !gogoproto.IsNullable(m.ValueAliasField) { 1990 valType = strings.TrimPrefix(valType, "*") 1991 } 1992 if !gogoproto.IsStdType(field) { 1993 g.RecordTypeUse(m.ValueAliasField.GetTypeName()) 1994 } 1995 } else { 1996 valType = strings.TrimPrefix(valType, "*") 1997 } 1998 } 1999 2000 m.GoType = fmt.Sprintf("map[%s]%s", keyType, valType) 2001 return m 2002} 2003 2004func (g *Generator) RecordTypeUse(t string) { 2005 if _, ok := g.typeNameToObject[t]; ok { 2006 // Call ObjectNamed to get the true object to record the use. 2007 obj := g.ObjectNamed(t) 2008 g.usedPackages[obj.GoImportPath()] = true 2009 } 2010} 2011 2012// Method names that may be generated. Fields with these names get an 2013// underscore appended. Any change to this set is a potential incompatible 2014// API change because it changes generated field names. 2015var methodNames = [...]string{ 2016 "Reset", 2017 "String", 2018 "ProtoMessage", 2019 "Marshal", 2020 "Unmarshal", 2021 "ExtensionRangeArray", 2022 "ExtensionMap", 2023 "Descriptor", 2024 "MarshalTo", 2025 "Equal", 2026 "VerboseEqual", 2027 "GoString", 2028 "ProtoSize", 2029} 2030 2031// Names of messages in the `google.protobuf` package for which 2032// we will generate XXX_WellKnownType methods. 2033var wellKnownTypes = map[string]bool{ 2034 "Any": true, 2035 "Duration": true, 2036 "Empty": true, 2037 "Struct": true, 2038 "Timestamp": true, 2039 2040 "Value": true, 2041 "ListValue": true, 2042 "DoubleValue": true, 2043 "FloatValue": true, 2044 "Int64Value": true, 2045 "UInt64Value": true, 2046 "Int32Value": true, 2047 "UInt32Value": true, 2048 "BoolValue": true, 2049 "StringValue": true, 2050 "BytesValue": true, 2051} 2052 2053// getterDefault finds the default value for the field to return from a getter, 2054// regardless of if it's a built in default or explicit from the source. Returns e.g. "nil", `""`, "Default_MessageType_FieldName" 2055func (g *Generator) getterDefault(field *descriptor.FieldDescriptorProto, goMessageType, goTypeName string) string { 2056 if isRepeated(field) { 2057 return "nil" 2058 } 2059 if def := field.GetDefaultValue(); def != "" { 2060 defaultConstant := g.defaultConstantName(goMessageType, field.GetName()) 2061 if *field.Type != descriptor.FieldDescriptorProto_TYPE_BYTES { 2062 return defaultConstant 2063 } 2064 return "append([]byte(nil), " + defaultConstant + "...)" 2065 } 2066 switch *field.Type { 2067 case descriptor.FieldDescriptorProto_TYPE_GROUP, 2068 descriptor.FieldDescriptorProto_TYPE_MESSAGE: 2069 if field.OneofIndex != nil { 2070 return "nil" 2071 } else { 2072 if !gogoproto.IsNullable(field) && (gogoproto.IsStdDuration(field) || 2073 gogoproto.IsStdDouble(field) || gogoproto.IsStdFloat(field) || 2074 gogoproto.IsStdInt64(field) || gogoproto.IsStdUInt64(field) || 2075 gogoproto.IsStdInt32(field) || gogoproto.IsStdUInt32(field)) { 2076 return "0" 2077 } else if !gogoproto.IsNullable(field) && gogoproto.IsStdBool(field) { 2078 return "false" 2079 } else if !gogoproto.IsNullable(field) && gogoproto.IsStdString(field) { 2080 return "\"\"" 2081 } else if !gogoproto.IsNullable(field) && gogoproto.IsStdBytes(field) { 2082 return "[]byte{}" 2083 } else { 2084 return goTypeName + "{}" 2085 } 2086 } 2087 case descriptor.FieldDescriptorProto_TYPE_BOOL: 2088 return "false" 2089 case descriptor.FieldDescriptorProto_TYPE_STRING: 2090 return "\"\"" 2091 case descriptor.FieldDescriptorProto_TYPE_BYTES: 2092 // This is only possible for oneof fields. 2093 return "nil" 2094 case descriptor.FieldDescriptorProto_TYPE_ENUM: 2095 // The default default for an enum is the first value in the enum, 2096 // not zero. 2097 obj := g.ObjectNamed(field.GetTypeName()) 2098 var enum *EnumDescriptor 2099 if id, ok := obj.(*ImportedDescriptor); ok { 2100 // The enum type has been publicly imported. 2101 enum, _ = id.o.(*EnumDescriptor) 2102 } else { 2103 enum, _ = obj.(*EnumDescriptor) 2104 } 2105 if enum == nil { 2106 log.Printf("don't know how to generate getter for %s", field.GetName()) 2107 return "nil" 2108 } 2109 if len(enum.Value) == 0 { 2110 return "0 // empty enum" 2111 } else { 2112 first := enum.Value[0].GetName() 2113 if gogoproto.IsEnumValueCustomName(enum.Value[0]) { 2114 first = gogoproto.GetEnumValueCustomName(enum.Value[0]) 2115 } 2116 if gogoproto.EnabledGoEnumPrefix(enum.file.FileDescriptorProto, enum.EnumDescriptorProto) { 2117 return g.DefaultPackageName(obj) + enum.prefix() + first 2118 } else { 2119 return g.DefaultPackageName(obj) + first 2120 } 2121 } 2122 default: 2123 return "0" 2124 } 2125} 2126 2127// defaultConstantName builds the name of the default constant from the message 2128// type name and the untouched field name, e.g. "Default_MessageType_FieldName" 2129func (g *Generator) defaultConstantName(goMessageType, protoFieldName string) string { 2130 return "Default_" + goMessageType + "_" + CamelCase(protoFieldName) 2131} 2132 2133// The different types of fields in a message and how to actually print them 2134// Most of the logic for generateMessage is in the methods of these types. 2135// 2136// Note that the content of the field is irrelevant, a simpleField can contain 2137// anything from a scalar to a group (which is just a message). 2138// 2139// Extension fields (and message sets) are however handled separately. 2140// 2141// simpleField - a field that is neiter weak nor oneof, possibly repeated 2142// oneofField - field containing list of subfields: 2143// - oneofSubField - a field within the oneof 2144 2145// msgCtx contais the context for the generator functions. 2146type msgCtx struct { 2147 goName string // Go struct name of the message, e.g. MessageName 2148 message *Descriptor // The descriptor for the message 2149} 2150 2151// fieldCommon contains data common to all types of fields. 2152type fieldCommon struct { 2153 goName string // Go name of field, e.g. "FieldName" or "Descriptor_" 2154 protoName string // Name of field in proto language, e.g. "field_name" or "descriptor" 2155 getterName string // Name of the getter, e.g. "GetFieldName" or "GetDescriptor_" 2156 goType string // The Go type as a string, e.g. "*int32" or "*OtherMessage" 2157 tags string // The tag string/annotation for the type, e.g. `protobuf:"varint,8,opt,name=region_id,json=regionId"` 2158 fullPath string // The full path of the field as used by Annotate etc, e.g. "4,0,2,0" 2159 protoField *descriptor.FieldDescriptorProto // gogo. Passing in the fieldDescriptor in for gogo options. TODO rethink this, we might need a better way of getting options. 2160} 2161 2162// getProtoName gets the proto name of a field, e.g. "field_name" or "descriptor". 2163func (f *fieldCommon) getProtoName() string { 2164 return f.protoName 2165} 2166 2167// getGoType returns the go type of the field as a string, e.g. "*int32". 2168func (f *fieldCommon) getGoType() string { 2169 return f.goType 2170} 2171 2172// simpleField is not weak, not a oneof, not an extension. Can be required, optional or repeated. 2173type simpleField struct { 2174 fieldCommon 2175 protoTypeName string // Proto type name, empty if primitive, e.g. ".google.protobuf.Duration" 2176 protoType descriptor.FieldDescriptorProto_Type // Actual type enum value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64 2177 deprecated string // Deprecation comment, if any, e.g. "// Deprecated: Do not use." 2178 getterDef string // Default for getters, e.g. "nil", `""` or "Default_MessageType_FieldName" 2179 protoDef string // Default value as defined in the proto file, e.g "yoshi" or "5" 2180 comment string // The full comment for the field, e.g. "// Useful information" 2181} 2182 2183// decl prints the declaration of the field in the struct (if any). 2184func (f *simpleField) decl(g *Generator, mc *msgCtx) { 2185 g.P(f.comment, Annotate(mc.message.file, f.fullPath, f.goName), "\t", f.goType, "\t`", f.tags, "`", f.deprecated) 2186} 2187 2188// getter prints the getter for the field. 2189func (f *simpleField) getter(g *Generator, mc *msgCtx) { 2190 oneof := false 2191 if !oneof && !gogoproto.HasGoGetters(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2192 return 2193 } 2194 if gogoproto.IsEmbed(f.protoField) || gogoproto.IsCustomType(f.protoField) { 2195 return 2196 } 2197 if f.deprecated != "" { 2198 g.P(f.deprecated) 2199 } 2200 g.generateGet(mc, f.protoField, f.protoType, false, f.goName, f.goType, "", "", f.fullPath, f.getterName, f.getterDef) 2201} 2202 2203// setter prints the setter method of the field. 2204func (f *simpleField) setter(g *Generator, mc *msgCtx) { 2205 // No setter for regular fields yet 2206} 2207 2208// getProtoDef returns the default value explicitly stated in the proto file, e.g "yoshi" or "5". 2209func (f *simpleField) getProtoDef() string { 2210 return f.protoDef 2211} 2212 2213// getProtoTypeName returns the protobuf type name for the field as returned by field.GetTypeName(), e.g. ".google.protobuf.Duration". 2214func (f *simpleField) getProtoTypeName() string { 2215 return f.protoTypeName 2216} 2217 2218// getProtoType returns the *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64. 2219func (f *simpleField) getProtoType() descriptor.FieldDescriptorProto_Type { 2220 return f.protoType 2221} 2222 2223func (f *simpleField) getProto() *descriptor.FieldDescriptorProto { 2224 return f.protoField 2225} 2226 2227// oneofSubFields are kept slize held by each oneofField. They do not appear in the top level slize of fields for the message. 2228type oneofSubField struct { 2229 fieldCommon 2230 protoTypeName string // Proto type name, empty if primitive, e.g. ".google.protobuf.Duration" 2231 protoType descriptor.FieldDescriptorProto_Type // Actual type enum value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64 2232 oneofTypeName string // Type name of the enclosing struct, e.g. "MessageName_FieldName" 2233 fieldNumber int // Actual field number, as defined in proto, e.g. 12 2234 getterDef string // Default for getters, e.g. "nil", `""` or "Default_MessageType_FieldName" 2235 protoDef string // Default value as defined in the proto file, e.g "yoshi" or "5" 2236 wireType string // gogo. We can set this on creation, instead of using a function 2237} 2238 2239// wireTypeName returns a textual wire type, needed for oneof sub fields in generated code. 2240func (f *oneofSubField) wireTypeName() string { 2241 return f.wireType 2242} 2243 2244// typedNil prints a nil casted to the pointer to this field. 2245// - for XXX_OneofFuncs 2246func (f *oneofSubField) typedNil(g *Generator) { 2247 g.P("(*", f.oneofTypeName, ")(nil),") 2248} 2249 2250// marshalCase prints the case matching this oneof subfield in the marshalling code. 2251func (f *oneofSubField) marshalCase(g *Generator, mc *msgCtx) { 2252 // if field.OneofIndex == nil || int(*field.OneofIndex) != oi { 2253 // continue 2254 // } 2255 g.P("case *", f.oneofTypeName, ":") 2256 var pre, post string 2257 val := "x." + f.goName // overridden for TYPE_BOOL 2258 canFail := false // only TYPE_MESSAGE and TYPE_GROUP can fail 2259 switch f.protoType { 2260 case descriptor.FieldDescriptorProto_TYPE_DOUBLE: 2261 pre = "b.EncodeFixed64(" + g.Pkg["math"] + ".Float64bits(" 2262 post = "))" 2263 case descriptor.FieldDescriptorProto_TYPE_FLOAT: 2264 pre = "b.EncodeFixed32(uint64(" + g.Pkg["math"] + ".Float32bits(" 2265 post = ")))" 2266 case descriptor.FieldDescriptorProto_TYPE_INT64, 2267 descriptor.FieldDescriptorProto_TYPE_UINT64: 2268 pre, post = "b.EncodeVarint(uint64(", "))" 2269 case descriptor.FieldDescriptorProto_TYPE_INT32, 2270 descriptor.FieldDescriptorProto_TYPE_UINT32, 2271 descriptor.FieldDescriptorProto_TYPE_ENUM: 2272 pre, post = "b.EncodeVarint(uint64(", "))" 2273 case descriptor.FieldDescriptorProto_TYPE_FIXED64, 2274 descriptor.FieldDescriptorProto_TYPE_SFIXED64: 2275 pre, post = "b.EncodeFixed64(uint64(", "))" 2276 case descriptor.FieldDescriptorProto_TYPE_FIXED32, 2277 descriptor.FieldDescriptorProto_TYPE_SFIXED32: 2278 pre, post = "b.EncodeFixed32(uint64(", "))" 2279 case descriptor.FieldDescriptorProto_TYPE_BOOL: 2280 // bool needs special handling. 2281 g.P("t := uint64(0)") 2282 g.P("if ", val, " { t = 1 }") 2283 val = "t" 2284 pre, post = "b.EncodeVarint(", ")" 2285 case descriptor.FieldDescriptorProto_TYPE_STRING: 2286 pre, post = "b.EncodeStringBytes(", ")" 2287 case descriptor.FieldDescriptorProto_TYPE_GROUP: 2288 pre, post = "b.Marshal(", ")" 2289 canFail = true 2290 case descriptor.FieldDescriptorProto_TYPE_MESSAGE: 2291 pre, post = "b.EncodeMessage(", ")" 2292 canFail = true 2293 case descriptor.FieldDescriptorProto_TYPE_BYTES: 2294 pre, post = "b.EncodeRawBytes(", ")" 2295 case descriptor.FieldDescriptorProto_TYPE_SINT32: 2296 pre, post = "b.EncodeZigzag32(uint64(", "))" 2297 case descriptor.FieldDescriptorProto_TYPE_SINT64: 2298 pre, post = "b.EncodeZigzag64(uint64(", "))" 2299 default: 2300 g.Fail("unhandled oneof field type ", f.protoType.String()) 2301 } 2302 g.P("_ = b.EncodeVarint(", f.fieldNumber, "<<3|", g.Pkg["proto"], ".", f.wireTypeName(), ")") 2303 if f.protoType == descriptor.FieldDescriptorProto_TYPE_BYTES && gogoproto.IsCustomType(f.protoField) { 2304 g.P(`dAtA, err := `, val, `.Marshal()`) 2305 g.P(`if err != nil {`) 2306 g.In() 2307 g.P(`return err`) 2308 g.Out() 2309 g.P(`}`) 2310 val = "dAtA" 2311 } else if gogoproto.IsStdType(f.protoField) { 2312 pkg := g.useTypes() 2313 ptr := "" 2314 fnname := "" 2315 if gogoproto.IsNullable(f.protoField) { 2316 ptr = "*" 2317 } 2318 if gogoproto.IsStdTime(f.protoField) { 2319 fnname = "Time" 2320 } else if gogoproto.IsStdDuration(f.protoField) { 2321 fnname = "Duration" 2322 } else if gogoproto.IsStdDouble(f.protoField) { 2323 fnname = "Double" 2324 } else if gogoproto.IsStdFloat(f.protoField) { 2325 fnname = "Float" 2326 } else if gogoproto.IsStdInt64(f.protoField) { 2327 fnname = "Int64" 2328 } else if gogoproto.IsStdUInt64(f.protoField) { 2329 fnname = "UInt64" 2330 } else if gogoproto.IsStdInt32(f.protoField) { 2331 fnname = "Int32" 2332 } else if gogoproto.IsStdUInt32(f.protoField) { 2333 fnname = "UInt32" 2334 } else if gogoproto.IsStdBool(f.protoField) { 2335 fnname = "Bool" 2336 } else if gogoproto.IsStdString(f.protoField) { 2337 fnname = "String" 2338 } else if gogoproto.IsStdBytes(f.protoField) { 2339 fnname = "Bytes" 2340 } else { 2341 panic("internal error") 2342 } 2343 g.P(`dAtA, err := `, pkg, `.Std`, fnname, `Marshal(`, ptr, val, `)`) 2344 g.P(`if err != nil {`) 2345 g.In() 2346 g.P(`return err`) 2347 g.Out() 2348 g.P(`}`) 2349 val = "dAtA" 2350 pre, post = "b.EncodeRawBytes(", ")" 2351 } 2352 if !canFail { 2353 g.P("_ = ", pre, val, post) 2354 } else { 2355 g.P("if err := ", pre, val, post, "; err != nil {") 2356 g.In() 2357 g.P("return err") 2358 g.Out() 2359 g.P("}") 2360 } 2361 if f.protoType == descriptor.FieldDescriptorProto_TYPE_GROUP { 2362 g.P("_ = b.EncodeVarint(", f.fieldNumber, "<<3|", g.Pkg["proto"], ".WireEndGroup)") 2363 } 2364} 2365 2366// unmarshalCase prints the case matching this oneof subfield in the unmarshalling code. 2367func (f *oneofSubField) unmarshalCase(g *Generator, origOneofName string, oneofName string, mc *msgCtx) { 2368 // if field.OneofIndex == nil { 2369 // continue 2370 // } 2371 g.P("case ", f.fieldNumber, ": // ", origOneofName, ".", f.getProtoName()) 2372 g.P("if wire != ", g.Pkg["proto"], ".", f.wireTypeName(), " {") 2373 g.P("return true, ", g.Pkg["proto"], ".ErrInternalBadWireType") 2374 g.P("}") 2375 lhs := "x, err" // overridden for TYPE_MESSAGE and TYPE_GROUP 2376 var dec, cast, cast2 string 2377 switch f.protoType { 2378 case descriptor.FieldDescriptorProto_TYPE_DOUBLE: 2379 dec, cast = "b.DecodeFixed64()", g.Pkg["math"]+".Float64frombits" 2380 case descriptor.FieldDescriptorProto_TYPE_FLOAT: 2381 dec, cast, cast2 = "b.DecodeFixed32()", "uint32", g.Pkg["math"]+".Float32frombits" 2382 case descriptor.FieldDescriptorProto_TYPE_INT64: 2383 dec, cast = "b.DecodeVarint()", "int64" 2384 case descriptor.FieldDescriptorProto_TYPE_UINT64: 2385 dec = "b.DecodeVarint()" 2386 case descriptor.FieldDescriptorProto_TYPE_INT32: 2387 dec, cast = "b.DecodeVarint()", "int32" 2388 case descriptor.FieldDescriptorProto_TYPE_FIXED64: 2389 dec = "b.DecodeFixed64()" 2390 case descriptor.FieldDescriptorProto_TYPE_FIXED32: 2391 dec, cast = "b.DecodeFixed32()", "uint32" 2392 case descriptor.FieldDescriptorProto_TYPE_BOOL: 2393 dec = "b.DecodeVarint()" 2394 // handled specially below 2395 case descriptor.FieldDescriptorProto_TYPE_STRING: 2396 dec = "b.DecodeStringBytes()" 2397 case descriptor.FieldDescriptorProto_TYPE_GROUP: 2398 g.P("msg := new(", f.goType[1:], ")") // drop star 2399 lhs = "err" 2400 dec = "b.DecodeGroup(msg)" 2401 // handled specially below 2402 case descriptor.FieldDescriptorProto_TYPE_MESSAGE: 2403 if gogoproto.IsStdType(f.protoField) { 2404 dec = "b.DecodeRawBytes(true)" 2405 } else { 2406 g.P("msg := new(", f.goType[1:], ")") // drop star 2407 lhs = "err" 2408 dec = "b.DecodeMessage(msg)" 2409 } 2410 // handled specially below 2411 case descriptor.FieldDescriptorProto_TYPE_BYTES: 2412 dec = "b.DecodeRawBytes(true)" 2413 case descriptor.FieldDescriptorProto_TYPE_UINT32: 2414 dec, cast = "b.DecodeVarint()", "uint32" 2415 case descriptor.FieldDescriptorProto_TYPE_ENUM: 2416 dec, cast = "b.DecodeVarint()", f.goType 2417 case descriptor.FieldDescriptorProto_TYPE_SFIXED32: 2418 dec, cast = "b.DecodeFixed32()", "int32" 2419 case descriptor.FieldDescriptorProto_TYPE_SFIXED64: 2420 dec, cast = "b.DecodeFixed64()", "int64" 2421 case descriptor.FieldDescriptorProto_TYPE_SINT32: 2422 dec, cast = "b.DecodeZigzag32()", "int32" 2423 case descriptor.FieldDescriptorProto_TYPE_SINT64: 2424 dec, cast = "b.DecodeZigzag64()", "int64" 2425 default: 2426 g.Fail("unhandled oneof field type ", f.protoType.String()) 2427 } 2428 g.P(lhs, " := ", dec) 2429 val := "x" 2430 if f.protoType == descriptor.FieldDescriptorProto_TYPE_BYTES && gogoproto.IsCustomType(f.protoField) { 2431 g.P(`if err != nil {`) 2432 g.In() 2433 g.P(`return true, err`) 2434 g.Out() 2435 g.P(`}`) 2436 _, ctyp, err := GetCustomType(f.protoField) 2437 if err != nil { 2438 panic(err) 2439 } 2440 g.P(`var cc `, ctyp) 2441 g.P(`c := &cc`) 2442 g.P(`err = c.Unmarshal(`, val, `)`) 2443 val = "*c" 2444 } else if gogoproto.IsStdType(f.protoField) { 2445 var stdtype string 2446 var fnname string 2447 if gogoproto.IsStdTime(f.protoField) { 2448 stdtype = "time.Time" 2449 fnname = "Time" 2450 } else if gogoproto.IsStdDuration(f.protoField) { 2451 stdtype = "time.Duration" 2452 fnname = "Duration" 2453 } else if gogoproto.IsStdDouble(f.protoField) { 2454 stdtype = "float64" 2455 fnname = "Double" 2456 } else if gogoproto.IsStdFloat(f.protoField) { 2457 stdtype = "float32" 2458 fnname = "Float" 2459 } else if gogoproto.IsStdInt64(f.protoField) { 2460 stdtype = "int64" 2461 fnname = "Int64" 2462 } else if gogoproto.IsStdUInt64(f.protoField) { 2463 stdtype = "uint64" 2464 fnname = "UInt64" 2465 } else if gogoproto.IsStdInt32(f.protoField) { 2466 stdtype = "int32" 2467 fnname = "Int32" 2468 } else if gogoproto.IsStdUInt32(f.protoField) { 2469 stdtype = "uint32" 2470 fnname = "UInt32" 2471 } else if gogoproto.IsStdBool(f.protoField) { 2472 stdtype = "bool" 2473 fnname = "Bool" 2474 } else if gogoproto.IsStdString(f.protoField) { 2475 stdtype = "string" 2476 fnname = "String" 2477 } else if gogoproto.IsStdBytes(f.protoField) { 2478 stdtype = "[]byte" 2479 fnname = "Bytes" 2480 } else { 2481 panic("internal error") 2482 } 2483 2484 pkg := g.useTypes() 2485 g.P(`if err != nil {`) 2486 g.In() 2487 g.P(`return true, err`) 2488 g.Out() 2489 g.P(`}`) 2490 g.P(`c := new(`, stdtype, `)`) 2491 g.P(`if err2 := `, pkg, `.Std`, fnname, `Unmarshal(c, `, val, `); err2 != nil {`) 2492 g.In() 2493 g.P(`return true, err`) 2494 g.Out() 2495 g.P(`}`) 2496 val = "c" 2497 } 2498 if cast != "" { 2499 val = cast + "(" + val + ")" 2500 } 2501 if cast2 != "" { 2502 val = cast2 + "(" + val + ")" 2503 } 2504 switch f.protoType { 2505 case descriptor.FieldDescriptorProto_TYPE_BOOL: 2506 val += " != 0" 2507 case descriptor.FieldDescriptorProto_TYPE_GROUP, 2508 descriptor.FieldDescriptorProto_TYPE_MESSAGE: 2509 if !gogoproto.IsStdType(f.protoField) { 2510 val = "msg" 2511 } 2512 } 2513 if gogoproto.IsCastType(f.protoField) { 2514 _, typ, err := getCastType(f.protoField) 2515 if err != nil { 2516 g.Fail(err.Error()) 2517 } 2518 val = typ + "(" + val + ")" 2519 } 2520 g.P("m.", oneofName, " = &", f.oneofTypeName, "{", val, "}") 2521 g.P("return true, err") 2522} 2523 2524// sizerCase prints the case matching this oneof subfield in the sizer code. 2525func (f *oneofSubField) sizerCase(g *Generator) { 2526 // if field.OneofIndex == nil || int(*field.OneofIndex) != oi { 2527 // continue 2528 // } 2529 g.P("case *", f.oneofTypeName, ":") 2530 val := "x." + f.goName 2531 var varint, fixed string 2532 switch f.protoType { 2533 case descriptor.FieldDescriptorProto_TYPE_DOUBLE: 2534 fixed = "8" 2535 case descriptor.FieldDescriptorProto_TYPE_FLOAT: 2536 fixed = "4" 2537 case descriptor.FieldDescriptorProto_TYPE_INT64, 2538 descriptor.FieldDescriptorProto_TYPE_UINT64, 2539 descriptor.FieldDescriptorProto_TYPE_INT32, 2540 descriptor.FieldDescriptorProto_TYPE_UINT32, 2541 descriptor.FieldDescriptorProto_TYPE_ENUM: 2542 varint = val 2543 case descriptor.FieldDescriptorProto_TYPE_FIXED64, 2544 descriptor.FieldDescriptorProto_TYPE_SFIXED64: 2545 fixed = "8" 2546 case descriptor.FieldDescriptorProto_TYPE_FIXED32, 2547 descriptor.FieldDescriptorProto_TYPE_SFIXED32: 2548 fixed = "4" 2549 case descriptor.FieldDescriptorProto_TYPE_BOOL: 2550 fixed = "1" 2551 case descriptor.FieldDescriptorProto_TYPE_STRING: 2552 fixed = "len(" + val + ")" 2553 varint = fixed 2554 case descriptor.FieldDescriptorProto_TYPE_GROUP: 2555 fixed = g.Pkg["proto"] + ".Size(" + val + ")" 2556 case descriptor.FieldDescriptorProto_TYPE_MESSAGE: 2557 if gogoproto.IsStdType(f.protoField) { 2558 pkg := g.useTypes() 2559 if gogoproto.IsNullable(f.protoField) { 2560 val = "*" + val 2561 } 2562 if gogoproto.IsStdTime(f.protoField) { 2563 g.P("s := ", pkg, ".SizeOfStdTime(", val, ")") 2564 } else if gogoproto.IsStdDuration(f.protoField) { 2565 g.P("s := ", pkg, ".SizeOfStdDuration(", val, ")") 2566 } else if gogoproto.IsStdDouble(f.protoField) { 2567 g.P("s := ", pkg, ".SizeOfStdDouble(", val, ")") 2568 } else if gogoproto.IsStdFloat(f.protoField) { 2569 g.P("s := ", pkg, ".SizeOfStdFloat(", val, ")") 2570 } else if gogoproto.IsStdInt64(f.protoField) { 2571 g.P("s := ", pkg, ".SizeOfStdInt64(", val, ")") 2572 } else if gogoproto.IsStdUInt64(f.protoField) { 2573 g.P("s := ", pkg, ".SizeOfStdUInt64(", val, ")") 2574 } else if gogoproto.IsStdInt32(f.protoField) { 2575 g.P("s := ", pkg, ".SizeOfStdInt32(", val, ")") 2576 } else if gogoproto.IsStdUInt32(f.protoField) { 2577 g.P("s := ", pkg, ".SizeOfStdUInt32(", val, ")") 2578 } else if gogoproto.IsStdBool(f.protoField) { 2579 g.P("s := ", pkg, ".SizeOfStdBool(", val, ")") 2580 } else if gogoproto.IsStdString(f.protoField) { 2581 g.P("s := ", pkg, ".SizeOfStdString(", val, ")") 2582 } else if gogoproto.IsStdBytes(f.protoField) { 2583 g.P("s := ", pkg, ".SizeOfStdBytes(", val, ")") 2584 } else { 2585 panic("internal error") 2586 } 2587 } else { 2588 g.P("s := ", g.Pkg["proto"], ".Size(", val, ")") 2589 } 2590 fixed = "s" 2591 varint = fixed 2592 case descriptor.FieldDescriptorProto_TYPE_BYTES: 2593 if gogoproto.IsCustomType(f.protoField) { 2594 fixed = val + ".Size()" 2595 } else { 2596 fixed = "len(" + val + ")" 2597 } 2598 varint = fixed 2599 case descriptor.FieldDescriptorProto_TYPE_SINT32: 2600 varint = "(uint32(" + val + ") << 1) ^ uint32((int32(" + val + ") >> 31))" 2601 case descriptor.FieldDescriptorProto_TYPE_SINT64: 2602 varint = "uint64(" + val + " << 1) ^ uint64((int64(" + val + ") >> 63))" 2603 default: 2604 g.Fail("unhandled oneof field type ", f.protoType.String()) 2605 } 2606 // Tag and wire varint is known statically, 2607 // so don't generate code for that part of the size computation. 2608 tagAndWireSize := proto.SizeVarint(uint64(f.fieldNumber << 3)) // wire doesn't affect varint size 2609 g.P("n += ", tagAndWireSize, " // tag and wire") 2610 if varint != "" { 2611 g.P("n += ", g.Pkg["proto"], ".SizeVarint(uint64(", varint, "))") 2612 } 2613 if fixed != "" { 2614 g.P("n += ", fixed) 2615 } 2616 if f.protoType == descriptor.FieldDescriptorProto_TYPE_GROUP { 2617 g.P("n += ", tagAndWireSize, " // tag and wire") 2618 } 2619} 2620 2621// getProtoDef returns the default value explicitly stated in the proto file, e.g "yoshi" or "5". 2622func (f *oneofSubField) getProtoDef() string { 2623 return f.protoDef 2624} 2625 2626// getProtoTypeName returns the protobuf type name for the field as returned by field.GetTypeName(), e.g. ".google.protobuf.Duration". 2627func (f *oneofSubField) getProtoTypeName() string { 2628 return f.protoTypeName 2629} 2630 2631// getProtoType returns the *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64. 2632func (f *oneofSubField) getProtoType() descriptor.FieldDescriptorProto_Type { 2633 return f.protoType 2634} 2635 2636func (f *oneofSubField) getProto() *descriptor.FieldDescriptorProto { 2637 return f.protoField 2638} 2639 2640// oneofField represents the oneof on top level. 2641// The alternative fields within the oneof are represented by oneofSubField. 2642type oneofField struct { 2643 fieldCommon 2644 subFields []*oneofSubField // All the possible oneof fields 2645 comment string // The full comment for the field, e.g. "// Types that are valid to be assigned to MyOneof:\n\\" 2646} 2647 2648// decl prints the declaration of the field in the struct (if any). 2649func (f *oneofField) decl(g *Generator, mc *msgCtx) { 2650 comment := f.comment 2651 for _, sf := range f.subFields { 2652 comment += "//\t*" + sf.oneofTypeName + "\n" 2653 } 2654 g.P(comment, Annotate(mc.message.file, f.fullPath, f.goName), " ", f.goType, " `", f.tags, "`") 2655} 2656 2657// getter for a oneof field will print additional discriminators and interfaces for the oneof, 2658// also it prints all the getters for the sub fields. 2659func (f *oneofField) getter(g *Generator, mc *msgCtx) { 2660 oneof := true 2661 if !oneof && !gogoproto.HasGoGetters(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2662 return 2663 } 2664 2665 for _, of := range f.subFields { 2666 if gogoproto.IsEmbed(of.protoField) || gogoproto.IsCustomType(of.protoField) { 2667 continue 2668 } 2669 g.generateGet(mc, of.protoField, of.protoType, true, of.goName, of.goType, f.goName, of.oneofTypeName, of.fullPath, of.getterName, of.getterDef) 2670 } 2671} 2672 2673// setter prints the setter method of the field. 2674func (f *oneofField) setter(g *Generator, mc *msgCtx) { 2675 // No setters for oneof yet 2676} 2677 2678// topLevelField interface implemented by all types of fields on the top level (not oneofSubField). 2679type topLevelField interface { 2680 decl(g *Generator, mc *msgCtx) // print declaration within the struct 2681 getter(g *Generator, mc *msgCtx) // print getter 2682 setter(g *Generator, mc *msgCtx) // print setter if applicable 2683} 2684 2685// defField interface implemented by all types of fields that can have defaults (not oneofField, but instead oneofSubField). 2686type defField interface { 2687 getProtoDef() string // default value explicitly stated in the proto file, e.g "yoshi" or "5" 2688 getProtoName() string // proto name of a field, e.g. "field_name" or "descriptor" 2689 getGoType() string // go type of the field as a string, e.g. "*int32" 2690 getProtoTypeName() string // protobuf type name for the field, e.g. ".google.protobuf.Duration" 2691 getProtoType() descriptor.FieldDescriptorProto_Type // *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64 2692 getProto() *descriptor.FieldDescriptorProto 2693} 2694 2695// generateDefaultConstants adds constants for default values if needed, which is only if the default value is. 2696// explicit in the proto. 2697func (g *Generator) generateDefaultConstants(mc *msgCtx, topLevelFields []topLevelField) { 2698 // Collect fields that can have defaults 2699 dFields := []defField{} 2700 for _, pf := range topLevelFields { 2701 if f, ok := pf.(*oneofField); ok { 2702 for _, osf := range f.subFields { 2703 dFields = append(dFields, osf) 2704 } 2705 continue 2706 } 2707 dFields = append(dFields, pf.(defField)) 2708 } 2709 for _, df := range dFields { 2710 def := df.getProtoDef() 2711 if def == "" { 2712 continue 2713 } 2714 if !gogoproto.IsNullable(df.getProto()) { 2715 g.Fail("illegal default value: ", df.getProtoName(), " in ", mc.message.GetName(), " is not nullable and is thus not allowed to have a default value") 2716 } 2717 fieldname := g.defaultConstantName(mc.goName, df.getProtoName()) 2718 typename := df.getGoType() 2719 if typename[0] == '*' { 2720 typename = typename[1:] 2721 } 2722 kind := "const " 2723 switch { 2724 case typename == "bool": 2725 case typename == "string": 2726 def = strconv.Quote(def) 2727 case typename == "[]byte": 2728 def = "[]byte(" + strconv.Quote(unescape(def)) + ")" 2729 kind = "var " 2730 case def == "inf", def == "-inf", def == "nan": 2731 // These names are known to, and defined by, the protocol language. 2732 switch def { 2733 case "inf": 2734 def = "math.Inf(1)" 2735 case "-inf": 2736 def = "math.Inf(-1)" 2737 case "nan": 2738 def = "math.NaN()" 2739 } 2740 if df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_FLOAT { 2741 def = "float32(" + def + ")" 2742 } 2743 kind = "var " 2744 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_ENUM: 2745 // Must be an enum. Need to construct the prefixed name. 2746 obj := g.ObjectNamed(df.getProtoTypeName()) 2747 var enum *EnumDescriptor 2748 if id, ok := obj.(*ImportedDescriptor); ok { 2749 // The enum type has been publicly imported. 2750 enum, _ = id.o.(*EnumDescriptor) 2751 } else { 2752 enum, _ = obj.(*EnumDescriptor) 2753 } 2754 if enum == nil { 2755 log.Printf("don't know how to generate constant for %s", fieldname) 2756 continue 2757 } 2758 2759 // hunt down the actual enum corresponding to the default 2760 var enumValue *descriptor.EnumValueDescriptorProto 2761 for _, ev := range enum.Value { 2762 if def == ev.GetName() { 2763 enumValue = ev 2764 } 2765 } 2766 2767 if enumValue != nil { 2768 if gogoproto.IsEnumValueCustomName(enumValue) { 2769 def = gogoproto.GetEnumValueCustomName(enumValue) 2770 } 2771 } else { 2772 g.Fail(fmt.Sprintf("could not resolve default enum value for %v.%v", g.DefaultPackageName(obj), def)) 2773 } 2774 2775 if gogoproto.EnabledGoEnumPrefix(enum.file.FileDescriptorProto, enum.EnumDescriptorProto) { 2776 def = g.DefaultPackageName(obj) + enum.prefix() + def 2777 } else { 2778 def = g.DefaultPackageName(obj) + def 2779 } 2780 } 2781 g.P(kind, fieldname, " ", typename, " = ", def) 2782 g.file.addExport(mc.message, constOrVarSymbol{fieldname, kind, ""}) 2783 } 2784 g.P() 2785} 2786 2787// generateGet generates the getter for both the simpleField and oneofSubField. 2788// We did not want to duplicate the code since it is quite intricate so we came 2789// up with this ugly method. At least the logic is in one place. This can be reworked. 2790func (g *Generator) generateGet(mc *msgCtx, protoField *descriptor.FieldDescriptorProto, protoType descriptor.FieldDescriptorProto_Type, 2791 oneof bool, fname, tname, uname, oneoftname, fullpath, gname, def string) { 2792 star := "" 2793 if (protoType != descriptor.FieldDescriptorProto_TYPE_MESSAGE) && 2794 (protoType != descriptor.FieldDescriptorProto_TYPE_GROUP) && 2795 needsStar(protoField, g.file.proto3, mc.message != nil && mc.message.allowOneof()) && tname[0] == '*' { 2796 tname = tname[1:] 2797 star = "*" 2798 } 2799 typeDefaultIsNil := false // whether this field type's default value is a literal nil unless specified 2800 switch protoType { 2801 case descriptor.FieldDescriptorProto_TYPE_BYTES: 2802 typeDefaultIsNil = def == "nil" 2803 case descriptor.FieldDescriptorProto_TYPE_GROUP, descriptor.FieldDescriptorProto_TYPE_MESSAGE: 2804 typeDefaultIsNil = gogoproto.IsNullable(protoField) 2805 } 2806 if isRepeated(protoField) { 2807 typeDefaultIsNil = true 2808 } 2809 g.P("func (m *", mc.goName, ") ", Annotate(mc.message.file, fullpath, gname), "() "+tname+" {") 2810 if !oneof && typeDefaultIsNil { 2811 // A bytes field with no explicit default needs less generated code, 2812 // as does a message or group field, or a repeated field. 2813 g.P("if m != nil {") 2814 g.In() 2815 g.P("return m." + fname) 2816 g.Out() 2817 g.P("}") 2818 g.P("return nil") 2819 g.Out() 2820 g.P("}") 2821 g.P() 2822 return 2823 } 2824 if !gogoproto.IsNullable(protoField) { 2825 g.P("if m != nil {") 2826 g.In() 2827 g.P("return m." + fname) 2828 g.Out() 2829 g.P("}") 2830 } else if !oneof { 2831 if mc.message.proto3() { 2832 g.P("if m != nil {") 2833 } else { 2834 g.P("if m != nil && m." + fname + " != nil {") 2835 } 2836 g.In() 2837 g.P("return " + star + "m." + fname) 2838 g.Out() 2839 g.P("}") 2840 } else { 2841 uname := uname 2842 tname := oneoftname 2843 g.P("if x, ok := m.Get", uname, "().(*", tname, "); ok {") 2844 g.P("return x.", fname) 2845 g.P("}") 2846 } 2847 g.P("return ", def) 2848 g.Out() 2849 g.P("}") 2850 g.P() 2851} 2852 2853// generateInternalStructFields just adds the XXX_<something> fields to the message struct. 2854func (g *Generator) generateInternalStructFields(mc *msgCtx, topLevelFields []topLevelField) { 2855 if gogoproto.HasUnkeyed(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2856 g.P("XXX_NoUnkeyedLiteral\tstruct{} `json:\"-\"`") // prevent unkeyed struct literals 2857 } 2858 if len(mc.message.ExtensionRange) > 0 { 2859 if gogoproto.HasExtensionsMap(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2860 messageset := "" 2861 if opts := mc.message.Options; opts != nil && opts.GetMessageSetWireFormat() { 2862 messageset = "protobuf_messageset:\"1\" " 2863 } 2864 g.P(g.Pkg["proto"], ".XXX_InternalExtensions `", messageset, "json:\"-\"`") 2865 } else { 2866 g.P("XXX_extensions\t\t[]byte `protobuf:\"bytes,0,opt\" json:\"-\"`") 2867 } 2868 } 2869 if gogoproto.HasUnrecognized(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2870 g.P("XXX_unrecognized\t[]byte `json:\"-\"`") 2871 } 2872 if gogoproto.HasSizecache(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2873 g.P("XXX_sizecache\tint32 `json:\"-\"`") 2874 } 2875} 2876 2877// generateOneofFuncs adds all the utility functions for oneof, including marshalling, unmarshalling and sizer. 2878func (g *Generator) generateOneofFuncs(mc *msgCtx, topLevelFields []topLevelField) { 2879 ofields := []*oneofField{} 2880 for _, f := range topLevelFields { 2881 if o, ok := f.(*oneofField); ok { 2882 ofields = append(ofields, o) 2883 } 2884 } 2885 if len(ofields) == 0 { 2886 return 2887 } 2888 enc := "_" + mc.goName + "_OneofMarshaler" 2889 dec := "_" + mc.goName + "_OneofUnmarshaler" 2890 size := "_" + mc.goName + "_OneofSizer" 2891 encSig := "(msg " + g.Pkg["proto"] + ".Message, b *" + g.Pkg["proto"] + ".Buffer) error" 2892 decSig := "(msg " + g.Pkg["proto"] + ".Message, tag, wire int, b *" + g.Pkg["proto"] + ".Buffer) (bool, error)" 2893 sizeSig := "(msg " + g.Pkg["proto"] + ".Message) (n int)" 2894 2895 // OneofFuncs 2896 g.P("// XXX_OneofFuncs is for the internal use of the proto package.") 2897 g.P("func (*", mc.goName, ") XXX_OneofFuncs() (func", encSig, ", func", decSig, ", func", sizeSig, ", []interface{}) {") 2898 g.P("return ", enc, ", ", dec, ", ", size, ", []interface{}{") 2899 for _, of := range ofields { 2900 for _, sf := range of.subFields { 2901 sf.typedNil(g) 2902 } 2903 } 2904 g.P("}") 2905 g.P("}") 2906 g.P() 2907 2908 // marshaler 2909 g.P("func ", enc, encSig, " {") 2910 g.P("m := msg.(*", mc.goName, ")") 2911 for _, of := range ofields { 2912 g.P("// ", of.getProtoName()) 2913 g.P("switch x := m.", of.goName, ".(type) {") 2914 for _, sf := range of.subFields { 2915 sf.marshalCase(g, mc) 2916 } 2917 g.P("case nil:") 2918 g.P("default: return ", g.Pkg["fmt"], `.Errorf("`, mc.goName, ".", of.goName, ` has unexpected type %T", x)`) 2919 g.P("}") 2920 } 2921 g.P("return nil") 2922 g.P("}") 2923 g.P() 2924 2925 // unmarshaler 2926 g.P("func ", dec, decSig, " {") 2927 g.P("m := msg.(*", mc.goName, ")") 2928 g.P("switch tag {") 2929 for _, of := range ofields { 2930 for _, sf := range of.subFields { 2931 sf.unmarshalCase(g, of.getProtoName(), of.goName, mc) 2932 } 2933 } 2934 g.P("default: return false, nil") 2935 g.P("}") 2936 g.P("}") 2937 g.P() 2938 2939 // sizer 2940 g.P("func ", size, sizeSig, " {") 2941 g.P("m := msg.(*", mc.goName, ")") 2942 for _, of := range ofields { 2943 g.P("// ", of.getProtoName()) 2944 g.P("switch x := m.", of.goName, ".(type) {") 2945 for _, sf := range of.subFields { 2946 // also fills in field.wire 2947 sf.sizerCase(g) 2948 } 2949 g.P("case nil:") 2950 g.P("default:") 2951 g.P("panic(", g.Pkg["fmt"], ".Sprintf(\"proto: unexpected type %T in oneof\", x))") 2952 g.P("}") 2953 } 2954 g.P("return n") 2955 g.P("}") 2956 g.P() 2957} 2958 2959func (g *Generator) generateOneofDecls(mc *msgCtx, topLevelFields []topLevelField) { 2960 ofields := []*oneofField{} 2961 for _, f := range topLevelFields { 2962 if o, ok := f.(*oneofField); ok { 2963 ofields = append(ofields, o) 2964 } 2965 } 2966 if len(ofields) == 0 { 2967 return 2968 } 2969 // Oneof per-field types, discriminants and getters. 2970 // Generate unexported named types for the discriminant interfaces. 2971 // We shouldn't have to do this, but there was (~19 Aug 2015) a compiler/linker bug 2972 // that was triggered by using anonymous interfaces here. 2973 // TODO: Revisit this and consider reverting back to anonymous interfaces. 2974 // for oi := range message.OneofDecl { 2975 for _, of := range ofields { 2976 dname := of.goType 2977 g.P("type ", dname, " interface {") 2978 g.In() 2979 g.P(dname, "()") 2980 if gogoproto.HasEqual(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2981 g.P(`Equal(interface{}) bool`) 2982 } 2983 if gogoproto.HasVerboseEqual(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2984 g.P(`VerboseEqual(interface{}) error`) 2985 } 2986 if gogoproto.IsMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) || 2987 gogoproto.IsUnsafeMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) || 2988 gogoproto.IsStableMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2989 g.P(`MarshalTo([]byte) (int, error)`) 2990 } 2991 if gogoproto.IsSizer(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2992 g.P(`Size() int`) 2993 } 2994 if gogoproto.IsProtoSizer(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 2995 g.P(`ProtoSize() int`) 2996 } 2997 g.Out() 2998 g.P("}") 2999 } 3000 g.P() 3001 for _, of := range ofields { 3002 for i, sf := range of.subFields { 3003 _, wiretype := g.GoType(mc.message, sf.protoField) 3004 tag := "protobuf:" + g.goTag(mc.message, sf.protoField, wiretype) 3005 fieldFullPath := fmt.Sprintf("%s,%d,%d", mc.message.path, messageFieldPath, i) 3006 g.P("type ", Annotate(mc.message.file, fieldFullPath, sf.oneofTypeName), " struct{ ", Annotate(mc.message.file, fieldFullPath, sf.goName), " ", sf.goType, " `", tag, "` }") 3007 if !gogoproto.IsStdType(sf.protoField) && !gogoproto.IsCustomType(sf.protoField) && !gogoproto.IsCastType(sf.protoField) { 3008 g.RecordTypeUse(sf.protoField.GetTypeName()) 3009 } 3010 } 3011 } 3012 g.P() 3013 for _, of := range ofields { 3014 for _, sf := range of.subFields { 3015 g.P("func (*", sf.oneofTypeName, ") ", of.goType, "() {}") 3016 } 3017 } 3018 g.P() 3019 for _, of := range ofields { 3020 fname := of.goName 3021 g.P("func (m *", mc.goName, ") Get", fname, "() ", of.goType, " {") 3022 g.P("if m != nil { return m.", fname, " }") 3023 g.P("return nil") 3024 g.P("}") 3025 } 3026 g.P() 3027} 3028 3029// generateMessageStruct adds the actual struct with it's members (but not methods) to the output. 3030func (g *Generator) generateMessageStruct(mc *msgCtx, topLevelFields []topLevelField) { 3031 comments := g.PrintComments(mc.message.path) 3032 3033 // Guarantee deprecation comments appear after user-provided comments. 3034 if mc.message.GetOptions().GetDeprecated() { 3035 if comments { 3036 // Convention: Separate deprecation comments from original 3037 // comments with an empty line. 3038 g.P("//") 3039 } 3040 g.P(deprecationComment) 3041 } 3042 g.P("type ", Annotate(mc.message.file, mc.message.path, mc.goName), " struct {") 3043 for _, pf := range topLevelFields { 3044 pf.decl(g, mc) 3045 } 3046 g.generateInternalStructFields(mc, topLevelFields) 3047 g.P("}") 3048} 3049 3050// generateGetters adds getters for all fields, including oneofs and weak fields when applicable. 3051func (g *Generator) generateGetters(mc *msgCtx, topLevelFields []topLevelField) { 3052 for _, pf := range topLevelFields { 3053 pf.getter(g, mc) 3054 3055 } 3056} 3057 3058// generateSetters add setters for all fields, including oneofs and weak fields when applicable. 3059func (g *Generator) generateSetters(mc *msgCtx, topLevelFields []topLevelField) { 3060 for _, pf := range topLevelFields { 3061 pf.setter(g, mc) 3062 } 3063} 3064 3065// generateCommonMethods adds methods to the message that are not on a per field basis. 3066func (g *Generator) generateCommonMethods(mc *msgCtx) { 3067 // Reset, String and ProtoMessage methods. 3068 g.P("func (m *", mc.goName, ") Reset() { *m = ", mc.goName, "{} }") 3069 if gogoproto.EnabledGoStringer(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 3070 g.P("func (m *", mc.goName, ") String() string { return ", g.Pkg["proto"], ".CompactTextString(m) }") 3071 } 3072 g.P("func (*", mc.goName, ") ProtoMessage() {}") 3073 var indexes []string 3074 for m := mc.message; m != nil; m = m.parent { 3075 indexes = append([]string{strconv.Itoa(m.index)}, indexes...) 3076 } 3077 g.P("func (*", mc.goName, ") Descriptor() ([]byte, []int) {") 3078 g.P("return ", g.file.VarName(), ", []int{", strings.Join(indexes, ", "), "}") 3079 g.P("}") 3080 // TODO: Revisit the decision to use a XXX_WellKnownType method 3081 // if we change proto.MessageName to work with multiple equivalents. 3082 if mc.message.file.GetPackage() == "google.protobuf" && wellKnownTypes[mc.message.GetName()] { 3083 g.P("func (*", mc.goName, `) XXX_WellKnownType() string { return "`, mc.message.GetName(), `" }`) 3084 } 3085 3086 // Extension support methods 3087 if len(mc.message.ExtensionRange) > 0 { 3088 // message_set_wire_format only makes sense when extensions are defined. 3089 if opts := mc.message.Options; opts != nil && opts.GetMessageSetWireFormat() { 3090 // isMessageSet = true 3091 g.P() 3092 g.P("func (m *", mc.goName, ") MarshalJSON() ([]byte, error) {") 3093 g.In() 3094 g.P("return ", g.Pkg["proto"], ".MarshalMessageSetJSON(&m.XXX_InternalExtensions)") 3095 g.Out() 3096 g.P("}") 3097 g.P("func (m *", mc.goName, ") UnmarshalJSON(buf []byte) error {") 3098 g.In() 3099 g.P("return ", g.Pkg["proto"], ".UnmarshalMessageSetJSON(buf, &m.XXX_InternalExtensions)") 3100 g.Out() 3101 g.P("}") 3102 } 3103 3104 g.P() 3105 g.P("var extRange_", mc.goName, " = []", g.Pkg["proto"], ".ExtensionRange{") 3106 g.In() 3107 for _, r := range mc.message.ExtensionRange { 3108 end := fmt.Sprint(*r.End - 1) // make range inclusive on both ends 3109 g.P("{Start: ", r.Start, ", End: ", end, "},") 3110 } 3111 g.Out() 3112 g.P("}") 3113 g.P("func (*", mc.goName, ") ExtensionRangeArray() []", g.Pkg["proto"], ".ExtensionRange {") 3114 g.In() 3115 g.P("return extRange_", mc.goName) 3116 g.Out() 3117 g.P("}") 3118 if !gogoproto.HasExtensionsMap(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 3119 g.P("func (m *", mc.goName, ") GetExtensions() *[]byte {") 3120 g.In() 3121 g.P("if m.XXX_extensions == nil {") 3122 g.In() 3123 g.P("m.XXX_extensions = make([]byte, 0)") 3124 g.Out() 3125 g.P("}") 3126 g.P("return &m.XXX_extensions") 3127 g.Out() 3128 g.P("}") 3129 } 3130 } 3131 3132 // TODO: It does not scale to keep adding another method for every 3133 // operation on protos that we want to switch over to using the 3134 // table-driven approach. Instead, we should only add a single method 3135 // that allows getting access to the *InternalMessageInfo struct and then 3136 // calling Unmarshal, Marshal, Merge, Size, and Discard directly on that. 3137 3138 // Wrapper for table-driven marshaling and unmarshaling. 3139 g.P("func (m *", mc.goName, ") XXX_Unmarshal(b []byte) error {") 3140 g.In() 3141 if gogoproto.IsUnmarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 3142 g.P("return m.Unmarshal(b)") 3143 } else { 3144 g.P("return xxx_messageInfo_", mc.goName, ".Unmarshal(m, b)") 3145 } 3146 g.Out() 3147 g.P("}") 3148 3149 g.P("func (m *", mc.goName, ") XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {") 3150 g.In() 3151 if gogoproto.IsMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) || 3152 gogoproto.IsUnsafeMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 3153 if gogoproto.IsStableMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 3154 g.P("b = b[:cap(b)]") 3155 g.P("n, err := m.MarshalTo(b)") 3156 g.P("if err != nil {") 3157 g.In() 3158 g.P("return nil, err") 3159 g.Out() 3160 g.P("}") 3161 g.P("return b[:n], nil") 3162 } else { 3163 g.P("if deterministic {") 3164 g.In() 3165 g.P("return xxx_messageInfo_", mc.goName, ".Marshal(b, m, deterministic)") 3166 g.P("} else {") 3167 g.In() 3168 g.P("b = b[:cap(b)]") 3169 g.P("n, err := m.MarshalTo(b)") 3170 g.P("if err != nil {") 3171 g.In() 3172 g.P("return nil, err") 3173 g.Out() 3174 g.P("}") 3175 g.Out() 3176 g.P("return b[:n], nil") 3177 g.Out() 3178 g.P("}") 3179 } 3180 } else { 3181 g.P("return xxx_messageInfo_", mc.goName, ".Marshal(b, m, deterministic)") 3182 } 3183 g.Out() 3184 g.P("}") 3185 3186 g.P("func (dst *", mc.goName, ") XXX_Merge(src ", g.Pkg["proto"], ".Message) {") 3187 g.In() 3188 g.P("xxx_messageInfo_", mc.goName, ".Merge(dst, src)") 3189 g.Out() 3190 g.P("}") 3191 3192 g.P("func (m *", mc.goName, ") XXX_Size() int {") // avoid name clash with "Size" field in some message 3193 g.In() 3194 if (gogoproto.IsMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) || 3195 gogoproto.IsUnsafeMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto)) && 3196 gogoproto.IsSizer(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 3197 g.P("return m.Size()") 3198 } else if (gogoproto.IsMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto) || 3199 gogoproto.IsUnsafeMarshaler(g.file.FileDescriptorProto, mc.message.DescriptorProto)) && 3200 gogoproto.IsProtoSizer(g.file.FileDescriptorProto, mc.message.DescriptorProto) { 3201 g.P("return m.ProtoSize()") 3202 } else { 3203 g.P("return xxx_messageInfo_", mc.goName, ".Size(m)") 3204 } 3205 g.Out() 3206 g.P("}") 3207 3208 g.P("func (m *", mc.goName, ") XXX_DiscardUnknown() {") 3209 g.In() 3210 g.P("xxx_messageInfo_", mc.goName, ".DiscardUnknown(m)") 3211 g.Out() 3212 g.P("}") 3213 3214 g.P("var xxx_messageInfo_", mc.goName, " ", g.Pkg["proto"], ".InternalMessageInfo") 3215} 3216 3217// Generate the type and default constant definitions for this Descriptor. 3218func (g *Generator) generateMessage(message *Descriptor) { 3219 topLevelFields := []topLevelField{} 3220 oFields := make(map[int32]*oneofField) 3221 // The full type name 3222 typeName := message.TypeName() 3223 // The full type name, CamelCased. 3224 goTypeName := CamelCaseSlice(typeName) 3225 3226 usedNames := make(map[string]bool) 3227 for _, n := range methodNames { 3228 usedNames[n] = true 3229 } 3230 if !gogoproto.IsProtoSizer(message.file.FileDescriptorProto, message.DescriptorProto) { 3231 usedNames["Size"] = true 3232 } 3233 3234 // allocNames finds a conflict-free variation of the given strings, 3235 // consistently mutating their suffixes. 3236 // It returns the same number of strings. 3237 allocNames := func(ns ...string) []string { 3238 Loop: 3239 for { 3240 for _, n := range ns { 3241 if usedNames[n] { 3242 for i := range ns { 3243 ns[i] += "_" 3244 } 3245 continue Loop 3246 } 3247 } 3248 for _, n := range ns { 3249 usedNames[n] = true 3250 } 3251 return ns 3252 } 3253 } 3254 3255 mapFieldTypes := make(map[*descriptor.FieldDescriptorProto]string) // keep track of the map fields to be added later 3256 3257 for i, field := range message.Field { 3258 // Allocate the getter and the field at the same time so name 3259 // collisions create field/method consistent names. 3260 // TODO: This allocation occurs based on the order of the fields 3261 // in the proto file, meaning that a change in the field 3262 // ordering can change generated Method/Field names. 3263 base := CamelCase(*field.Name) 3264 if gogoproto.IsCustomName(field) { 3265 base = gogoproto.GetCustomName(field) 3266 } 3267 ns := allocNames(base, "Get"+base) 3268 fieldName, fieldGetterName := ns[0], ns[1] 3269 3270 typename, wiretype := g.GoType(message, field) 3271 jsonName := *field.Name 3272 jsonTag := jsonName + ",omitempty" 3273 repeatedNativeType := (!field.IsMessage() && !gogoproto.IsCustomType(field) && field.IsRepeated()) 3274 if !gogoproto.IsNullable(field) && !repeatedNativeType { 3275 jsonTag = jsonName 3276 } 3277 gogoJsonTag := gogoproto.GetJsonTag(field) 3278 if gogoJsonTag != nil { 3279 jsonTag = *gogoJsonTag 3280 } 3281 gogoMoreTags := gogoproto.GetMoreTags(field) 3282 moreTags := "" 3283 if gogoMoreTags != nil { 3284 moreTags = " " + *gogoMoreTags 3285 } 3286 tag := fmt.Sprintf("protobuf:%s json:%q%s", g.goTag(message, field, wiretype), jsonTag, moreTags) 3287 if *field.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE && gogoproto.IsEmbed(field) { 3288 fieldName = "" 3289 } 3290 3291 oneof := field.OneofIndex != nil && message.allowOneof() 3292 if oneof && oFields[*field.OneofIndex] == nil { 3293 odp := message.OneofDecl[int(*field.OneofIndex)] 3294 base := CamelCase(odp.GetName()) 3295 names := allocNames(base, "Get"+base) 3296 fname, gname := names[0], names[1] 3297 3298 // This is the first field of a oneof we haven't seen before. 3299 // Generate the union field. 3300 oneofFullPath := fmt.Sprintf("%s,%d,%d", message.path, messageOneofPath, *field.OneofIndex) 3301 c, ok := g.makeComments(oneofFullPath) 3302 if ok { 3303 c += "\n//\n" 3304 } 3305 c += "// Types that are valid to be assigned to " + fname + ":\n" 3306 // Generate the rest of this comment later, 3307 // when we've computed any disambiguation. 3308 3309 dname := "is" + goTypeName + "_" + fname 3310 tag := `protobuf_oneof:"` + odp.GetName() + `"` 3311 of := oneofField{ 3312 fieldCommon: fieldCommon{ 3313 goName: fname, 3314 getterName: gname, 3315 goType: dname, 3316 tags: tag, 3317 protoName: odp.GetName(), 3318 fullPath: oneofFullPath, 3319 protoField: field, 3320 }, 3321 comment: c, 3322 } 3323 topLevelFields = append(topLevelFields, &of) 3324 oFields[*field.OneofIndex] = &of 3325 } 3326 3327 if *field.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE { 3328 desc := g.ObjectNamed(field.GetTypeName()) 3329 if d, ok := desc.(*Descriptor); ok && d.GetOptions().GetMapEntry() { 3330 m := g.GoMapType(d, field) 3331 typename = m.GoType 3332 mapFieldTypes[field] = typename // record for the getter generation 3333 3334 tag += fmt.Sprintf(" protobuf_key:%s protobuf_val:%s", m.KeyTag, m.ValueTag) 3335 } 3336 } 3337 goTyp, _ := g.GoType(message, field) 3338 dvalue := g.getterDefault(field, goTypeName, GoTypeToName(goTyp)) 3339 if oneof { 3340 tname := goTypeName + "_" + fieldName 3341 // It is possible for this to collide with a message or enum 3342 // nested in this message. Check for collisions. 3343 for { 3344 ok := true 3345 for _, desc := range message.nested { 3346 if CamelCaseSlice(desc.TypeName()) == tname { 3347 ok = false 3348 break 3349 } 3350 } 3351 for _, enum := range message.enums { 3352 if CamelCaseSlice(enum.TypeName()) == tname { 3353 ok = false 3354 break 3355 } 3356 } 3357 if !ok { 3358 tname += "_" 3359 continue 3360 } 3361 break 3362 } 3363 3364 oneofField := oFields[*field.OneofIndex] 3365 tag = "protobuf:" + g.goTag(message, field, wiretype) 3366 sf := oneofSubField{ 3367 fieldCommon: fieldCommon{ 3368 goName: fieldName, 3369 getterName: fieldGetterName, 3370 goType: typename, 3371 tags: tag, 3372 protoName: field.GetName(), 3373 fullPath: fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i), 3374 protoField: field, 3375 }, 3376 protoTypeName: field.GetTypeName(), 3377 fieldNumber: int(*field.Number), 3378 protoType: *field.Type, 3379 getterDef: dvalue, 3380 protoDef: field.GetDefaultValue(), 3381 oneofTypeName: tname, 3382 wireType: wireTypeName(field), 3383 } 3384 3385 oneofField.subFields = append(oneofField.subFields, &sf) 3386 if !gogoproto.IsStdType(field) && !gogoproto.IsCustomType(field) && !gogoproto.IsCastType(field) { 3387 g.RecordTypeUse(field.GetTypeName()) 3388 } 3389 continue 3390 } 3391 3392 fieldDeprecated := "" 3393 if field.GetOptions().GetDeprecated() { 3394 fieldDeprecated = deprecationComment 3395 } 3396 3397 fieldFullPath := fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i) 3398 c, ok := g.makeComments(fieldFullPath) 3399 if ok { 3400 c += "\n" 3401 } 3402 rf := simpleField{ 3403 fieldCommon: fieldCommon{ 3404 goName: fieldName, 3405 getterName: fieldGetterName, 3406 goType: typename, 3407 tags: tag, 3408 protoName: field.GetName(), 3409 fullPath: fieldFullPath, 3410 protoField: field, 3411 }, 3412 protoTypeName: field.GetTypeName(), 3413 protoType: *field.Type, 3414 deprecated: fieldDeprecated, 3415 getterDef: dvalue, 3416 protoDef: field.GetDefaultValue(), 3417 comment: c, 3418 } 3419 var pf topLevelField = &rf 3420 3421 topLevelFields = append(topLevelFields, pf) 3422 3423 if gogoproto.HasTypeDecl(message.file.FileDescriptorProto, message.DescriptorProto) { 3424 if !gogoproto.IsStdType(field) && !gogoproto.IsCustomType(field) && !gogoproto.IsCastType(field) { 3425 g.RecordTypeUse(field.GetTypeName()) 3426 } 3427 } else { 3428 // Even if the type does not need to be generated, we need to iterate 3429 // over all its fields to be able to mark as used any imported types 3430 // used by those fields. 3431 for _, mfield := range message.Field { 3432 if !gogoproto.IsStdType(mfield) && !gogoproto.IsCustomType(mfield) && !gogoproto.IsCastType(mfield) { 3433 g.RecordTypeUse(mfield.GetTypeName()) 3434 } 3435 } 3436 } 3437 } 3438 3439 mc := &msgCtx{ 3440 goName: goTypeName, 3441 message: message, 3442 } 3443 3444 if gogoproto.HasTypeDecl(message.file.FileDescriptorProto, message.DescriptorProto) { 3445 g.generateMessageStruct(mc, topLevelFields) 3446 g.P() 3447 } 3448 g.generateCommonMethods(mc) 3449 g.P() 3450 g.generateDefaultConstants(mc, topLevelFields) 3451 g.P() 3452 g.generateOneofDecls(mc, topLevelFields) 3453 g.P() 3454 g.generateGetters(mc, topLevelFields) 3455 g.P() 3456 g.generateSetters(mc, topLevelFields) 3457 g.P() 3458 g.generateOneofFuncs(mc, topLevelFields) 3459 g.P() 3460 3461 if !message.group { 3462 var oneofTypes []string 3463 for _, f := range topLevelFields { 3464 if of, ok := f.(*oneofField); ok { 3465 for _, osf := range of.subFields { 3466 oneofTypes = append(oneofTypes, osf.oneofTypeName) 3467 } 3468 } 3469 } 3470 3471 opts := message.Options 3472 ms := &messageSymbol{ 3473 sym: goTypeName, 3474 hasExtensions: len(message.ExtensionRange) > 0, 3475 isMessageSet: opts != nil && opts.GetMessageSetWireFormat(), 3476 oneofTypes: oneofTypes, 3477 } 3478 g.file.addExport(message, ms) 3479 } 3480 3481 for _, ext := range message.ext { 3482 g.generateExtension(ext) 3483 } 3484 3485 fullName := strings.Join(message.TypeName(), ".") 3486 if g.file.Package != nil { 3487 fullName = *g.file.Package + "." + fullName 3488 } 3489 3490 g.addInitf("%s.RegisterType((*%s)(nil), %q)", g.Pkg["proto"], goTypeName, fullName) 3491 if gogoproto.ImportsGoGoProto(g.file.FileDescriptorProto) && gogoproto.RegistersGolangProto(g.file.FileDescriptorProto) { 3492 g.addInitf("%s.RegisterType((*%s)(nil), %q)", g.Pkg["golang_proto"], goTypeName, fullName) 3493 } 3494 if gogoproto.HasMessageName(g.file.FileDescriptorProto, message.DescriptorProto) { 3495 g.P("func (*", goTypeName, ") XXX_MessageName() string {") 3496 g.In() 3497 g.P("return ", strconv.Quote(fullName)) 3498 g.Out() 3499 g.P("}") 3500 } 3501 // Register types for native map types. 3502 for _, k := range mapFieldKeys(mapFieldTypes) { 3503 fullName := strings.TrimPrefix(*k.TypeName, ".") 3504 g.addInitf("%s.RegisterMapType((%s)(nil), %q)", g.Pkg["proto"], mapFieldTypes[k], fullName) 3505 if gogoproto.ImportsGoGoProto(g.file.FileDescriptorProto) && gogoproto.RegistersGolangProto(g.file.FileDescriptorProto) { 3506 g.addInitf("%s.RegisterMapType((%s)(nil), %q)", g.Pkg["golang_proto"], mapFieldTypes[k], fullName) 3507 } 3508 } 3509} 3510 3511type byTypeName []*descriptor.FieldDescriptorProto 3512 3513func (a byTypeName) Len() int { return len(a) } 3514func (a byTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 3515func (a byTypeName) Less(i, j int) bool { return *a[i].TypeName < *a[j].TypeName } 3516 3517// mapFieldKeys returns the keys of m in a consistent order. 3518func mapFieldKeys(m map[*descriptor.FieldDescriptorProto]string) []*descriptor.FieldDescriptorProto { 3519 keys := make([]*descriptor.FieldDescriptorProto, 0, len(m)) 3520 for k := range m { 3521 keys = append(keys, k) 3522 } 3523 sort.Sort(byTypeName(keys)) 3524 return keys 3525} 3526 3527var escapeChars = [256]byte{ 3528 'a': '\a', 'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t', 'v': '\v', '\\': '\\', '"': '"', '\'': '\'', '?': '?', 3529} 3530 3531// unescape reverses the "C" escaping that protoc does for default values of bytes fields. 3532// It is best effort in that it effectively ignores malformed input. Seemingly invalid escape 3533// sequences are conveyed, unmodified, into the decoded result. 3534func unescape(s string) string { 3535 // NB: Sadly, we can't use strconv.Unquote because protoc will escape both 3536 // single and double quotes, but strconv.Unquote only allows one or the 3537 // other (based on actual surrounding quotes of its input argument). 3538 3539 var out []byte 3540 for len(s) > 0 { 3541 // regular character, or too short to be valid escape 3542 if s[0] != '\\' || len(s) < 2 { 3543 out = append(out, s[0]) 3544 s = s[1:] 3545 } else if c := escapeChars[s[1]]; c != 0 { 3546 // escape sequence 3547 out = append(out, c) 3548 s = s[2:] 3549 } else if s[1] == 'x' || s[1] == 'X' { 3550 // hex escape, e.g. "\x80 3551 if len(s) < 4 { 3552 // too short to be valid 3553 out = append(out, s[:2]...) 3554 s = s[2:] 3555 continue 3556 } 3557 v, err := strconv.ParseUint(s[2:4], 16, 8) 3558 if err != nil { 3559 out = append(out, s[:4]...) 3560 } else { 3561 out = append(out, byte(v)) 3562 } 3563 s = s[4:] 3564 } else if '0' <= s[1] && s[1] <= '7' { 3565 // octal escape, can vary from 1 to 3 octal digits; e.g., "\0" "\40" or "\164" 3566 // so consume up to 2 more bytes or up to end-of-string 3567 n := len(s[1:]) - len(strings.TrimLeft(s[1:], "01234567")) 3568 if n > 3 { 3569 n = 3 3570 } 3571 v, err := strconv.ParseUint(s[1:1+n], 8, 8) 3572 if err != nil { 3573 out = append(out, s[:1+n]...) 3574 } else { 3575 out = append(out, byte(v)) 3576 } 3577 s = s[1+n:] 3578 } else { 3579 // bad escape, just propagate the slash as-is 3580 out = append(out, s[0]) 3581 s = s[1:] 3582 } 3583 } 3584 3585 return string(out) 3586} 3587 3588func (g *Generator) generateExtension(ext *ExtensionDescriptor) { 3589 ccTypeName := ext.DescName() 3590 3591 extObj := g.ObjectNamed(*ext.Extendee) 3592 var extDesc *Descriptor 3593 if id, ok := extObj.(*ImportedDescriptor); ok { 3594 // This is extending a publicly imported message. 3595 // We need the underlying type for goTag. 3596 extDesc = id.o.(*Descriptor) 3597 } else { 3598 extDesc = extObj.(*Descriptor) 3599 } 3600 extendedType := "*" + g.TypeName(extObj) // always use the original 3601 field := ext.FieldDescriptorProto 3602 fieldType, wireType := g.GoType(ext.parent, field) 3603 tag := g.goTag(extDesc, field, wireType) 3604 g.RecordTypeUse(*ext.Extendee) 3605 if n := ext.FieldDescriptorProto.TypeName; n != nil { 3606 // foreign extension type 3607 g.RecordTypeUse(*n) 3608 } 3609 3610 typeName := ext.TypeName() 3611 3612 // Special case for proto2 message sets: If this extension is extending 3613 // proto2.bridge.MessageSet, and its final name component is "message_set_extension", 3614 // then drop that last component. 3615 // 3616 // TODO: This should be implemented in the text formatter rather than the generator. 3617 // In addition, the situation for when to apply this special case is implemented 3618 // differently in other languages: 3619 // https://github.com/google/protobuf/blob/aff10976/src/google/protobuf/text_format.cc#L1560 3620 mset := false 3621 if extDesc.GetOptions().GetMessageSetWireFormat() && typeName[len(typeName)-1] == "message_set_extension" { 3622 typeName = typeName[:len(typeName)-1] 3623 mset = true 3624 } 3625 3626 // For text formatting, the package must be exactly what the .proto file declares, 3627 // ignoring overrides such as the go_package option, and with no dot/underscore mapping. 3628 extName := strings.Join(typeName, ".") 3629 if g.file.Package != nil { 3630 extName = *g.file.Package + "." + extName 3631 } 3632 3633 g.P("var ", ccTypeName, " = &", g.Pkg["proto"], ".ExtensionDesc{") 3634 g.In() 3635 g.P("ExtendedType: (", extendedType, ")(nil),") 3636 g.P("ExtensionType: (", fieldType, ")(nil),") 3637 g.P("Field: ", field.Number, ",") 3638 g.P(`Name: "`, extName, `",`) 3639 g.P("Tag: ", tag, ",") 3640 g.P(`Filename: "`, g.file.GetName(), `",`) 3641 3642 g.Out() 3643 g.P("}") 3644 g.P() 3645 3646 if mset { 3647 // Generate a bit more code to register with message_set.go. 3648 g.addInitf("%s.RegisterMessageSetType((%s)(nil), %d, %q)", g.Pkg["proto"], fieldType, *field.Number, extName) 3649 if gogoproto.ImportsGoGoProto(g.file.FileDescriptorProto) && gogoproto.RegistersGolangProto(g.file.FileDescriptorProto) { 3650 g.addInitf("%s.RegisterMessageSetType((%s)(nil), %d, %q)", g.Pkg["golang_proto"], fieldType, *field.Number, extName) 3651 } 3652 } 3653 3654 g.file.addExport(ext, constOrVarSymbol{ccTypeName, "var", ""}) 3655} 3656 3657func (g *Generator) generateInitFunction() { 3658 for _, enum := range g.file.enum { 3659 g.generateEnumRegistration(enum) 3660 } 3661 for _, d := range g.file.desc { 3662 for _, ext := range d.ext { 3663 g.generateExtensionRegistration(ext) 3664 } 3665 } 3666 for _, ext := range g.file.ext { 3667 g.generateExtensionRegistration(ext) 3668 } 3669 if len(g.init) == 0 { 3670 return 3671 } 3672 g.P("func init() {") 3673 g.In() 3674 for _, l := range g.init { 3675 g.P(l) 3676 } 3677 g.Out() 3678 g.P("}") 3679 g.init = nil 3680} 3681 3682func (g *Generator) generateFileDescriptor(file *FileDescriptor) { 3683 // Make a copy and trim source_code_info data. 3684 // TODO: Trim this more when we know exactly what we need. 3685 pb := proto.Clone(file.FileDescriptorProto).(*descriptor.FileDescriptorProto) 3686 pb.SourceCodeInfo = nil 3687 3688 b, err := proto.Marshal(pb) 3689 if err != nil { 3690 g.Fail(err.Error()) 3691 } 3692 3693 var buf bytes.Buffer 3694 w, _ := gzip.NewWriterLevel(&buf, gzip.BestCompression) 3695 w.Write(b) 3696 w.Close() 3697 b = buf.Bytes() 3698 3699 v := file.VarName() 3700 g.P() 3701 g.P("func init() { ", g.Pkg["proto"], ".RegisterFile(", strconv.Quote(*file.Name), ", ", v, ") }") 3702 if gogoproto.ImportsGoGoProto(g.file.FileDescriptorProto) && gogoproto.RegistersGolangProto(g.file.FileDescriptorProto) { 3703 g.P("func init() { ", g.Pkg["golang_proto"], ".RegisterFile(", strconv.Quote(*file.Name), ", ", v, ") }") 3704 } 3705 g.P("var ", v, " = []byte{") 3706 g.In() 3707 g.P("// ", len(b), " bytes of a gzipped FileDescriptorProto") 3708 for len(b) > 0 { 3709 n := 16 3710 if n > len(b) { 3711 n = len(b) 3712 } 3713 3714 s := "" 3715 for _, c := range b[:n] { 3716 s += fmt.Sprintf("0x%02x,", c) 3717 } 3718 g.P(s) 3719 3720 b = b[n:] 3721 } 3722 g.Out() 3723 g.P("}") 3724} 3725 3726func (g *Generator) generateEnumRegistration(enum *EnumDescriptor) { 3727 // // We always print the full (proto-world) package name here. 3728 pkg := enum.File().GetPackage() 3729 if pkg != "" { 3730 pkg += "." 3731 } 3732 // The full type name 3733 typeName := enum.TypeName() 3734 // The full type name, CamelCased. 3735 ccTypeName := CamelCaseSlice(typeName) 3736 g.addInitf("%s.RegisterEnum(%q, %[3]s_name, %[3]s_value)", g.Pkg["proto"], pkg+ccTypeName, ccTypeName) 3737 if gogoproto.ImportsGoGoProto(g.file.FileDescriptorProto) && gogoproto.RegistersGolangProto(g.file.FileDescriptorProto) { 3738 g.addInitf("%s.RegisterEnum(%q, %[3]s_name, %[3]s_value)", g.Pkg["golang_proto"], pkg+ccTypeName, ccTypeName) 3739 } 3740} 3741 3742func (g *Generator) generateExtensionRegistration(ext *ExtensionDescriptor) { 3743 g.addInitf("%s.RegisterExtension(%s)", g.Pkg["proto"], ext.DescName()) 3744 if gogoproto.ImportsGoGoProto(g.file.FileDescriptorProto) && gogoproto.RegistersGolangProto(g.file.FileDescriptorProto) { 3745 g.addInitf("%s.RegisterExtension(%s)", g.Pkg["golang_proto"], ext.DescName()) 3746 } 3747} 3748 3749// And now lots of helper functions. 3750 3751// Is c an ASCII lower-case letter? 3752func isASCIILower(c byte) bool { 3753 return 'a' <= c && c <= 'z' 3754} 3755 3756// Is c an ASCII digit? 3757func isASCIIDigit(c byte) bool { 3758 return '0' <= c && c <= '9' 3759} 3760 3761// CamelCase returns the CamelCased name. 3762// If there is an interior underscore followed by a lower case letter, 3763// drop the underscore and convert the letter to upper case. 3764// There is a remote possibility of this rewrite causing a name collision, 3765// but it's so remote we're prepared to pretend it's nonexistent - since the 3766// C++ generator lowercases names, it's extremely unlikely to have two fields 3767// with different capitalizations. 3768// In short, _my_field_name_2 becomes XMyFieldName_2. 3769func CamelCase(s string) string { 3770 if s == "" { 3771 return "" 3772 } 3773 t := make([]byte, 0, 32) 3774 i := 0 3775 if s[0] == '_' { 3776 // Need a capital letter; drop the '_'. 3777 t = append(t, 'X') 3778 i++ 3779 } 3780 // Invariant: if the next letter is lower case, it must be converted 3781 // to upper case. 3782 // That is, we process a word at a time, where words are marked by _ or 3783 // upper case letter. Digits are treated as words. 3784 for ; i < len(s); i++ { 3785 c := s[i] 3786 if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) { 3787 continue // Skip the underscore in s. 3788 } 3789 if isASCIIDigit(c) { 3790 t = append(t, c) 3791 continue 3792 } 3793 // Assume we have a letter now - if not, it's a bogus identifier. 3794 // The next word is a sequence of characters that must start upper case. 3795 if isASCIILower(c) { 3796 c ^= ' ' // Make it a capital letter. 3797 } 3798 t = append(t, c) // Guaranteed not lower case. 3799 // Accept lower case sequence that follows. 3800 for i+1 < len(s) && isASCIILower(s[i+1]) { 3801 i++ 3802 t = append(t, s[i]) 3803 } 3804 } 3805 return string(t) 3806} 3807 3808// CamelCaseSlice is like CamelCase, but the argument is a slice of strings to 3809// be joined with "_". 3810func CamelCaseSlice(elem []string) string { return CamelCase(strings.Join(elem, "_")) } 3811 3812// dottedSlice turns a sliced name into a dotted name. 3813func dottedSlice(elem []string) string { return strings.Join(elem, ".") } 3814 3815// Is this field optional? 3816func isOptional(field *descriptor.FieldDescriptorProto) bool { 3817 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_OPTIONAL 3818} 3819 3820// Is this field required? 3821func isRequired(field *descriptor.FieldDescriptorProto) bool { 3822 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REQUIRED 3823} 3824 3825// Is this field repeated? 3826func isRepeated(field *descriptor.FieldDescriptorProto) bool { 3827 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED 3828} 3829 3830// Is this field a scalar numeric type? 3831func IsScalar(field *descriptor.FieldDescriptorProto) bool { 3832 if field.Type == nil { 3833 return false 3834 } 3835 switch *field.Type { 3836 case descriptor.FieldDescriptorProto_TYPE_DOUBLE, 3837 descriptor.FieldDescriptorProto_TYPE_FLOAT, 3838 descriptor.FieldDescriptorProto_TYPE_INT64, 3839 descriptor.FieldDescriptorProto_TYPE_UINT64, 3840 descriptor.FieldDescriptorProto_TYPE_INT32, 3841 descriptor.FieldDescriptorProto_TYPE_FIXED64, 3842 descriptor.FieldDescriptorProto_TYPE_FIXED32, 3843 descriptor.FieldDescriptorProto_TYPE_BOOL, 3844 descriptor.FieldDescriptorProto_TYPE_UINT32, 3845 descriptor.FieldDescriptorProto_TYPE_ENUM, 3846 descriptor.FieldDescriptorProto_TYPE_SFIXED32, 3847 descriptor.FieldDescriptorProto_TYPE_SFIXED64, 3848 descriptor.FieldDescriptorProto_TYPE_SINT32, 3849 descriptor.FieldDescriptorProto_TYPE_SINT64: 3850 return true 3851 default: 3852 return false 3853 } 3854} 3855 3856func wireTypeName(field *descriptor.FieldDescriptorProto) string { 3857 switch *field.Type { 3858 case descriptor.FieldDescriptorProto_TYPE_DOUBLE: 3859 return "WireFixed64" 3860 case descriptor.FieldDescriptorProto_TYPE_FLOAT: 3861 return "WireFixed32" 3862 case descriptor.FieldDescriptorProto_TYPE_INT64, 3863 descriptor.FieldDescriptorProto_TYPE_UINT64: 3864 return "WireVarint" 3865 case descriptor.FieldDescriptorProto_TYPE_INT32, 3866 descriptor.FieldDescriptorProto_TYPE_UINT32, 3867 descriptor.FieldDescriptorProto_TYPE_ENUM: 3868 return "WireVarint" 3869 case descriptor.FieldDescriptorProto_TYPE_FIXED64, 3870 descriptor.FieldDescriptorProto_TYPE_SFIXED64: 3871 return "WireFixed64" 3872 case descriptor.FieldDescriptorProto_TYPE_FIXED32, 3873 descriptor.FieldDescriptorProto_TYPE_SFIXED32: 3874 return "WireFixed32" 3875 case descriptor.FieldDescriptorProto_TYPE_BOOL: 3876 return "WireVarint" 3877 case descriptor.FieldDescriptorProto_TYPE_STRING: 3878 return "WireBytes" 3879 case descriptor.FieldDescriptorProto_TYPE_GROUP: 3880 return "WireStartGroup" 3881 case descriptor.FieldDescriptorProto_TYPE_MESSAGE: 3882 return "WireBytes" 3883 case descriptor.FieldDescriptorProto_TYPE_BYTES: 3884 return "WireBytes" 3885 case descriptor.FieldDescriptorProto_TYPE_SINT32: 3886 return "WireVarint" 3887 case descriptor.FieldDescriptorProto_TYPE_SINT64: 3888 return "WireVarint" 3889 default: 3890 return "WireVarint" 3891 } 3892} 3893 3894// badToUnderscore is the mapping function used to generate Go names from package names, 3895// which can be dotted in the input .proto file. It replaces non-identifier characters such as 3896// dot or dash with underscore. 3897func badToUnderscore(r rune) rune { 3898 if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' { 3899 return r 3900 } 3901 return '_' 3902} 3903 3904// baseName returns the last path element of the name, with the last dotted suffix removed. 3905func baseName(name string) string { 3906 // First, find the last element 3907 if i := strings.LastIndex(name, "/"); i >= 0 { 3908 name = name[i+1:] 3909 } 3910 // Now drop the suffix 3911 if i := strings.LastIndex(name, "."); i >= 0 { 3912 name = name[0:i] 3913 } 3914 return name 3915} 3916 3917// The SourceCodeInfo message describes the location of elements of a parsed 3918// .proto file by way of a "path", which is a sequence of integers that 3919// describe the route from a FileDescriptorProto to the relevant submessage. 3920// The path alternates between a field number of a repeated field, and an index 3921// into that repeated field. The constants below define the field numbers that 3922// are used. 3923// 3924// See descriptor.proto for more information about this. 3925const ( 3926 // tag numbers in FileDescriptorProto 3927 packagePath = 2 // package 3928 messagePath = 4 // message_type 3929 enumPath = 5 // enum_type 3930 // tag numbers in DescriptorProto 3931 messageFieldPath = 2 // field 3932 messageMessagePath = 3 // nested_type 3933 messageEnumPath = 4 // enum_type 3934 messageOneofPath = 8 // oneof_decl 3935 // tag numbers in EnumDescriptorProto 3936 enumValuePath = 2 // value 3937) 3938 3939var supportTypeAliases bool 3940 3941func init() { 3942 for _, tag := range build.Default.ReleaseTags { 3943 if tag == "go1.9" { 3944 supportTypeAliases = true 3945 return 3946 } 3947 } 3948} 3949