1// Go support for Protocol Buffers - Google's data interchange format 2// 3// Copyright 2010 The Go Authors. All rights reserved. 4// https://github.com/golang/protobuf 5// 6// Redistribution and use in source and binary forms, with or without 7// modification, are permitted provided that the following conditions are 8// met: 9// 10// * Redistributions of source code must retain the above copyright 11// notice, this list of conditions and the following disclaimer. 12// * Redistributions in binary form must reproduce the above 13// copyright notice, this list of conditions and the following disclaimer 14// in the documentation and/or other materials provided with the 15// distribution. 16// * Neither the name of Google Inc. nor the names of its 17// contributors may be used to endorse or promote products derived from 18// this software without specific prior written permission. 19// 20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 32/* 33 The code generator for the plugin for the Google protocol buffer compiler. 34 It generates Go code from the protocol buffer description files read by the 35 main routine. 36*/ 37package generator 38 39import ( 40 "bufio" 41 "bytes" 42 "compress/gzip" 43 "crypto/sha256" 44 "encoding/hex" 45 "fmt" 46 "go/ast" 47 "go/build" 48 "go/parser" 49 "go/printer" 50 "go/token" 51 "log" 52 "os" 53 "path" 54 "sort" 55 "strconv" 56 "strings" 57 "unicode" 58 "unicode/utf8" 59 60 "github.com/golang/protobuf/proto" 61 "github.com/golang/protobuf/protoc-gen-go/generator/internal/remap" 62 63 "github.com/golang/protobuf/protoc-gen-go/descriptor" 64 plugin "github.com/golang/protobuf/protoc-gen-go/plugin" 65) 66 67// generatedCodeVersion indicates a version of the generated code. 68// It is incremented whenever an incompatibility between the generated code and 69// proto package is introduced; the generated code references 70// a constant, proto.ProtoPackageIsVersionN (where N is generatedCodeVersion). 71const generatedCodeVersion = 3 72 73// A Plugin provides functionality to add to the output during Go code generation, 74// such as to produce RPC stubs. 75type Plugin interface { 76 // Name identifies the plugin. 77 Name() string 78 // Init is called once after data structures are built but before 79 // code generation begins. 80 Init(g *Generator) 81 // Generate produces the code generated by the plugin for this file, 82 // except for the imports, by calling the generator's methods P, In, and Out. 83 Generate(file *FileDescriptor) 84 // GenerateImports produces the import declarations for this file. 85 // It is called after Generate. 86 GenerateImports(file *FileDescriptor) 87} 88 89var plugins []Plugin 90 91// RegisterPlugin installs a (second-order) plugin to be run when the Go output is generated. 92// It is typically called during initialization. 93func RegisterPlugin(p Plugin) { 94 plugins = append(plugins, p) 95} 96 97// A GoImportPath is the import path of a Go package. e.g., "google.golang.org/genproto/protobuf". 98type GoImportPath string 99 100func (p GoImportPath) String() string { return strconv.Quote(string(p)) } 101 102// A GoPackageName is the name of a Go package. e.g., "protobuf". 103type GoPackageName string 104 105// Each type we import as a protocol buffer (other than FileDescriptorProto) needs 106// a pointer to the FileDescriptorProto that represents it. These types achieve that 107// wrapping by placing each Proto inside a struct with the pointer to its File. The 108// structs have the same names as their contents, with "Proto" removed. 109// FileDescriptor is used to store the things that it points to. 110 111// The file and package name method are common to messages and enums. 112type common struct { 113 file *FileDescriptor // File this object comes from. 114} 115 116// GoImportPath is the import path of the Go package containing the type. 117func (c *common) GoImportPath() GoImportPath { 118 return c.file.importPath 119} 120 121func (c *common) File() *FileDescriptor { return c.file } 122 123func fileIsProto3(file *descriptor.FileDescriptorProto) bool { 124 return file.GetSyntax() == "proto3" 125} 126 127func (c *common) proto3() bool { return fileIsProto3(c.file.FileDescriptorProto) } 128 129// Descriptor represents a protocol buffer message. 130type Descriptor struct { 131 common 132 *descriptor.DescriptorProto 133 parent *Descriptor // The containing message, if any. 134 nested []*Descriptor // Inner messages, if any. 135 enums []*EnumDescriptor // Inner enums, if any. 136 ext []*ExtensionDescriptor // Extensions, if any. 137 typename []string // Cached typename vector. 138 index int // The index into the container, whether the file or another message. 139 path string // The SourceCodeInfo path as comma-separated integers. 140 group bool 141} 142 143// TypeName returns the elements of the dotted type name. 144// The package name is not part of this name. 145func (d *Descriptor) TypeName() []string { 146 if d.typename != nil { 147 return d.typename 148 } 149 n := 0 150 for parent := d; parent != nil; parent = parent.parent { 151 n++ 152 } 153 s := make([]string, n) 154 for parent := d; parent != nil; parent = parent.parent { 155 n-- 156 s[n] = parent.GetName() 157 } 158 d.typename = s 159 return s 160} 161 162// EnumDescriptor describes an enum. If it's at top level, its parent will be nil. 163// Otherwise it will be the descriptor of the message in which it is defined. 164type EnumDescriptor struct { 165 common 166 *descriptor.EnumDescriptorProto 167 parent *Descriptor // The containing message, if any. 168 typename []string // Cached typename vector. 169 index int // The index into the container, whether the file or a message. 170 path string // The SourceCodeInfo path as comma-separated integers. 171} 172 173// TypeName returns the elements of the dotted type name. 174// The package name is not part of this name. 175func (e *EnumDescriptor) TypeName() (s []string) { 176 if e.typename != nil { 177 return e.typename 178 } 179 name := e.GetName() 180 if e.parent == nil { 181 s = make([]string, 1) 182 } else { 183 pname := e.parent.TypeName() 184 s = make([]string, len(pname)+1) 185 copy(s, pname) 186 } 187 s[len(s)-1] = name 188 e.typename = s 189 return s 190} 191 192// Everything but the last element of the full type name, CamelCased. 193// The values of type Foo.Bar are call Foo_value1... not Foo_Bar_value1... . 194func (e *EnumDescriptor) prefix() string { 195 if e.parent == nil { 196 // If the enum is not part of a message, the prefix is just the type name. 197 return CamelCase(*e.Name) + "_" 198 } 199 typeName := e.TypeName() 200 return CamelCaseSlice(typeName[0:len(typeName)-1]) + "_" 201} 202 203// The integer value of the named constant in this enumerated type. 204func (e *EnumDescriptor) integerValueAsString(name string) string { 205 for _, c := range e.Value { 206 if c.GetName() == name { 207 return fmt.Sprint(c.GetNumber()) 208 } 209 } 210 log.Fatal("cannot find value for enum constant") 211 return "" 212} 213 214// ExtensionDescriptor describes an extension. If it's at top level, its parent will be nil. 215// Otherwise it will be the descriptor of the message in which it is defined. 216type ExtensionDescriptor struct { 217 common 218 *descriptor.FieldDescriptorProto 219 parent *Descriptor // The containing message, if any. 220} 221 222// TypeName returns the elements of the dotted type name. 223// The package name is not part of this name. 224func (e *ExtensionDescriptor) TypeName() (s []string) { 225 name := e.GetName() 226 if e.parent == nil { 227 // top-level extension 228 s = make([]string, 1) 229 } else { 230 pname := e.parent.TypeName() 231 s = make([]string, len(pname)+1) 232 copy(s, pname) 233 } 234 s[len(s)-1] = name 235 return s 236} 237 238// DescName returns the variable name used for the generated descriptor. 239func (e *ExtensionDescriptor) DescName() string { 240 // The full type name. 241 typeName := e.TypeName() 242 // Each scope of the extension is individually CamelCased, and all are joined with "_" with an "E_" prefix. 243 for i, s := range typeName { 244 typeName[i] = CamelCase(s) 245 } 246 return "E_" + strings.Join(typeName, "_") 247} 248 249// ImportedDescriptor describes a type that has been publicly imported from another file. 250type ImportedDescriptor struct { 251 common 252 o Object 253} 254 255func (id *ImportedDescriptor) TypeName() []string { return id.o.TypeName() } 256 257// FileDescriptor describes an protocol buffer descriptor file (.proto). 258// It includes slices of all the messages and enums defined within it. 259// Those slices are constructed by WrapTypes. 260type FileDescriptor struct { 261 *descriptor.FileDescriptorProto 262 desc []*Descriptor // All the messages defined in this file. 263 enum []*EnumDescriptor // All the enums defined in this file. 264 ext []*ExtensionDescriptor // All the top-level extensions defined in this file. 265 imp []*ImportedDescriptor // All types defined in files publicly imported by this file. 266 267 // Comments, stored as a map of path (comma-separated integers) to the comment. 268 comments map[string]*descriptor.SourceCodeInfo_Location 269 270 // The full list of symbols that are exported, 271 // as a map from the exported object to its symbols. 272 // This is used for supporting public imports. 273 exported map[Object][]symbol 274 275 importPath GoImportPath // Import path of this file's package. 276 packageName GoPackageName // Name of this file's Go package. 277 278 proto3 bool // whether to generate proto3 code for this file 279} 280 281// VarName is the variable name we'll use in the generated code to refer 282// to the compressed bytes of this descriptor. It is not exported, so 283// it is only valid inside the generated package. 284func (d *FileDescriptor) VarName() string { 285 h := sha256.Sum256([]byte(d.GetName())) 286 return fmt.Sprintf("fileDescriptor_%s", hex.EncodeToString(h[:8])) 287} 288 289// goPackageOption interprets the file's go_package option. 290// If there is no go_package, it returns ("", "", false). 291// If there's a simple name, it returns ("", pkg, true). 292// If the option implies an import path, it returns (impPath, pkg, true). 293func (d *FileDescriptor) goPackageOption() (impPath GoImportPath, pkg GoPackageName, ok bool) { 294 opt := d.GetOptions().GetGoPackage() 295 if opt == "" { 296 return "", "", false 297 } 298 // A semicolon-delimited suffix delimits the import path and package name. 299 sc := strings.Index(opt, ";") 300 if sc >= 0 { 301 return GoImportPath(opt[:sc]), cleanPackageName(opt[sc+1:]), true 302 } 303 // The presence of a slash implies there's an import path. 304 slash := strings.LastIndex(opt, "/") 305 if slash >= 0 { 306 return GoImportPath(opt), cleanPackageName(opt[slash+1:]), true 307 } 308 return "", cleanPackageName(opt), true 309} 310 311// goFileName returns the output name for the generated Go file. 312func (d *FileDescriptor) goFileName(pathType pathType) string { 313 name := *d.Name 314 if ext := path.Ext(name); ext == ".proto" || ext == ".protodevel" { 315 name = name[:len(name)-len(ext)] 316 } 317 name += ".pb.go" 318 319 if pathType == pathTypeSourceRelative { 320 return name 321 } 322 323 // Does the file have a "go_package" option? 324 // If it does, it may override the filename. 325 if impPath, _, ok := d.goPackageOption(); ok && impPath != "" { 326 // Replace the existing dirname with the declared import path. 327 _, name = path.Split(name) 328 name = path.Join(string(impPath), name) 329 return name 330 } 331 332 return name 333} 334 335func (d *FileDescriptor) addExport(obj Object, sym symbol) { 336 d.exported[obj] = append(d.exported[obj], sym) 337} 338 339// symbol is an interface representing an exported Go symbol. 340type symbol interface { 341 // GenerateAlias should generate an appropriate alias 342 // for the symbol from the named package. 343 GenerateAlias(g *Generator, filename string, pkg GoPackageName) 344} 345 346type messageSymbol struct { 347 sym string 348 hasExtensions, isMessageSet bool 349 oneofTypes []string 350} 351 352type getterSymbol struct { 353 name string 354 typ string 355 typeName string // canonical name in proto world; empty for proto.Message and similar 356 genType bool // whether typ contains a generated type (message/group/enum) 357} 358 359func (ms *messageSymbol) GenerateAlias(g *Generator, filename string, pkg GoPackageName) { 360 g.P("// ", ms.sym, " from public import ", filename) 361 g.P("type ", ms.sym, " = ", pkg, ".", ms.sym) 362 for _, name := range ms.oneofTypes { 363 g.P("type ", name, " = ", pkg, ".", name) 364 } 365} 366 367type enumSymbol struct { 368 name string 369 proto3 bool // Whether this came from a proto3 file. 370} 371 372func (es enumSymbol) GenerateAlias(g *Generator, filename string, pkg GoPackageName) { 373 s := es.name 374 g.P("// ", s, " from public import ", filename) 375 g.P("type ", s, " = ", pkg, ".", s) 376 g.P("var ", s, "_name = ", pkg, ".", s, "_name") 377 g.P("var ", s, "_value = ", pkg, ".", s, "_value") 378} 379 380type constOrVarSymbol struct { 381 sym string 382 typ string // either "const" or "var" 383 cast string // if non-empty, a type cast is required (used for enums) 384} 385 386func (cs constOrVarSymbol) GenerateAlias(g *Generator, filename string, pkg GoPackageName) { 387 v := string(pkg) + "." + cs.sym 388 if cs.cast != "" { 389 v = cs.cast + "(" + v + ")" 390 } 391 g.P(cs.typ, " ", cs.sym, " = ", v) 392} 393 394// Object is an interface abstracting the abilities shared by enums, messages, extensions and imported objects. 395type Object interface { 396 GoImportPath() GoImportPath 397 TypeName() []string 398 File() *FileDescriptor 399} 400 401// Generator is the type whose methods generate the output, stored in the associated response structure. 402type Generator struct { 403 *bytes.Buffer 404 405 Request *plugin.CodeGeneratorRequest // The input. 406 Response *plugin.CodeGeneratorResponse // The output. 407 408 Param map[string]string // Command-line parameters. 409 PackageImportPath string // Go import path of the package we're generating code for 410 ImportPrefix string // String to prefix to imported package file names. 411 ImportMap map[string]string // Mapping from .proto file name to import path 412 413 Pkg map[string]string // The names under which we import support packages 414 415 outputImportPath GoImportPath // Package we're generating code for. 416 allFiles []*FileDescriptor // All files in the tree 417 allFilesByName map[string]*FileDescriptor // All files by filename. 418 genFiles []*FileDescriptor // Those files we will generate output for. 419 file *FileDescriptor // The file we are compiling now. 420 packageNames map[GoImportPath]GoPackageName // Imported package names in the current file. 421 usedPackages map[GoImportPath]bool // Packages used in current file. 422 usedPackageNames map[GoPackageName]bool // Package names used in the current file. 423 addedImports map[GoImportPath]bool // Additional imports to emit. 424 typeNameToObject map[string]Object // Key is a fully-qualified name in input syntax. 425 init []string // Lines to emit in the init function. 426 indent string 427 pathType pathType // How to generate output filenames. 428 writeOutput bool 429 annotateCode bool // whether to store annotations 430 annotations []*descriptor.GeneratedCodeInfo_Annotation // annotations to store 431} 432 433type pathType int 434 435const ( 436 pathTypeImport pathType = iota 437 pathTypeSourceRelative 438) 439 440// New creates a new generator and allocates the request and response protobufs. 441func New() *Generator { 442 g := new(Generator) 443 g.Buffer = new(bytes.Buffer) 444 g.Request = new(plugin.CodeGeneratorRequest) 445 g.Response = new(plugin.CodeGeneratorResponse) 446 return g 447} 448 449// Error reports a problem, including an error, and exits the program. 450func (g *Generator) Error(err error, msgs ...string) { 451 s := strings.Join(msgs, " ") + ":" + err.Error() 452 log.Print("protoc-gen-go: error:", s) 453 os.Exit(1) 454} 455 456// Fail reports a problem and exits the program. 457func (g *Generator) Fail(msgs ...string) { 458 s := strings.Join(msgs, " ") 459 log.Print("protoc-gen-go: error:", s) 460 os.Exit(1) 461} 462 463// CommandLineParameters breaks the comma-separated list of key=value pairs 464// in the parameter (a member of the request protobuf) into a key/value map. 465// It then sets file name mappings defined by those entries. 466func (g *Generator) CommandLineParameters(parameter string) { 467 g.Param = make(map[string]string) 468 for _, p := range strings.Split(parameter, ",") { 469 if i := strings.Index(p, "="); i < 0 { 470 g.Param[p] = "" 471 } else { 472 g.Param[p[0:i]] = p[i+1:] 473 } 474 } 475 476 g.ImportMap = make(map[string]string) 477 pluginList := "none" // Default list of plugin names to enable (empty means all). 478 for k, v := range g.Param { 479 switch k { 480 case "import_prefix": 481 g.ImportPrefix = v 482 case "import_path": 483 g.PackageImportPath = v 484 case "paths": 485 switch v { 486 case "import": 487 g.pathType = pathTypeImport 488 case "source_relative": 489 g.pathType = pathTypeSourceRelative 490 default: 491 g.Fail(fmt.Sprintf(`Unknown path type %q: want "import" or "source_relative".`, v)) 492 } 493 case "plugins": 494 pluginList = v 495 case "annotate_code": 496 if v == "true" { 497 g.annotateCode = true 498 } 499 default: 500 if len(k) > 0 && k[0] == 'M' { 501 g.ImportMap[k[1:]] = v 502 } 503 } 504 } 505 if pluginList != "" { 506 // Amend the set of plugins. 507 enabled := make(map[string]bool) 508 for _, name := range strings.Split(pluginList, "+") { 509 enabled[name] = true 510 } 511 var nplugins []Plugin 512 for _, p := range plugins { 513 if enabled[p.Name()] { 514 nplugins = append(nplugins, p) 515 } 516 } 517 plugins = nplugins 518 } 519} 520 521// DefaultPackageName returns the package name printed for the object. 522// If its file is in a different package, it returns the package name we're using for this file, plus ".". 523// Otherwise it returns the empty string. 524func (g *Generator) DefaultPackageName(obj Object) string { 525 importPath := obj.GoImportPath() 526 if importPath == g.outputImportPath { 527 return "" 528 } 529 return string(g.GoPackageName(importPath)) + "." 530} 531 532// GoPackageName returns the name used for a package. 533func (g *Generator) GoPackageName(importPath GoImportPath) GoPackageName { 534 if name, ok := g.packageNames[importPath]; ok { 535 return name 536 } 537 name := cleanPackageName(baseName(string(importPath))) 538 for i, orig := 1, name; g.usedPackageNames[name] || isGoPredeclaredIdentifier[string(name)]; i++ { 539 name = orig + GoPackageName(strconv.Itoa(i)) 540 } 541 g.packageNames[importPath] = name 542 g.usedPackageNames[name] = true 543 return name 544} 545 546// AddImport adds a package to the generated file's import section. 547// It returns the name used for the package. 548func (g *Generator) AddImport(importPath GoImportPath) GoPackageName { 549 g.addedImports[importPath] = true 550 return g.GoPackageName(importPath) 551} 552 553var globalPackageNames = map[GoPackageName]bool{ 554 "fmt": true, 555 "math": true, 556 "proto": true, 557} 558 559// Create and remember a guaranteed unique package name. Pkg is the candidate name. 560// The FileDescriptor parameter is unused. 561func RegisterUniquePackageName(pkg string, f *FileDescriptor) string { 562 name := cleanPackageName(pkg) 563 for i, orig := 1, name; globalPackageNames[name]; i++ { 564 name = orig + GoPackageName(strconv.Itoa(i)) 565 } 566 globalPackageNames[name] = true 567 return string(name) 568} 569 570var isGoKeyword = map[string]bool{ 571 "break": true, 572 "case": true, 573 "chan": true, 574 "const": true, 575 "continue": true, 576 "default": true, 577 "else": true, 578 "defer": true, 579 "fallthrough": true, 580 "for": true, 581 "func": true, 582 "go": true, 583 "goto": true, 584 "if": true, 585 "import": true, 586 "interface": true, 587 "map": true, 588 "package": true, 589 "range": true, 590 "return": true, 591 "select": true, 592 "struct": true, 593 "switch": true, 594 "type": true, 595 "var": true, 596} 597 598var isGoPredeclaredIdentifier = map[string]bool{ 599 "append": true, 600 "bool": true, 601 "byte": true, 602 "cap": true, 603 "close": true, 604 "complex": true, 605 "complex128": true, 606 "complex64": true, 607 "copy": true, 608 "delete": true, 609 "error": true, 610 "false": true, 611 "float32": true, 612 "float64": true, 613 "imag": true, 614 "int": true, 615 "int16": true, 616 "int32": true, 617 "int64": true, 618 "int8": true, 619 "iota": true, 620 "len": true, 621 "make": true, 622 "new": true, 623 "nil": true, 624 "panic": true, 625 "print": true, 626 "println": true, 627 "real": true, 628 "recover": true, 629 "rune": true, 630 "string": true, 631 "true": true, 632 "uint": true, 633 "uint16": true, 634 "uint32": true, 635 "uint64": true, 636 "uint8": true, 637 "uintptr": true, 638} 639 640func cleanPackageName(name string) GoPackageName { 641 name = strings.Map(badToUnderscore, name) 642 // Identifier must not be keyword or predeclared identifier: insert _. 643 if isGoKeyword[name] { 644 name = "_" + name 645 } 646 // Identifier must not begin with digit: insert _. 647 if r, _ := utf8.DecodeRuneInString(name); unicode.IsDigit(r) { 648 name = "_" + name 649 } 650 return GoPackageName(name) 651} 652 653// defaultGoPackage returns the package name to use, 654// derived from the import path of the package we're building code for. 655func (g *Generator) defaultGoPackage() GoPackageName { 656 p := g.PackageImportPath 657 if i := strings.LastIndex(p, "/"); i >= 0 { 658 p = p[i+1:] 659 } 660 return cleanPackageName(p) 661} 662 663// SetPackageNames sets the package name for this run. 664// The package name must agree across all files being generated. 665// It also defines unique package names for all imported files. 666func (g *Generator) SetPackageNames() { 667 g.outputImportPath = g.genFiles[0].importPath 668 669 defaultPackageNames := make(map[GoImportPath]GoPackageName) 670 for _, f := range g.genFiles { 671 if _, p, ok := f.goPackageOption(); ok { 672 defaultPackageNames[f.importPath] = p 673 } 674 } 675 for _, f := range g.genFiles { 676 if _, p, ok := f.goPackageOption(); ok { 677 // Source file: option go_package = "quux/bar"; 678 f.packageName = p 679 } else if p, ok := defaultPackageNames[f.importPath]; ok { 680 // A go_package option in another file in the same package. 681 // 682 // This is a poor choice in general, since every source file should 683 // contain a go_package option. Supported mainly for historical 684 // compatibility. 685 f.packageName = p 686 } else if p := g.defaultGoPackage(); p != "" { 687 // Command-line: import_path=quux/bar. 688 // 689 // The import_path flag sets a package name for files which don't 690 // contain a go_package option. 691 f.packageName = p 692 } else if p := f.GetPackage(); p != "" { 693 // Source file: package quux.bar; 694 f.packageName = cleanPackageName(p) 695 } else { 696 // Source filename. 697 f.packageName = cleanPackageName(baseName(f.GetName())) 698 } 699 } 700 701 // Check that all files have a consistent package name and import path. 702 for _, f := range g.genFiles[1:] { 703 if a, b := g.genFiles[0].importPath, f.importPath; a != b { 704 g.Fail(fmt.Sprintf("inconsistent package import paths: %v, %v", a, b)) 705 } 706 if a, b := g.genFiles[0].packageName, f.packageName; a != b { 707 g.Fail(fmt.Sprintf("inconsistent package names: %v, %v", a, b)) 708 } 709 } 710 711 // Names of support packages. These never vary (if there are conflicts, 712 // we rename the conflicting package), so this could be removed someday. 713 g.Pkg = map[string]string{ 714 "fmt": "fmt", 715 "math": "math", 716 "proto": "proto", 717 } 718} 719 720// WrapTypes walks the incoming data, wrapping DescriptorProtos, EnumDescriptorProtos 721// and FileDescriptorProtos into file-referenced objects within the Generator. 722// It also creates the list of files to generate and so should be called before GenerateAllFiles. 723func (g *Generator) WrapTypes() { 724 g.allFiles = make([]*FileDescriptor, 0, len(g.Request.ProtoFile)) 725 g.allFilesByName = make(map[string]*FileDescriptor, len(g.allFiles)) 726 genFileNames := make(map[string]bool) 727 for _, n := range g.Request.FileToGenerate { 728 genFileNames[n] = true 729 } 730 for _, f := range g.Request.ProtoFile { 731 fd := &FileDescriptor{ 732 FileDescriptorProto: f, 733 exported: make(map[Object][]symbol), 734 proto3: fileIsProto3(f), 735 } 736 // The import path may be set in a number of ways. 737 if substitution, ok := g.ImportMap[f.GetName()]; ok { 738 // Command-line: M=foo.proto=quux/bar. 739 // 740 // Explicit mapping of source file to import path. 741 fd.importPath = GoImportPath(substitution) 742 } else if genFileNames[f.GetName()] && g.PackageImportPath != "" { 743 // Command-line: import_path=quux/bar. 744 // 745 // The import_path flag sets the import path for every file that 746 // we generate code for. 747 fd.importPath = GoImportPath(g.PackageImportPath) 748 } else if p, _, _ := fd.goPackageOption(); p != "" { 749 // Source file: option go_package = "quux/bar"; 750 // 751 // The go_package option sets the import path. Most users should use this. 752 fd.importPath = p 753 } else { 754 // Source filename. 755 // 756 // Last resort when nothing else is available. 757 fd.importPath = GoImportPath(path.Dir(f.GetName())) 758 } 759 // We must wrap the descriptors before we wrap the enums 760 fd.desc = wrapDescriptors(fd) 761 g.buildNestedDescriptors(fd.desc) 762 fd.enum = wrapEnumDescriptors(fd, fd.desc) 763 g.buildNestedEnums(fd.desc, fd.enum) 764 fd.ext = wrapExtensions(fd) 765 extractComments(fd) 766 g.allFiles = append(g.allFiles, fd) 767 g.allFilesByName[f.GetName()] = fd 768 } 769 for _, fd := range g.allFiles { 770 fd.imp = wrapImported(fd, g) 771 } 772 773 g.genFiles = make([]*FileDescriptor, 0, len(g.Request.FileToGenerate)) 774 for _, fileName := range g.Request.FileToGenerate { 775 fd := g.allFilesByName[fileName] 776 if fd == nil { 777 g.Fail("could not find file named", fileName) 778 } 779 g.genFiles = append(g.genFiles, fd) 780 } 781} 782 783// Scan the descriptors in this file. For each one, build the slice of nested descriptors 784func (g *Generator) buildNestedDescriptors(descs []*Descriptor) { 785 for _, desc := range descs { 786 if len(desc.NestedType) != 0 { 787 for _, nest := range descs { 788 if nest.parent == desc { 789 desc.nested = append(desc.nested, nest) 790 } 791 } 792 if len(desc.nested) != len(desc.NestedType) { 793 g.Fail("internal error: nesting failure for", desc.GetName()) 794 } 795 } 796 } 797} 798 799func (g *Generator) buildNestedEnums(descs []*Descriptor, enums []*EnumDescriptor) { 800 for _, desc := range descs { 801 if len(desc.EnumType) != 0 { 802 for _, enum := range enums { 803 if enum.parent == desc { 804 desc.enums = append(desc.enums, enum) 805 } 806 } 807 if len(desc.enums) != len(desc.EnumType) { 808 g.Fail("internal error: enum nesting failure for", desc.GetName()) 809 } 810 } 811 } 812} 813 814// Construct the Descriptor 815func newDescriptor(desc *descriptor.DescriptorProto, parent *Descriptor, file *FileDescriptor, index int) *Descriptor { 816 d := &Descriptor{ 817 common: common{file}, 818 DescriptorProto: desc, 819 parent: parent, 820 index: index, 821 } 822 if parent == nil { 823 d.path = fmt.Sprintf("%d,%d", messagePath, index) 824 } else { 825 d.path = fmt.Sprintf("%s,%d,%d", parent.path, messageMessagePath, index) 826 } 827 828 // The only way to distinguish a group from a message is whether 829 // the containing message has a TYPE_GROUP field that matches. 830 if parent != nil { 831 parts := d.TypeName() 832 if file.Package != nil { 833 parts = append([]string{*file.Package}, parts...) 834 } 835 exp := "." + strings.Join(parts, ".") 836 for _, field := range parent.Field { 837 if field.GetType() == descriptor.FieldDescriptorProto_TYPE_GROUP && field.GetTypeName() == exp { 838 d.group = true 839 break 840 } 841 } 842 } 843 844 for _, field := range desc.Extension { 845 d.ext = append(d.ext, &ExtensionDescriptor{common{file}, field, d}) 846 } 847 848 return d 849} 850 851// Return a slice of all the Descriptors defined within this file 852func wrapDescriptors(file *FileDescriptor) []*Descriptor { 853 sl := make([]*Descriptor, 0, len(file.MessageType)+10) 854 for i, desc := range file.MessageType { 855 sl = wrapThisDescriptor(sl, desc, nil, file, i) 856 } 857 return sl 858} 859 860// Wrap this Descriptor, recursively 861func wrapThisDescriptor(sl []*Descriptor, desc *descriptor.DescriptorProto, parent *Descriptor, file *FileDescriptor, index int) []*Descriptor { 862 sl = append(sl, newDescriptor(desc, parent, file, index)) 863 me := sl[len(sl)-1] 864 for i, nested := range desc.NestedType { 865 sl = wrapThisDescriptor(sl, nested, me, file, i) 866 } 867 return sl 868} 869 870// Construct the EnumDescriptor 871func newEnumDescriptor(desc *descriptor.EnumDescriptorProto, parent *Descriptor, file *FileDescriptor, index int) *EnumDescriptor { 872 ed := &EnumDescriptor{ 873 common: common{file}, 874 EnumDescriptorProto: desc, 875 parent: parent, 876 index: index, 877 } 878 if parent == nil { 879 ed.path = fmt.Sprintf("%d,%d", enumPath, index) 880 } else { 881 ed.path = fmt.Sprintf("%s,%d,%d", parent.path, messageEnumPath, index) 882 } 883 return ed 884} 885 886// Return a slice of all the EnumDescriptors defined within this file 887func wrapEnumDescriptors(file *FileDescriptor, descs []*Descriptor) []*EnumDescriptor { 888 sl := make([]*EnumDescriptor, 0, len(file.EnumType)+10) 889 // Top-level enums. 890 for i, enum := range file.EnumType { 891 sl = append(sl, newEnumDescriptor(enum, nil, file, i)) 892 } 893 // Enums within messages. Enums within embedded messages appear in the outer-most message. 894 for _, nested := range descs { 895 for i, enum := range nested.EnumType { 896 sl = append(sl, newEnumDescriptor(enum, nested, file, i)) 897 } 898 } 899 return sl 900} 901 902// Return a slice of all the top-level ExtensionDescriptors defined within this file. 903func wrapExtensions(file *FileDescriptor) []*ExtensionDescriptor { 904 var sl []*ExtensionDescriptor 905 for _, field := range file.Extension { 906 sl = append(sl, &ExtensionDescriptor{common{file}, field, nil}) 907 } 908 return sl 909} 910 911// Return a slice of all the types that are publicly imported into this file. 912func wrapImported(file *FileDescriptor, g *Generator) (sl []*ImportedDescriptor) { 913 for _, index := range file.PublicDependency { 914 df := g.fileByName(file.Dependency[index]) 915 for _, d := range df.desc { 916 if d.GetOptions().GetMapEntry() { 917 continue 918 } 919 sl = append(sl, &ImportedDescriptor{common{file}, d}) 920 } 921 for _, e := range df.enum { 922 sl = append(sl, &ImportedDescriptor{common{file}, e}) 923 } 924 for _, ext := range df.ext { 925 sl = append(sl, &ImportedDescriptor{common{file}, ext}) 926 } 927 } 928 return 929} 930 931func extractComments(file *FileDescriptor) { 932 file.comments = make(map[string]*descriptor.SourceCodeInfo_Location) 933 for _, loc := range file.GetSourceCodeInfo().GetLocation() { 934 if loc.LeadingComments == nil { 935 continue 936 } 937 var p []string 938 for _, n := range loc.Path { 939 p = append(p, strconv.Itoa(int(n))) 940 } 941 file.comments[strings.Join(p, ",")] = loc 942 } 943} 944 945// BuildTypeNameMap builds the map from fully qualified type names to objects. 946// The key names for the map come from the input data, which puts a period at the beginning. 947// It should be called after SetPackageNames and before GenerateAllFiles. 948func (g *Generator) BuildTypeNameMap() { 949 g.typeNameToObject = make(map[string]Object) 950 for _, f := range g.allFiles { 951 // The names in this loop are defined by the proto world, not us, so the 952 // package name may be empty. If so, the dotted package name of X will 953 // be ".X"; otherwise it will be ".pkg.X". 954 dottedPkg := "." + f.GetPackage() 955 if dottedPkg != "." { 956 dottedPkg += "." 957 } 958 for _, enum := range f.enum { 959 name := dottedPkg + dottedSlice(enum.TypeName()) 960 g.typeNameToObject[name] = enum 961 } 962 for _, desc := range f.desc { 963 name := dottedPkg + dottedSlice(desc.TypeName()) 964 g.typeNameToObject[name] = desc 965 } 966 } 967} 968 969// ObjectNamed, given a fully-qualified input type name as it appears in the input data, 970// returns the descriptor for the message or enum with that name. 971func (g *Generator) ObjectNamed(typeName string) Object { 972 o, ok := g.typeNameToObject[typeName] 973 if !ok { 974 g.Fail("can't find object with type", typeName) 975 } 976 return o 977} 978 979// AnnotatedAtoms is a list of atoms (as consumed by P) that records the file name and proto AST path from which they originated. 980type AnnotatedAtoms struct { 981 source string 982 path string 983 atoms []interface{} 984} 985 986// Annotate records the file name and proto AST path of a list of atoms 987// so that a later call to P can emit a link from each atom to its origin. 988func Annotate(file *FileDescriptor, path string, atoms ...interface{}) *AnnotatedAtoms { 989 return &AnnotatedAtoms{source: *file.Name, path: path, atoms: atoms} 990} 991 992// printAtom prints the (atomic, non-annotation) argument to the generated output. 993func (g *Generator) printAtom(v interface{}) { 994 switch v := v.(type) { 995 case string: 996 g.WriteString(v) 997 case *string: 998 g.WriteString(*v) 999 case bool: 1000 fmt.Fprint(g, v) 1001 case *bool: 1002 fmt.Fprint(g, *v) 1003 case int: 1004 fmt.Fprint(g, v) 1005 case *int32: 1006 fmt.Fprint(g, *v) 1007 case *int64: 1008 fmt.Fprint(g, *v) 1009 case float64: 1010 fmt.Fprint(g, v) 1011 case *float64: 1012 fmt.Fprint(g, *v) 1013 case GoPackageName: 1014 g.WriteString(string(v)) 1015 case GoImportPath: 1016 g.WriteString(strconv.Quote(string(v))) 1017 default: 1018 g.Fail(fmt.Sprintf("unknown type in printer: %T", v)) 1019 } 1020} 1021 1022// P prints the arguments to the generated output. It handles strings and int32s, plus 1023// handling indirections because they may be *string, etc. Any inputs of type AnnotatedAtoms may emit 1024// annotations in a .meta file in addition to outputting the atoms themselves (if g.annotateCode 1025// is true). 1026func (g *Generator) P(str ...interface{}) { 1027 if !g.writeOutput { 1028 return 1029 } 1030 g.WriteString(g.indent) 1031 for _, v := range str { 1032 switch v := v.(type) { 1033 case *AnnotatedAtoms: 1034 begin := int32(g.Len()) 1035 for _, v := range v.atoms { 1036 g.printAtom(v) 1037 } 1038 if g.annotateCode { 1039 end := int32(g.Len()) 1040 var path []int32 1041 for _, token := range strings.Split(v.path, ",") { 1042 val, err := strconv.ParseInt(token, 10, 32) 1043 if err != nil { 1044 g.Fail("could not parse proto AST path: ", err.Error()) 1045 } 1046 path = append(path, int32(val)) 1047 } 1048 g.annotations = append(g.annotations, &descriptor.GeneratedCodeInfo_Annotation{ 1049 Path: path, 1050 SourceFile: &v.source, 1051 Begin: &begin, 1052 End: &end, 1053 }) 1054 } 1055 default: 1056 g.printAtom(v) 1057 } 1058 } 1059 g.WriteByte('\n') 1060} 1061 1062// addInitf stores the given statement to be printed inside the file's init function. 1063// The statement is given as a format specifier and arguments. 1064func (g *Generator) addInitf(stmt string, a ...interface{}) { 1065 g.init = append(g.init, fmt.Sprintf(stmt, a...)) 1066} 1067 1068// In Indents the output one tab stop. 1069func (g *Generator) In() { g.indent += "\t" } 1070 1071// Out unindents the output one tab stop. 1072func (g *Generator) Out() { 1073 if len(g.indent) > 0 { 1074 g.indent = g.indent[1:] 1075 } 1076} 1077 1078// GenerateAllFiles generates the output for all the files we're outputting. 1079func (g *Generator) GenerateAllFiles() { 1080 // Initialize the plugins 1081 for _, p := range plugins { 1082 p.Init(g) 1083 } 1084 // Generate the output. The generator runs for every file, even the files 1085 // that we don't generate output for, so that we can collate the full list 1086 // of exported symbols to support public imports. 1087 genFileMap := make(map[*FileDescriptor]bool, len(g.genFiles)) 1088 for _, file := range g.genFiles { 1089 genFileMap[file] = true 1090 } 1091 for _, file := range g.allFiles { 1092 g.Reset() 1093 g.annotations = nil 1094 g.writeOutput = genFileMap[file] 1095 g.generate(file) 1096 if !g.writeOutput { 1097 continue 1098 } 1099 fname := file.goFileName(g.pathType) 1100 g.Response.File = append(g.Response.File, &plugin.CodeGeneratorResponse_File{ 1101 Name: proto.String(fname), 1102 Content: proto.String(g.String()), 1103 }) 1104 if g.annotateCode { 1105 // Store the generated code annotations in text, as the protoc plugin protocol requires that 1106 // strings contain valid UTF-8. 1107 g.Response.File = append(g.Response.File, &plugin.CodeGeneratorResponse_File{ 1108 Name: proto.String(file.goFileName(g.pathType) + ".meta"), 1109 Content: proto.String(proto.CompactTextString(&descriptor.GeneratedCodeInfo{Annotation: g.annotations})), 1110 }) 1111 } 1112 } 1113} 1114 1115// Run all the plugins associated with the file. 1116func (g *Generator) runPlugins(file *FileDescriptor) { 1117 for _, p := range plugins { 1118 p.Generate(file) 1119 } 1120} 1121 1122// Fill the response protocol buffer with the generated output for all the files we're 1123// supposed to generate. 1124func (g *Generator) generate(file *FileDescriptor) { 1125 g.file = file 1126 g.usedPackages = make(map[GoImportPath]bool) 1127 g.packageNames = make(map[GoImportPath]GoPackageName) 1128 g.usedPackageNames = make(map[GoPackageName]bool) 1129 g.addedImports = make(map[GoImportPath]bool) 1130 for name := range globalPackageNames { 1131 g.usedPackageNames[name] = true 1132 } 1133 1134 g.P("// This is a compile-time assertion to ensure that this generated file") 1135 g.P("// is compatible with the proto package it is being compiled against.") 1136 g.P("// A compilation error at this line likely means your copy of the") 1137 g.P("// proto package needs to be updated.") 1138 g.P("const _ = ", g.Pkg["proto"], ".ProtoPackageIsVersion", generatedCodeVersion, " // please upgrade the proto package") 1139 g.P() 1140 1141 for _, td := range g.file.imp { 1142 g.generateImported(td) 1143 } 1144 for _, enum := range g.file.enum { 1145 g.generateEnum(enum) 1146 } 1147 for _, desc := range g.file.desc { 1148 // Don't generate virtual messages for maps. 1149 if desc.GetOptions().GetMapEntry() { 1150 continue 1151 } 1152 g.generateMessage(desc) 1153 } 1154 for _, ext := range g.file.ext { 1155 g.generateExtension(ext) 1156 } 1157 g.generateInitFunction() 1158 g.generateFileDescriptor(file) 1159 1160 // Run the plugins before the imports so we know which imports are necessary. 1161 g.runPlugins(file) 1162 1163 // Generate header and imports last, though they appear first in the output. 1164 rem := g.Buffer 1165 remAnno := g.annotations 1166 g.Buffer = new(bytes.Buffer) 1167 g.annotations = nil 1168 g.generateHeader() 1169 g.generateImports() 1170 if !g.writeOutput { 1171 return 1172 } 1173 // Adjust the offsets for annotations displaced by the header and imports. 1174 for _, anno := range remAnno { 1175 *anno.Begin += int32(g.Len()) 1176 *anno.End += int32(g.Len()) 1177 g.annotations = append(g.annotations, anno) 1178 } 1179 g.Write(rem.Bytes()) 1180 1181 // Reformat generated code and patch annotation locations. 1182 fset := token.NewFileSet() 1183 original := g.Bytes() 1184 if g.annotateCode { 1185 // make a copy independent of g; we'll need it after Reset. 1186 original = append([]byte(nil), original...) 1187 } 1188 fileAST, err := parser.ParseFile(fset, "", original, parser.ParseComments) 1189 if err != nil { 1190 // Print out the bad code with line numbers. 1191 // This should never happen in practice, but it can while changing generated code, 1192 // so consider this a debugging aid. 1193 var src bytes.Buffer 1194 s := bufio.NewScanner(bytes.NewReader(original)) 1195 for line := 1; s.Scan(); line++ { 1196 fmt.Fprintf(&src, "%5d\t%s\n", line, s.Bytes()) 1197 } 1198 g.Fail("bad Go source code was generated:", err.Error(), "\n"+src.String()) 1199 } 1200 ast.SortImports(fset, fileAST) 1201 g.Reset() 1202 err = (&printer.Config{Mode: printer.TabIndent | printer.UseSpaces, Tabwidth: 8}).Fprint(g, fset, fileAST) 1203 if err != nil { 1204 g.Fail("generated Go source code could not be reformatted:", err.Error()) 1205 } 1206 if g.annotateCode { 1207 m, err := remap.Compute(original, g.Bytes()) 1208 if err != nil { 1209 g.Fail("formatted generated Go source code could not be mapped back to the original code:", err.Error()) 1210 } 1211 for _, anno := range g.annotations { 1212 new, ok := m.Find(int(*anno.Begin), int(*anno.End)) 1213 if !ok { 1214 g.Fail("span in formatted generated Go source code could not be mapped back to the original code") 1215 } 1216 *anno.Begin = int32(new.Pos) 1217 *anno.End = int32(new.End) 1218 } 1219 } 1220} 1221 1222// Generate the header, including package definition 1223func (g *Generator) generateHeader() { 1224 g.P("// Code generated by protoc-gen-go. DO NOT EDIT.") 1225 if g.file.GetOptions().GetDeprecated() { 1226 g.P("// ", g.file.Name, " is a deprecated file.") 1227 } else { 1228 g.P("// source: ", g.file.Name) 1229 } 1230 g.P() 1231 g.PrintComments(strconv.Itoa(packagePath)) 1232 g.P() 1233 g.P("package ", g.file.packageName) 1234 g.P() 1235} 1236 1237// deprecationComment is the standard comment added to deprecated 1238// messages, fields, enums, and enum values. 1239var deprecationComment = "// Deprecated: Do not use." 1240 1241// PrintComments prints any comments from the source .proto file. 1242// The path is a comma-separated list of integers. 1243// It returns an indication of whether any comments were printed. 1244// See descriptor.proto for its format. 1245func (g *Generator) PrintComments(path string) bool { 1246 if !g.writeOutput { 1247 return false 1248 } 1249 if c, ok := g.makeComments(path); ok { 1250 g.P(c) 1251 return true 1252 } 1253 return false 1254} 1255 1256// makeComments generates the comment string for the field, no "\n" at the end 1257func (g *Generator) makeComments(path string) (string, bool) { 1258 loc, ok := g.file.comments[path] 1259 if !ok { 1260 return "", false 1261 } 1262 w := new(bytes.Buffer) 1263 nl := "" 1264 for _, line := range strings.Split(strings.TrimSuffix(loc.GetLeadingComments(), "\n"), "\n") { 1265 fmt.Fprintf(w, "%s//%s", nl, line) 1266 nl = "\n" 1267 } 1268 return w.String(), true 1269} 1270 1271func (g *Generator) fileByName(filename string) *FileDescriptor { 1272 return g.allFilesByName[filename] 1273} 1274 1275// weak returns whether the ith import of the current file is a weak import. 1276func (g *Generator) weak(i int32) bool { 1277 for _, j := range g.file.WeakDependency { 1278 if j == i { 1279 return true 1280 } 1281 } 1282 return false 1283} 1284 1285// Generate the imports 1286func (g *Generator) generateImports() { 1287 imports := make(map[GoImportPath]GoPackageName) 1288 for i, s := range g.file.Dependency { 1289 fd := g.fileByName(s) 1290 importPath := fd.importPath 1291 // Do not import our own package. 1292 if importPath == g.file.importPath { 1293 continue 1294 } 1295 // Do not import weak imports. 1296 if g.weak(int32(i)) { 1297 continue 1298 } 1299 // Do not import a package twice. 1300 if _, ok := imports[importPath]; ok { 1301 continue 1302 } 1303 // We need to import all the dependencies, even if we don't reference them, 1304 // because other code and tools depend on having the full transitive closure 1305 // of protocol buffer types in the binary. 1306 packageName := g.GoPackageName(importPath) 1307 if _, ok := g.usedPackages[importPath]; !ok { 1308 packageName = "_" 1309 } 1310 imports[importPath] = packageName 1311 } 1312 for importPath := range g.addedImports { 1313 imports[importPath] = g.GoPackageName(importPath) 1314 } 1315 // We almost always need a proto import. Rather than computing when we 1316 // do, which is tricky when there's a plugin, just import it and 1317 // reference it later. The same argument applies to the fmt and math packages. 1318 g.P("import (") 1319 g.P(g.Pkg["fmt"] + ` "fmt"`) 1320 g.P(g.Pkg["math"] + ` "math"`) 1321 g.P(g.Pkg["proto"]+" ", GoImportPath(g.ImportPrefix)+"github.com/golang/protobuf/proto") 1322 for importPath, packageName := range imports { 1323 g.P(packageName, " ", GoImportPath(g.ImportPrefix)+importPath) 1324 } 1325 g.P(")") 1326 g.P() 1327 // TODO: may need to worry about uniqueness across plugins 1328 for _, p := range plugins { 1329 p.GenerateImports(g.file) 1330 g.P() 1331 } 1332 g.P("// Reference imports to suppress errors if they are not otherwise used.") 1333 g.P("var _ = ", g.Pkg["proto"], ".Marshal") 1334 g.P("var _ = ", g.Pkg["fmt"], ".Errorf") 1335 g.P("var _ = ", g.Pkg["math"], ".Inf") 1336 g.P() 1337} 1338 1339func (g *Generator) generateImported(id *ImportedDescriptor) { 1340 df := id.o.File() 1341 filename := *df.Name 1342 if df.importPath == g.file.importPath { 1343 // Don't generate type aliases for files in the same Go package as this one. 1344 return 1345 } 1346 if !supportTypeAliases { 1347 g.Fail(fmt.Sprintf("%s: public imports require at least go1.9", filename)) 1348 } 1349 g.usedPackages[df.importPath] = true 1350 1351 for _, sym := range df.exported[id.o] { 1352 sym.GenerateAlias(g, filename, g.GoPackageName(df.importPath)) 1353 } 1354 1355 g.P() 1356} 1357 1358// Generate the enum definitions for this EnumDescriptor. 1359func (g *Generator) generateEnum(enum *EnumDescriptor) { 1360 // The full type name 1361 typeName := enum.TypeName() 1362 // The full type name, CamelCased. 1363 ccTypeName := CamelCaseSlice(typeName) 1364 ccPrefix := enum.prefix() 1365 1366 deprecatedEnum := "" 1367 if enum.GetOptions().GetDeprecated() { 1368 deprecatedEnum = deprecationComment 1369 } 1370 g.PrintComments(enum.path) 1371 g.P("type ", Annotate(enum.file, enum.path, ccTypeName), " int32", deprecatedEnum) 1372 g.file.addExport(enum, enumSymbol{ccTypeName, enum.proto3()}) 1373 g.P("const (") 1374 for i, e := range enum.Value { 1375 etorPath := fmt.Sprintf("%s,%d,%d", enum.path, enumValuePath, i) 1376 g.PrintComments(etorPath) 1377 1378 deprecatedValue := "" 1379 if e.GetOptions().GetDeprecated() { 1380 deprecatedValue = deprecationComment 1381 } 1382 1383 name := ccPrefix + *e.Name 1384 g.P(Annotate(enum.file, etorPath, name), " ", ccTypeName, " = ", e.Number, " ", deprecatedValue) 1385 g.file.addExport(enum, constOrVarSymbol{name, "const", ccTypeName}) 1386 } 1387 g.P(")") 1388 g.P() 1389 g.P("var ", ccTypeName, "_name = map[int32]string{") 1390 generated := make(map[int32]bool) // avoid duplicate values 1391 for _, e := range enum.Value { 1392 duplicate := "" 1393 if _, present := generated[*e.Number]; present { 1394 duplicate = "// Duplicate value: " 1395 } 1396 g.P(duplicate, e.Number, ": ", strconv.Quote(*e.Name), ",") 1397 generated[*e.Number] = true 1398 } 1399 g.P("}") 1400 g.P() 1401 g.P("var ", ccTypeName, "_value = map[string]int32{") 1402 for _, e := range enum.Value { 1403 g.P(strconv.Quote(*e.Name), ": ", e.Number, ",") 1404 } 1405 g.P("}") 1406 g.P() 1407 1408 if !enum.proto3() { 1409 g.P("func (x ", ccTypeName, ") Enum() *", ccTypeName, " {") 1410 g.P("p := new(", ccTypeName, ")") 1411 g.P("*p = x") 1412 g.P("return p") 1413 g.P("}") 1414 g.P() 1415 } 1416 1417 g.P("func (x ", ccTypeName, ") String() string {") 1418 g.P("return ", g.Pkg["proto"], ".EnumName(", ccTypeName, "_name, int32(x))") 1419 g.P("}") 1420 g.P() 1421 1422 if !enum.proto3() { 1423 g.P("func (x *", ccTypeName, ") UnmarshalJSON(data []byte) error {") 1424 g.P("value, err := ", g.Pkg["proto"], ".UnmarshalJSONEnum(", ccTypeName, `_value, data, "`, ccTypeName, `")`) 1425 g.P("if err != nil {") 1426 g.P("return err") 1427 g.P("}") 1428 g.P("*x = ", ccTypeName, "(value)") 1429 g.P("return nil") 1430 g.P("}") 1431 g.P() 1432 } 1433 1434 var indexes []string 1435 for m := enum.parent; m != nil; m = m.parent { 1436 // XXX: skip groups? 1437 indexes = append([]string{strconv.Itoa(m.index)}, indexes...) 1438 } 1439 indexes = append(indexes, strconv.Itoa(enum.index)) 1440 g.P("func (", ccTypeName, ") EnumDescriptor() ([]byte, []int) {") 1441 g.P("return ", g.file.VarName(), ", []int{", strings.Join(indexes, ", "), "}") 1442 g.P("}") 1443 g.P() 1444 if enum.file.GetPackage() == "google.protobuf" && enum.GetName() == "NullValue" { 1445 g.P("func (", ccTypeName, `) XXX_WellKnownType() string { return "`, enum.GetName(), `" }`) 1446 g.P() 1447 } 1448 1449 g.generateEnumRegistration(enum) 1450} 1451 1452// The tag is a string like "varint,2,opt,name=fieldname,def=7" that 1453// identifies details of the field for the protocol buffer marshaling and unmarshaling 1454// code. The fields are: 1455// wire encoding 1456// protocol tag number 1457// opt,req,rep for optional, required, or repeated 1458// packed whether the encoding is "packed" (optional; repeated primitives only) 1459// name= the original declared name 1460// enum= the name of the enum type if it is an enum-typed field. 1461// proto3 if this field is in a proto3 message 1462// def= string representation of the default value, if any. 1463// The default value must be in a representation that can be used at run-time 1464// to generate the default value. Thus bools become 0 and 1, for instance. 1465func (g *Generator) goTag(message *Descriptor, field *descriptor.FieldDescriptorProto, wiretype string) string { 1466 optrepreq := "" 1467 switch { 1468 case isOptional(field): 1469 optrepreq = "opt" 1470 case isRequired(field): 1471 optrepreq = "req" 1472 case isRepeated(field): 1473 optrepreq = "rep" 1474 } 1475 var defaultValue string 1476 if dv := field.DefaultValue; dv != nil { // set means an explicit default 1477 defaultValue = *dv 1478 // Some types need tweaking. 1479 switch *field.Type { 1480 case descriptor.FieldDescriptorProto_TYPE_BOOL: 1481 if defaultValue == "true" { 1482 defaultValue = "1" 1483 } else { 1484 defaultValue = "0" 1485 } 1486 case descriptor.FieldDescriptorProto_TYPE_STRING, 1487 descriptor.FieldDescriptorProto_TYPE_BYTES: 1488 // Nothing to do. Quoting is done for the whole tag. 1489 case descriptor.FieldDescriptorProto_TYPE_ENUM: 1490 // For enums we need to provide the integer constant. 1491 obj := g.ObjectNamed(field.GetTypeName()) 1492 if id, ok := obj.(*ImportedDescriptor); ok { 1493 // It is an enum that was publicly imported. 1494 // We need the underlying type. 1495 obj = id.o 1496 } 1497 enum, ok := obj.(*EnumDescriptor) 1498 if !ok { 1499 log.Printf("obj is a %T", obj) 1500 if id, ok := obj.(*ImportedDescriptor); ok { 1501 log.Printf("id.o is a %T", id.o) 1502 } 1503 g.Fail("unknown enum type", CamelCaseSlice(obj.TypeName())) 1504 } 1505 defaultValue = enum.integerValueAsString(defaultValue) 1506 case descriptor.FieldDescriptorProto_TYPE_FLOAT: 1507 if def := defaultValue; def != "inf" && def != "-inf" && def != "nan" { 1508 if f, err := strconv.ParseFloat(defaultValue, 32); err == nil { 1509 defaultValue = fmt.Sprint(float32(f)) 1510 } 1511 } 1512 case descriptor.FieldDescriptorProto_TYPE_DOUBLE: 1513 if def := defaultValue; def != "inf" && def != "-inf" && def != "nan" { 1514 if f, err := strconv.ParseFloat(defaultValue, 64); err == nil { 1515 defaultValue = fmt.Sprint(f) 1516 } 1517 } 1518 } 1519 defaultValue = ",def=" + defaultValue 1520 } 1521 enum := "" 1522 if *field.Type == descriptor.FieldDescriptorProto_TYPE_ENUM { 1523 // We avoid using obj.GoPackageName(), because we want to use the 1524 // original (proto-world) package name. 1525 obj := g.ObjectNamed(field.GetTypeName()) 1526 if id, ok := obj.(*ImportedDescriptor); ok { 1527 obj = id.o 1528 } 1529 enum = ",enum=" 1530 if pkg := obj.File().GetPackage(); pkg != "" { 1531 enum += pkg + "." 1532 } 1533 enum += CamelCaseSlice(obj.TypeName()) 1534 } 1535 packed := "" 1536 if (field.Options != nil && field.Options.GetPacked()) || 1537 // Per https://developers.google.com/protocol-buffers/docs/proto3#simple: 1538 // "In proto3, repeated fields of scalar numeric types use packed encoding by default." 1539 (message.proto3() && (field.Options == nil || field.Options.Packed == nil) && 1540 isRepeated(field) && isScalar(field)) { 1541 packed = ",packed" 1542 } 1543 fieldName := field.GetName() 1544 name := fieldName 1545 if *field.Type == descriptor.FieldDescriptorProto_TYPE_GROUP { 1546 // We must use the type name for groups instead of 1547 // the field name to preserve capitalization. 1548 // type_name in FieldDescriptorProto is fully-qualified, 1549 // but we only want the local part. 1550 name = *field.TypeName 1551 if i := strings.LastIndex(name, "."); i >= 0 { 1552 name = name[i+1:] 1553 } 1554 } 1555 if json := field.GetJsonName(); field.Extendee == nil && json != "" && json != name { 1556 // TODO: escaping might be needed, in which case 1557 // perhaps this should be in its own "json" tag. 1558 name += ",json=" + json 1559 } 1560 name = ",name=" + name 1561 if message.proto3() { 1562 name += ",proto3" 1563 } 1564 oneof := "" 1565 if field.OneofIndex != nil { 1566 oneof = ",oneof" 1567 } 1568 return strconv.Quote(fmt.Sprintf("%s,%d,%s%s%s%s%s%s", 1569 wiretype, 1570 field.GetNumber(), 1571 optrepreq, 1572 packed, 1573 name, 1574 enum, 1575 oneof, 1576 defaultValue)) 1577} 1578 1579func needsStar(typ descriptor.FieldDescriptorProto_Type) bool { 1580 switch typ { 1581 case descriptor.FieldDescriptorProto_TYPE_GROUP: 1582 return false 1583 case descriptor.FieldDescriptorProto_TYPE_MESSAGE: 1584 return false 1585 case descriptor.FieldDescriptorProto_TYPE_BYTES: 1586 return false 1587 } 1588 return true 1589} 1590 1591// TypeName is the printed name appropriate for an item. If the object is in the current file, 1592// TypeName drops the package name and underscores the rest. 1593// Otherwise the object is from another package; and the result is the underscored 1594// package name followed by the item name. 1595// The result always has an initial capital. 1596func (g *Generator) TypeName(obj Object) string { 1597 return g.DefaultPackageName(obj) + CamelCaseSlice(obj.TypeName()) 1598} 1599 1600// GoType returns a string representing the type name, and the wire type 1601func (g *Generator) GoType(message *Descriptor, field *descriptor.FieldDescriptorProto) (typ string, wire string) { 1602 // TODO: Options. 1603 switch *field.Type { 1604 case descriptor.FieldDescriptorProto_TYPE_DOUBLE: 1605 typ, wire = "float64", "fixed64" 1606 case descriptor.FieldDescriptorProto_TYPE_FLOAT: 1607 typ, wire = "float32", "fixed32" 1608 case descriptor.FieldDescriptorProto_TYPE_INT64: 1609 typ, wire = "int64", "varint" 1610 case descriptor.FieldDescriptorProto_TYPE_UINT64: 1611 typ, wire = "uint64", "varint" 1612 case descriptor.FieldDescriptorProto_TYPE_INT32: 1613 typ, wire = "int32", "varint" 1614 case descriptor.FieldDescriptorProto_TYPE_UINT32: 1615 typ, wire = "uint32", "varint" 1616 case descriptor.FieldDescriptorProto_TYPE_FIXED64: 1617 typ, wire = "uint64", "fixed64" 1618 case descriptor.FieldDescriptorProto_TYPE_FIXED32: 1619 typ, wire = "uint32", "fixed32" 1620 case descriptor.FieldDescriptorProto_TYPE_BOOL: 1621 typ, wire = "bool", "varint" 1622 case descriptor.FieldDescriptorProto_TYPE_STRING: 1623 typ, wire = "string", "bytes" 1624 case descriptor.FieldDescriptorProto_TYPE_GROUP: 1625 desc := g.ObjectNamed(field.GetTypeName()) 1626 typ, wire = "*"+g.TypeName(desc), "group" 1627 case descriptor.FieldDescriptorProto_TYPE_MESSAGE: 1628 desc := g.ObjectNamed(field.GetTypeName()) 1629 typ, wire = "*"+g.TypeName(desc), "bytes" 1630 case descriptor.FieldDescriptorProto_TYPE_BYTES: 1631 typ, wire = "[]byte", "bytes" 1632 case descriptor.FieldDescriptorProto_TYPE_ENUM: 1633 desc := g.ObjectNamed(field.GetTypeName()) 1634 typ, wire = g.TypeName(desc), "varint" 1635 case descriptor.FieldDescriptorProto_TYPE_SFIXED32: 1636 typ, wire = "int32", "fixed32" 1637 case descriptor.FieldDescriptorProto_TYPE_SFIXED64: 1638 typ, wire = "int64", "fixed64" 1639 case descriptor.FieldDescriptorProto_TYPE_SINT32: 1640 typ, wire = "int32", "zigzag32" 1641 case descriptor.FieldDescriptorProto_TYPE_SINT64: 1642 typ, wire = "int64", "zigzag64" 1643 default: 1644 g.Fail("unknown type for", field.GetName()) 1645 } 1646 if isRepeated(field) { 1647 typ = "[]" + typ 1648 } else if message != nil && message.proto3() { 1649 return 1650 } else if field.OneofIndex != nil && message != nil { 1651 return 1652 } else if needsStar(*field.Type) { 1653 typ = "*" + typ 1654 } 1655 return 1656} 1657 1658func (g *Generator) RecordTypeUse(t string) { 1659 if _, ok := g.typeNameToObject[t]; !ok { 1660 return 1661 } 1662 importPath := g.ObjectNamed(t).GoImportPath() 1663 if importPath == g.outputImportPath { 1664 // Don't record use of objects in our package. 1665 return 1666 } 1667 g.AddImport(importPath) 1668 g.usedPackages[importPath] = true 1669} 1670 1671// Method names that may be generated. Fields with these names get an 1672// underscore appended. Any change to this set is a potential incompatible 1673// API change because it changes generated field names. 1674var methodNames = [...]string{ 1675 "Reset", 1676 "String", 1677 "ProtoMessage", 1678 "Marshal", 1679 "Unmarshal", 1680 "ExtensionRangeArray", 1681 "ExtensionMap", 1682 "Descriptor", 1683} 1684 1685// Names of messages in the `google.protobuf` package for which 1686// we will generate XXX_WellKnownType methods. 1687var wellKnownTypes = map[string]bool{ 1688 "Any": true, 1689 "Duration": true, 1690 "Empty": true, 1691 "Struct": true, 1692 "Timestamp": true, 1693 1694 "Value": true, 1695 "ListValue": true, 1696 "DoubleValue": true, 1697 "FloatValue": true, 1698 "Int64Value": true, 1699 "UInt64Value": true, 1700 "Int32Value": true, 1701 "UInt32Value": true, 1702 "BoolValue": true, 1703 "StringValue": true, 1704 "BytesValue": true, 1705} 1706 1707// getterDefault finds the default value for the field to return from a getter, 1708// regardless of if it's a built in default or explicit from the source. Returns e.g. "nil", `""`, "Default_MessageType_FieldName" 1709func (g *Generator) getterDefault(field *descriptor.FieldDescriptorProto, goMessageType string) string { 1710 if isRepeated(field) { 1711 return "nil" 1712 } 1713 if def := field.GetDefaultValue(); def != "" { 1714 defaultConstant := g.defaultConstantName(goMessageType, field.GetName()) 1715 if *field.Type != descriptor.FieldDescriptorProto_TYPE_BYTES { 1716 return defaultConstant 1717 } 1718 return "append([]byte(nil), " + defaultConstant + "...)" 1719 } 1720 switch *field.Type { 1721 case descriptor.FieldDescriptorProto_TYPE_BOOL: 1722 return "false" 1723 case descriptor.FieldDescriptorProto_TYPE_STRING: 1724 return `""` 1725 case descriptor.FieldDescriptorProto_TYPE_GROUP, descriptor.FieldDescriptorProto_TYPE_MESSAGE, descriptor.FieldDescriptorProto_TYPE_BYTES: 1726 return "nil" 1727 case descriptor.FieldDescriptorProto_TYPE_ENUM: 1728 obj := g.ObjectNamed(field.GetTypeName()) 1729 var enum *EnumDescriptor 1730 if id, ok := obj.(*ImportedDescriptor); ok { 1731 // The enum type has been publicly imported. 1732 enum, _ = id.o.(*EnumDescriptor) 1733 } else { 1734 enum, _ = obj.(*EnumDescriptor) 1735 } 1736 if enum == nil { 1737 log.Printf("don't know how to generate getter for %s", field.GetName()) 1738 return "nil" 1739 } 1740 if len(enum.Value) == 0 { 1741 return "0 // empty enum" 1742 } 1743 first := enum.Value[0].GetName() 1744 return g.DefaultPackageName(obj) + enum.prefix() + first 1745 default: 1746 return "0" 1747 } 1748} 1749 1750// defaultConstantName builds the name of the default constant from the message 1751// type name and the untouched field name, e.g. "Default_MessageType_FieldName" 1752func (g *Generator) defaultConstantName(goMessageType, protoFieldName string) string { 1753 return "Default_" + goMessageType + "_" + CamelCase(protoFieldName) 1754} 1755 1756// The different types of fields in a message and how to actually print them 1757// Most of the logic for generateMessage is in the methods of these types. 1758// 1759// Note that the content of the field is irrelevant, a simpleField can contain 1760// anything from a scalar to a group (which is just a message). 1761// 1762// Extension fields (and message sets) are however handled separately. 1763// 1764// simpleField - a field that is neiter weak nor oneof, possibly repeated 1765// oneofField - field containing list of subfields: 1766// - oneofSubField - a field within the oneof 1767 1768// msgCtx contains the context for the generator functions. 1769type msgCtx struct { 1770 goName string // Go struct name of the message, e.g. MessageName 1771 message *Descriptor // The descriptor for the message 1772} 1773 1774// fieldCommon contains data common to all types of fields. 1775type fieldCommon struct { 1776 goName string // Go name of field, e.g. "FieldName" or "Descriptor_" 1777 protoName string // Name of field in proto language, e.g. "field_name" or "descriptor" 1778 getterName string // Name of the getter, e.g. "GetFieldName" or "GetDescriptor_" 1779 goType string // The Go type as a string, e.g. "*int32" or "*OtherMessage" 1780 tags string // The tag string/annotation for the type, e.g. `protobuf:"varint,8,opt,name=region_id,json=regionId"` 1781 fullPath string // The full path of the field as used by Annotate etc, e.g. "4,0,2,0" 1782} 1783 1784// getProtoName gets the proto name of a field, e.g. "field_name" or "descriptor". 1785func (f *fieldCommon) getProtoName() string { 1786 return f.protoName 1787} 1788 1789// getGoType returns the go type of the field as a string, e.g. "*int32". 1790func (f *fieldCommon) getGoType() string { 1791 return f.goType 1792} 1793 1794// simpleField is not weak, not a oneof, not an extension. Can be required, optional or repeated. 1795type simpleField struct { 1796 fieldCommon 1797 protoTypeName string // Proto type name, empty if primitive, e.g. ".google.protobuf.Duration" 1798 protoType descriptor.FieldDescriptorProto_Type // Actual type enum value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64 1799 deprecated string // Deprecation comment, if any, e.g. "// Deprecated: Do not use." 1800 getterDef string // Default for getters, e.g. "nil", `""` or "Default_MessageType_FieldName" 1801 protoDef string // Default value as defined in the proto file, e.g "yoshi" or "5" 1802 comment string // The full comment for the field, e.g. "// Useful information" 1803} 1804 1805// decl prints the declaration of the field in the struct (if any). 1806func (f *simpleField) decl(g *Generator, mc *msgCtx) { 1807 g.P(f.comment, Annotate(mc.message.file, f.fullPath, f.goName), "\t", f.goType, "\t`", f.tags, "`", f.deprecated) 1808} 1809 1810// getter prints the getter for the field. 1811func (f *simpleField) getter(g *Generator, mc *msgCtx) { 1812 star := "" 1813 tname := f.goType 1814 if needsStar(f.protoType) && tname[0] == '*' { 1815 tname = tname[1:] 1816 star = "*" 1817 } 1818 if f.deprecated != "" { 1819 g.P(f.deprecated) 1820 } 1821 g.P("func (m *", mc.goName, ") ", Annotate(mc.message.file, f.fullPath, f.getterName), "() "+tname+" {") 1822 if f.getterDef == "nil" { // Simpler getter 1823 g.P("if m != nil {") 1824 g.P("return m." + f.goName) 1825 g.P("}") 1826 g.P("return nil") 1827 g.P("}") 1828 g.P() 1829 return 1830 } 1831 if mc.message.proto3() { 1832 g.P("if m != nil {") 1833 } else { 1834 g.P("if m != nil && m." + f.goName + " != nil {") 1835 } 1836 g.P("return " + star + "m." + f.goName) 1837 g.P("}") 1838 g.P("return ", f.getterDef) 1839 g.P("}") 1840 g.P() 1841} 1842 1843// setter prints the setter method of the field. 1844func (f *simpleField) setter(g *Generator, mc *msgCtx) { 1845 // No setter for regular fields yet 1846} 1847 1848// getProtoDef returns the default value explicitly stated in the proto file, e.g "yoshi" or "5". 1849func (f *simpleField) getProtoDef() string { 1850 return f.protoDef 1851} 1852 1853// getProtoTypeName returns the protobuf type name for the field as returned by field.GetTypeName(), e.g. ".google.protobuf.Duration". 1854func (f *simpleField) getProtoTypeName() string { 1855 return f.protoTypeName 1856} 1857 1858// getProtoType returns the *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64. 1859func (f *simpleField) getProtoType() descriptor.FieldDescriptorProto_Type { 1860 return f.protoType 1861} 1862 1863// oneofSubFields are kept slize held by each oneofField. They do not appear in the top level slize of fields for the message. 1864type oneofSubField struct { 1865 fieldCommon 1866 protoTypeName string // Proto type name, empty if primitive, e.g. ".google.protobuf.Duration" 1867 protoType descriptor.FieldDescriptorProto_Type // Actual type enum value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64 1868 oneofTypeName string // Type name of the enclosing struct, e.g. "MessageName_FieldName" 1869 fieldNumber int // Actual field number, as defined in proto, e.g. 12 1870 getterDef string // Default for getters, e.g. "nil", `""` or "Default_MessageType_FieldName" 1871 protoDef string // Default value as defined in the proto file, e.g "yoshi" or "5" 1872 deprecated string // Deprecation comment, if any. 1873} 1874 1875// typedNil prints a nil casted to the pointer to this field. 1876// - for XXX_OneofWrappers 1877func (f *oneofSubField) typedNil(g *Generator) { 1878 g.P("(*", f.oneofTypeName, ")(nil),") 1879} 1880 1881// getProtoDef returns the default value explicitly stated in the proto file, e.g "yoshi" or "5". 1882func (f *oneofSubField) getProtoDef() string { 1883 return f.protoDef 1884} 1885 1886// getProtoTypeName returns the protobuf type name for the field as returned by field.GetTypeName(), e.g. ".google.protobuf.Duration". 1887func (f *oneofSubField) getProtoTypeName() string { 1888 return f.protoTypeName 1889} 1890 1891// getProtoType returns the *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64. 1892func (f *oneofSubField) getProtoType() descriptor.FieldDescriptorProto_Type { 1893 return f.protoType 1894} 1895 1896// oneofField represents the oneof on top level. 1897// The alternative fields within the oneof are represented by oneofSubField. 1898type oneofField struct { 1899 fieldCommon 1900 subFields []*oneofSubField // All the possible oneof fields 1901 comment string // The full comment for the field, e.g. "// Types that are valid to be assigned to MyOneof:\n\\" 1902} 1903 1904// decl prints the declaration of the field in the struct (if any). 1905func (f *oneofField) decl(g *Generator, mc *msgCtx) { 1906 comment := f.comment 1907 for _, sf := range f.subFields { 1908 comment += "//\t*" + sf.oneofTypeName + "\n" 1909 } 1910 g.P(comment, Annotate(mc.message.file, f.fullPath, f.goName), " ", f.goType, " `", f.tags, "`") 1911} 1912 1913// getter for a oneof field will print additional discriminators and interfaces for the oneof, 1914// also it prints all the getters for the sub fields. 1915func (f *oneofField) getter(g *Generator, mc *msgCtx) { 1916 // The discriminator type 1917 g.P("type ", f.goType, " interface {") 1918 g.P(f.goType, "()") 1919 g.P("}") 1920 g.P() 1921 // The subField types, fulfilling the discriminator type contract 1922 for _, sf := range f.subFields { 1923 g.P("type ", Annotate(mc.message.file, sf.fullPath, sf.oneofTypeName), " struct {") 1924 g.P(Annotate(mc.message.file, sf.fullPath, sf.goName), " ", sf.goType, " `", sf.tags, "`") 1925 g.P("}") 1926 g.P() 1927 } 1928 for _, sf := range f.subFields { 1929 g.P("func (*", sf.oneofTypeName, ") ", f.goType, "() {}") 1930 g.P() 1931 } 1932 // Getter for the oneof field 1933 g.P("func (m *", mc.goName, ") ", Annotate(mc.message.file, f.fullPath, f.getterName), "() ", f.goType, " {") 1934 g.P("if m != nil { return m.", f.goName, " }") 1935 g.P("return nil") 1936 g.P("}") 1937 g.P() 1938 // Getters for each oneof 1939 for _, sf := range f.subFields { 1940 if sf.deprecated != "" { 1941 g.P(sf.deprecated) 1942 } 1943 g.P("func (m *", mc.goName, ") ", Annotate(mc.message.file, sf.fullPath, sf.getterName), "() "+sf.goType+" {") 1944 g.P("if x, ok := m.", f.getterName, "().(*", sf.oneofTypeName, "); ok {") 1945 g.P("return x.", sf.goName) 1946 g.P("}") 1947 g.P("return ", sf.getterDef) 1948 g.P("}") 1949 g.P() 1950 } 1951} 1952 1953// setter prints the setter method of the field. 1954func (f *oneofField) setter(g *Generator, mc *msgCtx) { 1955 // No setters for oneof yet 1956} 1957 1958// topLevelField interface implemented by all types of fields on the top level (not oneofSubField). 1959type topLevelField interface { 1960 decl(g *Generator, mc *msgCtx) // print declaration within the struct 1961 getter(g *Generator, mc *msgCtx) // print getter 1962 setter(g *Generator, mc *msgCtx) // print setter if applicable 1963} 1964 1965// defField interface implemented by all types of fields that can have defaults (not oneofField, but instead oneofSubField). 1966type defField interface { 1967 getProtoDef() string // default value explicitly stated in the proto file, e.g "yoshi" or "5" 1968 getProtoName() string // proto name of a field, e.g. "field_name" or "descriptor" 1969 getGoType() string // go type of the field as a string, e.g. "*int32" 1970 getProtoTypeName() string // protobuf type name for the field, e.g. ".google.protobuf.Duration" 1971 getProtoType() descriptor.FieldDescriptorProto_Type // *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64 1972} 1973 1974// generateDefaultConstants adds constants for default values if needed, which is only if the default value is. 1975// explicit in the proto. 1976func (g *Generator) generateDefaultConstants(mc *msgCtx, topLevelFields []topLevelField) { 1977 // Collect fields that can have defaults 1978 dFields := []defField{} 1979 for _, pf := range topLevelFields { 1980 if f, ok := pf.(*oneofField); ok { 1981 for _, osf := range f.subFields { 1982 dFields = append(dFields, osf) 1983 } 1984 continue 1985 } 1986 dFields = append(dFields, pf.(defField)) 1987 } 1988 for _, df := range dFields { 1989 def := df.getProtoDef() 1990 if def == "" { 1991 continue 1992 } 1993 fieldname := g.defaultConstantName(mc.goName, df.getProtoName()) 1994 typename := df.getGoType() 1995 if typename[0] == '*' { 1996 typename = typename[1:] 1997 } 1998 kind := "const " 1999 switch { 2000 case typename == "bool": 2001 case typename == "string": 2002 def = strconv.Quote(def) 2003 case typename == "[]byte": 2004 def = "[]byte(" + strconv.Quote(unescape(def)) + ")" 2005 kind = "var " 2006 case def == "inf", def == "-inf", def == "nan": 2007 // These names are known to, and defined by, the protocol language. 2008 switch def { 2009 case "inf": 2010 def = "math.Inf(1)" 2011 case "-inf": 2012 def = "math.Inf(-1)" 2013 case "nan": 2014 def = "math.NaN()" 2015 } 2016 if df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_FLOAT { 2017 def = "float32(" + def + ")" 2018 } 2019 kind = "var " 2020 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_FLOAT: 2021 if f, err := strconv.ParseFloat(def, 32); err == nil { 2022 def = fmt.Sprint(float32(f)) 2023 } 2024 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_DOUBLE: 2025 if f, err := strconv.ParseFloat(def, 64); err == nil { 2026 def = fmt.Sprint(f) 2027 } 2028 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_ENUM: 2029 // Must be an enum. Need to construct the prefixed name. 2030 obj := g.ObjectNamed(df.getProtoTypeName()) 2031 var enum *EnumDescriptor 2032 if id, ok := obj.(*ImportedDescriptor); ok { 2033 // The enum type has been publicly imported. 2034 enum, _ = id.o.(*EnumDescriptor) 2035 } else { 2036 enum, _ = obj.(*EnumDescriptor) 2037 } 2038 if enum == nil { 2039 log.Printf("don't know how to generate constant for %s", fieldname) 2040 continue 2041 } 2042 def = g.DefaultPackageName(obj) + enum.prefix() + def 2043 } 2044 g.P(kind, fieldname, " ", typename, " = ", def) 2045 g.file.addExport(mc.message, constOrVarSymbol{fieldname, kind, ""}) 2046 } 2047 g.P() 2048} 2049 2050// generateInternalStructFields just adds the XXX_<something> fields to the message struct. 2051func (g *Generator) generateInternalStructFields(mc *msgCtx, topLevelFields []topLevelField) { 2052 g.P("XXX_NoUnkeyedLiteral\tstruct{} `json:\"-\"`") // prevent unkeyed struct literals 2053 if len(mc.message.ExtensionRange) > 0 { 2054 messageset := "" 2055 if opts := mc.message.Options; opts != nil && opts.GetMessageSetWireFormat() { 2056 messageset = "protobuf_messageset:\"1\" " 2057 } 2058 g.P(g.Pkg["proto"], ".XXX_InternalExtensions `", messageset, "json:\"-\"`") 2059 } 2060 g.P("XXX_unrecognized\t[]byte `json:\"-\"`") 2061 g.P("XXX_sizecache\tint32 `json:\"-\"`") 2062 2063} 2064 2065// generateOneofFuncs adds all the utility functions for oneof, including marshaling, unmarshaling and sizer. 2066func (g *Generator) generateOneofFuncs(mc *msgCtx, topLevelFields []topLevelField) { 2067 ofields := []*oneofField{} 2068 for _, f := range topLevelFields { 2069 if o, ok := f.(*oneofField); ok { 2070 ofields = append(ofields, o) 2071 } 2072 } 2073 if len(ofields) == 0 { 2074 return 2075 } 2076 2077 // OneofFuncs 2078 g.P("// XXX_OneofWrappers is for the internal use of the proto package.") 2079 g.P("func (*", mc.goName, ") XXX_OneofWrappers() []interface{} {") 2080 g.P("return []interface{}{") 2081 for _, of := range ofields { 2082 for _, sf := range of.subFields { 2083 sf.typedNil(g) 2084 } 2085 } 2086 g.P("}") 2087 g.P("}") 2088 g.P() 2089} 2090 2091// generateMessageStruct adds the actual struct with it's members (but not methods) to the output. 2092func (g *Generator) generateMessageStruct(mc *msgCtx, topLevelFields []topLevelField) { 2093 comments := g.PrintComments(mc.message.path) 2094 2095 // Guarantee deprecation comments appear after user-provided comments. 2096 if mc.message.GetOptions().GetDeprecated() { 2097 if comments { 2098 // Convention: Separate deprecation comments from original 2099 // comments with an empty line. 2100 g.P("//") 2101 } 2102 g.P(deprecationComment) 2103 } 2104 2105 g.P("type ", Annotate(mc.message.file, mc.message.path, mc.goName), " struct {") 2106 for _, pf := range topLevelFields { 2107 pf.decl(g, mc) 2108 } 2109 g.generateInternalStructFields(mc, topLevelFields) 2110 g.P("}") 2111} 2112 2113// generateGetters adds getters for all fields, including oneofs and weak fields when applicable. 2114func (g *Generator) generateGetters(mc *msgCtx, topLevelFields []topLevelField) { 2115 for _, pf := range topLevelFields { 2116 pf.getter(g, mc) 2117 } 2118} 2119 2120// generateSetters add setters for all fields, including oneofs and weak fields when applicable. 2121func (g *Generator) generateSetters(mc *msgCtx, topLevelFields []topLevelField) { 2122 for _, pf := range topLevelFields { 2123 pf.setter(g, mc) 2124 } 2125} 2126 2127// generateCommonMethods adds methods to the message that are not on a per field basis. 2128func (g *Generator) generateCommonMethods(mc *msgCtx) { 2129 // Reset, String and ProtoMessage methods. 2130 g.P("func (m *", mc.goName, ") Reset() { *m = ", mc.goName, "{} }") 2131 g.P("func (m *", mc.goName, ") String() string { return ", g.Pkg["proto"], ".CompactTextString(m) }") 2132 g.P("func (*", mc.goName, ") ProtoMessage() {}") 2133 var indexes []string 2134 for m := mc.message; m != nil; m = m.parent { 2135 indexes = append([]string{strconv.Itoa(m.index)}, indexes...) 2136 } 2137 g.P("func (*", mc.goName, ") Descriptor() ([]byte, []int) {") 2138 g.P("return ", g.file.VarName(), ", []int{", strings.Join(indexes, ", "), "}") 2139 g.P("}") 2140 g.P() 2141 // TODO: Revisit the decision to use a XXX_WellKnownType method 2142 // if we change proto.MessageName to work with multiple equivalents. 2143 if mc.message.file.GetPackage() == "google.protobuf" && wellKnownTypes[mc.message.GetName()] { 2144 g.P("func (*", mc.goName, `) XXX_WellKnownType() string { return "`, mc.message.GetName(), `" }`) 2145 g.P() 2146 } 2147 2148 // Extension support methods 2149 if len(mc.message.ExtensionRange) > 0 { 2150 g.P() 2151 g.P("var extRange_", mc.goName, " = []", g.Pkg["proto"], ".ExtensionRange{") 2152 for _, r := range mc.message.ExtensionRange { 2153 end := fmt.Sprint(*r.End - 1) // make range inclusive on both ends 2154 g.P("{Start: ", r.Start, ", End: ", end, "},") 2155 } 2156 g.P("}") 2157 g.P("func (*", mc.goName, ") ExtensionRangeArray() []", g.Pkg["proto"], ".ExtensionRange {") 2158 g.P("return extRange_", mc.goName) 2159 g.P("}") 2160 g.P() 2161 } 2162 2163 // TODO: It does not scale to keep adding another method for every 2164 // operation on protos that we want to switch over to using the 2165 // table-driven approach. Instead, we should only add a single method 2166 // that allows getting access to the *InternalMessageInfo struct and then 2167 // calling Unmarshal, Marshal, Merge, Size, and Discard directly on that. 2168 2169 // Wrapper for table-driven marshaling and unmarshaling. 2170 g.P("func (m *", mc.goName, ") XXX_Unmarshal(b []byte) error {") 2171 g.P("return xxx_messageInfo_", mc.goName, ".Unmarshal(m, b)") 2172 g.P("}") 2173 2174 g.P("func (m *", mc.goName, ") XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {") 2175 g.P("return xxx_messageInfo_", mc.goName, ".Marshal(b, m, deterministic)") 2176 g.P("}") 2177 2178 g.P("func (m *", mc.goName, ") XXX_Merge(src ", g.Pkg["proto"], ".Message) {") 2179 g.P("xxx_messageInfo_", mc.goName, ".Merge(m, src)") 2180 g.P("}") 2181 2182 g.P("func (m *", mc.goName, ") XXX_Size() int {") // avoid name clash with "Size" field in some message 2183 g.P("return xxx_messageInfo_", mc.goName, ".Size(m)") 2184 g.P("}") 2185 2186 g.P("func (m *", mc.goName, ") XXX_DiscardUnknown() {") 2187 g.P("xxx_messageInfo_", mc.goName, ".DiscardUnknown(m)") 2188 g.P("}") 2189 2190 g.P("var xxx_messageInfo_", mc.goName, " ", g.Pkg["proto"], ".InternalMessageInfo") 2191 g.P() 2192} 2193 2194// Generate the type, methods and default constant definitions for this Descriptor. 2195func (g *Generator) generateMessage(message *Descriptor) { 2196 topLevelFields := []topLevelField{} 2197 oFields := make(map[int32]*oneofField) 2198 // The full type name 2199 typeName := message.TypeName() 2200 // The full type name, CamelCased. 2201 goTypeName := CamelCaseSlice(typeName) 2202 2203 usedNames := make(map[string]bool) 2204 for _, n := range methodNames { 2205 usedNames[n] = true 2206 } 2207 2208 // allocNames finds a conflict-free variation of the given strings, 2209 // consistently mutating their suffixes. 2210 // It returns the same number of strings. 2211 allocNames := func(ns ...string) []string { 2212 Loop: 2213 for { 2214 for _, n := range ns { 2215 if usedNames[n] { 2216 for i := range ns { 2217 ns[i] += "_" 2218 } 2219 continue Loop 2220 } 2221 } 2222 for _, n := range ns { 2223 usedNames[n] = true 2224 } 2225 return ns 2226 } 2227 } 2228 2229 mapFieldTypes := make(map[*descriptor.FieldDescriptorProto]string) // keep track of the map fields to be added later 2230 2231 // Build a structure more suitable for generating the text in one pass 2232 for i, field := range message.Field { 2233 // Allocate the getter and the field at the same time so name 2234 // collisions create field/method consistent names. 2235 // TODO: This allocation occurs based on the order of the fields 2236 // in the proto file, meaning that a change in the field 2237 // ordering can change generated Method/Field names. 2238 base := CamelCase(*field.Name) 2239 ns := allocNames(base, "Get"+base) 2240 fieldName, fieldGetterName := ns[0], ns[1] 2241 typename, wiretype := g.GoType(message, field) 2242 jsonName := *field.Name 2243 tag := fmt.Sprintf("protobuf:%s json:%q", g.goTag(message, field, wiretype), jsonName+",omitempty") 2244 2245 oneof := field.OneofIndex != nil 2246 if oneof && oFields[*field.OneofIndex] == nil { 2247 odp := message.OneofDecl[int(*field.OneofIndex)] 2248 base := CamelCase(odp.GetName()) 2249 fname := allocNames(base)[0] 2250 2251 // This is the first field of a oneof we haven't seen before. 2252 // Generate the union field. 2253 oneofFullPath := fmt.Sprintf("%s,%d,%d", message.path, messageOneofPath, *field.OneofIndex) 2254 c, ok := g.makeComments(oneofFullPath) 2255 if ok { 2256 c += "\n//\n" 2257 } 2258 c += "// Types that are valid to be assigned to " + fname + ":\n" 2259 // Generate the rest of this comment later, 2260 // when we've computed any disambiguation. 2261 2262 dname := "is" + goTypeName + "_" + fname 2263 tag := `protobuf_oneof:"` + odp.GetName() + `"` 2264 of := oneofField{ 2265 fieldCommon: fieldCommon{ 2266 goName: fname, 2267 getterName: "Get" + fname, 2268 goType: dname, 2269 tags: tag, 2270 protoName: odp.GetName(), 2271 fullPath: oneofFullPath, 2272 }, 2273 comment: c, 2274 } 2275 topLevelFields = append(topLevelFields, &of) 2276 oFields[*field.OneofIndex] = &of 2277 } 2278 2279 if *field.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE { 2280 desc := g.ObjectNamed(field.GetTypeName()) 2281 if d, ok := desc.(*Descriptor); ok && d.GetOptions().GetMapEntry() { 2282 // Figure out the Go types and tags for the key and value types. 2283 keyField, valField := d.Field[0], d.Field[1] 2284 keyType, keyWire := g.GoType(d, keyField) 2285 valType, valWire := g.GoType(d, valField) 2286 keyTag, valTag := g.goTag(d, keyField, keyWire), g.goTag(d, valField, valWire) 2287 2288 // We don't use stars, except for message-typed values. 2289 // Message and enum types are the only two possibly foreign types used in maps, 2290 // so record their use. They are not permitted as map keys. 2291 keyType = strings.TrimPrefix(keyType, "*") 2292 switch *valField.Type { 2293 case descriptor.FieldDescriptorProto_TYPE_ENUM: 2294 valType = strings.TrimPrefix(valType, "*") 2295 g.RecordTypeUse(valField.GetTypeName()) 2296 case descriptor.FieldDescriptorProto_TYPE_MESSAGE: 2297 g.RecordTypeUse(valField.GetTypeName()) 2298 default: 2299 valType = strings.TrimPrefix(valType, "*") 2300 } 2301 2302 typename = fmt.Sprintf("map[%s]%s", keyType, valType) 2303 mapFieldTypes[field] = typename // record for the getter generation 2304 2305 tag += fmt.Sprintf(" protobuf_key:%s protobuf_val:%s", keyTag, valTag) 2306 } 2307 } 2308 2309 fieldDeprecated := "" 2310 if field.GetOptions().GetDeprecated() { 2311 fieldDeprecated = deprecationComment 2312 } 2313 2314 dvalue := g.getterDefault(field, goTypeName) 2315 if oneof { 2316 tname := goTypeName + "_" + fieldName 2317 // It is possible for this to collide with a message or enum 2318 // nested in this message. Check for collisions. 2319 for { 2320 ok := true 2321 for _, desc := range message.nested { 2322 if CamelCaseSlice(desc.TypeName()) == tname { 2323 ok = false 2324 break 2325 } 2326 } 2327 for _, enum := range message.enums { 2328 if CamelCaseSlice(enum.TypeName()) == tname { 2329 ok = false 2330 break 2331 } 2332 } 2333 if !ok { 2334 tname += "_" 2335 continue 2336 } 2337 break 2338 } 2339 2340 oneofField := oFields[*field.OneofIndex] 2341 tag := "protobuf:" + g.goTag(message, field, wiretype) 2342 sf := oneofSubField{ 2343 fieldCommon: fieldCommon{ 2344 goName: fieldName, 2345 getterName: fieldGetterName, 2346 goType: typename, 2347 tags: tag, 2348 protoName: field.GetName(), 2349 fullPath: fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i), 2350 }, 2351 protoTypeName: field.GetTypeName(), 2352 fieldNumber: int(*field.Number), 2353 protoType: *field.Type, 2354 getterDef: dvalue, 2355 protoDef: field.GetDefaultValue(), 2356 oneofTypeName: tname, 2357 deprecated: fieldDeprecated, 2358 } 2359 oneofField.subFields = append(oneofField.subFields, &sf) 2360 g.RecordTypeUse(field.GetTypeName()) 2361 continue 2362 } 2363 2364 fieldFullPath := fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i) 2365 c, ok := g.makeComments(fieldFullPath) 2366 if ok { 2367 c += "\n" 2368 } 2369 rf := simpleField{ 2370 fieldCommon: fieldCommon{ 2371 goName: fieldName, 2372 getterName: fieldGetterName, 2373 goType: typename, 2374 tags: tag, 2375 protoName: field.GetName(), 2376 fullPath: fieldFullPath, 2377 }, 2378 protoTypeName: field.GetTypeName(), 2379 protoType: *field.Type, 2380 deprecated: fieldDeprecated, 2381 getterDef: dvalue, 2382 protoDef: field.GetDefaultValue(), 2383 comment: c, 2384 } 2385 var pf topLevelField = &rf 2386 2387 topLevelFields = append(topLevelFields, pf) 2388 g.RecordTypeUse(field.GetTypeName()) 2389 } 2390 2391 mc := &msgCtx{ 2392 goName: goTypeName, 2393 message: message, 2394 } 2395 2396 g.generateMessageStruct(mc, topLevelFields) 2397 g.P() 2398 g.generateCommonMethods(mc) 2399 g.P() 2400 g.generateDefaultConstants(mc, topLevelFields) 2401 g.P() 2402 g.generateGetters(mc, topLevelFields) 2403 g.P() 2404 g.generateSetters(mc, topLevelFields) 2405 g.P() 2406 g.generateOneofFuncs(mc, topLevelFields) 2407 g.P() 2408 2409 var oneofTypes []string 2410 for _, f := range topLevelFields { 2411 if of, ok := f.(*oneofField); ok { 2412 for _, osf := range of.subFields { 2413 oneofTypes = append(oneofTypes, osf.oneofTypeName) 2414 } 2415 } 2416 } 2417 2418 opts := message.Options 2419 ms := &messageSymbol{ 2420 sym: goTypeName, 2421 hasExtensions: len(message.ExtensionRange) > 0, 2422 isMessageSet: opts != nil && opts.GetMessageSetWireFormat(), 2423 oneofTypes: oneofTypes, 2424 } 2425 g.file.addExport(message, ms) 2426 2427 for _, ext := range message.ext { 2428 g.generateExtension(ext) 2429 } 2430 2431 fullName := strings.Join(message.TypeName(), ".") 2432 if g.file.Package != nil { 2433 fullName = *g.file.Package + "." + fullName 2434 } 2435 2436 g.addInitf("%s.RegisterType((*%s)(nil), %q)", g.Pkg["proto"], goTypeName, fullName) 2437 // Register types for native map types. 2438 for _, k := range mapFieldKeys(mapFieldTypes) { 2439 fullName := strings.TrimPrefix(*k.TypeName, ".") 2440 g.addInitf("%s.RegisterMapType((%s)(nil), %q)", g.Pkg["proto"], mapFieldTypes[k], fullName) 2441 } 2442 2443} 2444 2445type byTypeName []*descriptor.FieldDescriptorProto 2446 2447func (a byTypeName) Len() int { return len(a) } 2448func (a byTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 2449func (a byTypeName) Less(i, j int) bool { return *a[i].TypeName < *a[j].TypeName } 2450 2451// mapFieldKeys returns the keys of m in a consistent order. 2452func mapFieldKeys(m map[*descriptor.FieldDescriptorProto]string) []*descriptor.FieldDescriptorProto { 2453 keys := make([]*descriptor.FieldDescriptorProto, 0, len(m)) 2454 for k := range m { 2455 keys = append(keys, k) 2456 } 2457 sort.Sort(byTypeName(keys)) 2458 return keys 2459} 2460 2461var escapeChars = [256]byte{ 2462 'a': '\a', 'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t', 'v': '\v', '\\': '\\', '"': '"', '\'': '\'', '?': '?', 2463} 2464 2465// unescape reverses the "C" escaping that protoc does for default values of bytes fields. 2466// It is best effort in that it effectively ignores malformed input. Seemingly invalid escape 2467// sequences are conveyed, unmodified, into the decoded result. 2468func unescape(s string) string { 2469 // NB: Sadly, we can't use strconv.Unquote because protoc will escape both 2470 // single and double quotes, but strconv.Unquote only allows one or the 2471 // other (based on actual surrounding quotes of its input argument). 2472 2473 var out []byte 2474 for len(s) > 0 { 2475 // regular character, or too short to be valid escape 2476 if s[0] != '\\' || len(s) < 2 { 2477 out = append(out, s[0]) 2478 s = s[1:] 2479 } else if c := escapeChars[s[1]]; c != 0 { 2480 // escape sequence 2481 out = append(out, c) 2482 s = s[2:] 2483 } else if s[1] == 'x' || s[1] == 'X' { 2484 // hex escape, e.g. "\x80 2485 if len(s) < 4 { 2486 // too short to be valid 2487 out = append(out, s[:2]...) 2488 s = s[2:] 2489 continue 2490 } 2491 v, err := strconv.ParseUint(s[2:4], 16, 8) 2492 if err != nil { 2493 out = append(out, s[:4]...) 2494 } else { 2495 out = append(out, byte(v)) 2496 } 2497 s = s[4:] 2498 } else if '0' <= s[1] && s[1] <= '7' { 2499 // octal escape, can vary from 1 to 3 octal digits; e.g., "\0" "\40" or "\164" 2500 // so consume up to 2 more bytes or up to end-of-string 2501 n := len(s[1:]) - len(strings.TrimLeft(s[1:], "01234567")) 2502 if n > 3 { 2503 n = 3 2504 } 2505 v, err := strconv.ParseUint(s[1:1+n], 8, 8) 2506 if err != nil { 2507 out = append(out, s[:1+n]...) 2508 } else { 2509 out = append(out, byte(v)) 2510 } 2511 s = s[1+n:] 2512 } else { 2513 // bad escape, just propagate the slash as-is 2514 out = append(out, s[0]) 2515 s = s[1:] 2516 } 2517 } 2518 2519 return string(out) 2520} 2521 2522func (g *Generator) generateExtension(ext *ExtensionDescriptor) { 2523 ccTypeName := ext.DescName() 2524 2525 extObj := g.ObjectNamed(*ext.Extendee) 2526 var extDesc *Descriptor 2527 if id, ok := extObj.(*ImportedDescriptor); ok { 2528 // This is extending a publicly imported message. 2529 // We need the underlying type for goTag. 2530 extDesc = id.o.(*Descriptor) 2531 } else { 2532 extDesc = extObj.(*Descriptor) 2533 } 2534 extendedType := "*" + g.TypeName(extObj) // always use the original 2535 field := ext.FieldDescriptorProto 2536 fieldType, wireType := g.GoType(ext.parent, field) 2537 tag := g.goTag(extDesc, field, wireType) 2538 g.RecordTypeUse(*ext.Extendee) 2539 if n := ext.FieldDescriptorProto.TypeName; n != nil { 2540 // foreign extension type 2541 g.RecordTypeUse(*n) 2542 } 2543 2544 typeName := ext.TypeName() 2545 2546 // Special case for proto2 message sets: If this extension is extending 2547 // proto2.bridge.MessageSet, and its final name component is "message_set_extension", 2548 // then drop that last component. 2549 // 2550 // TODO: This should be implemented in the text formatter rather than the generator. 2551 // In addition, the situation for when to apply this special case is implemented 2552 // differently in other languages: 2553 // https://github.com/google/protobuf/blob/aff10976/src/google/protobuf/text_format.cc#L1560 2554 if extDesc.GetOptions().GetMessageSetWireFormat() && typeName[len(typeName)-1] == "message_set_extension" { 2555 typeName = typeName[:len(typeName)-1] 2556 } 2557 2558 // For text formatting, the package must be exactly what the .proto file declares, 2559 // ignoring overrides such as the go_package option, and with no dot/underscore mapping. 2560 extName := strings.Join(typeName, ".") 2561 if g.file.Package != nil { 2562 extName = *g.file.Package + "." + extName 2563 } 2564 2565 g.P("var ", ccTypeName, " = &", g.Pkg["proto"], ".ExtensionDesc{") 2566 g.P("ExtendedType: (", extendedType, ")(nil),") 2567 g.P("ExtensionType: (", fieldType, ")(nil),") 2568 g.P("Field: ", field.Number, ",") 2569 g.P(`Name: "`, extName, `",`) 2570 g.P("Tag: ", tag, ",") 2571 g.P(`Filename: "`, g.file.GetName(), `",`) 2572 2573 g.P("}") 2574 g.P() 2575 2576 g.addInitf("%s.RegisterExtension(%s)", g.Pkg["proto"], ext.DescName()) 2577 2578 g.file.addExport(ext, constOrVarSymbol{ccTypeName, "var", ""}) 2579} 2580 2581func (g *Generator) generateInitFunction() { 2582 if len(g.init) == 0 { 2583 return 2584 } 2585 g.P("func init() {") 2586 for _, l := range g.init { 2587 g.P(l) 2588 } 2589 g.P("}") 2590 g.init = nil 2591} 2592 2593func (g *Generator) generateFileDescriptor(file *FileDescriptor) { 2594 // Make a copy and trim source_code_info data. 2595 // TODO: Trim this more when we know exactly what we need. 2596 pb := proto.Clone(file.FileDescriptorProto).(*descriptor.FileDescriptorProto) 2597 pb.SourceCodeInfo = nil 2598 2599 b, err := proto.Marshal(pb) 2600 if err != nil { 2601 g.Fail(err.Error()) 2602 } 2603 2604 var buf bytes.Buffer 2605 w, _ := gzip.NewWriterLevel(&buf, gzip.BestCompression) 2606 w.Write(b) 2607 w.Close() 2608 b = buf.Bytes() 2609 2610 v := file.VarName() 2611 g.P() 2612 g.P("func init() {") 2613 g.P(g.Pkg["proto"], ".RegisterFile(", strconv.Quote(*file.Name), ", ", v, ")") 2614 g.P("}") 2615 g.P("var ", v, " = []byte{") 2616 g.P("// ", len(b), " bytes of a gzipped FileDescriptorProto") 2617 for len(b) > 0 { 2618 n := 16 2619 if n > len(b) { 2620 n = len(b) 2621 } 2622 2623 s := "" 2624 for _, c := range b[:n] { 2625 s += fmt.Sprintf("0x%02x,", c) 2626 } 2627 g.P(s) 2628 2629 b = b[n:] 2630 } 2631 g.P("}") 2632} 2633 2634func (g *Generator) generateEnumRegistration(enum *EnumDescriptor) { 2635 // // We always print the full (proto-world) package name here. 2636 pkg := enum.File().GetPackage() 2637 if pkg != "" { 2638 pkg += "." 2639 } 2640 // The full type name 2641 typeName := enum.TypeName() 2642 // The full type name, CamelCased. 2643 ccTypeName := CamelCaseSlice(typeName) 2644 g.addInitf("%s.RegisterEnum(%q, %[3]s_name, %[3]s_value)", g.Pkg["proto"], pkg+ccTypeName, ccTypeName) 2645} 2646 2647// And now lots of helper functions. 2648 2649// Is c an ASCII lower-case letter? 2650func isASCIILower(c byte) bool { 2651 return 'a' <= c && c <= 'z' 2652} 2653 2654// Is c an ASCII digit? 2655func isASCIIDigit(c byte) bool { 2656 return '0' <= c && c <= '9' 2657} 2658 2659// CamelCase returns the CamelCased name. 2660// If there is an interior underscore followed by a lower case letter, 2661// drop the underscore and convert the letter to upper case. 2662// There is a remote possibility of this rewrite causing a name collision, 2663// but it's so remote we're prepared to pretend it's nonexistent - since the 2664// C++ generator lowercases names, it's extremely unlikely to have two fields 2665// with different capitalizations. 2666// In short, _my_field_name_2 becomes XMyFieldName_2. 2667func CamelCase(s string) string { 2668 if s == "" { 2669 return "" 2670 } 2671 t := make([]byte, 0, 32) 2672 i := 0 2673 if s[0] == '_' { 2674 // Need a capital letter; drop the '_'. 2675 t = append(t, 'X') 2676 i++ 2677 } 2678 // Invariant: if the next letter is lower case, it must be converted 2679 // to upper case. 2680 // That is, we process a word at a time, where words are marked by _ or 2681 // upper case letter. Digits are treated as words. 2682 for ; i < len(s); i++ { 2683 c := s[i] 2684 if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) { 2685 continue // Skip the underscore in s. 2686 } 2687 if isASCIIDigit(c) { 2688 t = append(t, c) 2689 continue 2690 } 2691 // Assume we have a letter now - if not, it's a bogus identifier. 2692 // The next word is a sequence of characters that must start upper case. 2693 if isASCIILower(c) { 2694 c ^= ' ' // Make it a capital letter. 2695 } 2696 t = append(t, c) // Guaranteed not lower case. 2697 // Accept lower case sequence that follows. 2698 for i+1 < len(s) && isASCIILower(s[i+1]) { 2699 i++ 2700 t = append(t, s[i]) 2701 } 2702 } 2703 return string(t) 2704} 2705 2706// CamelCaseSlice is like CamelCase, but the argument is a slice of strings to 2707// be joined with "_". 2708func CamelCaseSlice(elem []string) string { return CamelCase(strings.Join(elem, "_")) } 2709 2710// dottedSlice turns a sliced name into a dotted name. 2711func dottedSlice(elem []string) string { return strings.Join(elem, ".") } 2712 2713// Is this field optional? 2714func isOptional(field *descriptor.FieldDescriptorProto) bool { 2715 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_OPTIONAL 2716} 2717 2718// Is this field required? 2719func isRequired(field *descriptor.FieldDescriptorProto) bool { 2720 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REQUIRED 2721} 2722 2723// Is this field repeated? 2724func isRepeated(field *descriptor.FieldDescriptorProto) bool { 2725 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED 2726} 2727 2728// Is this field a scalar numeric type? 2729func isScalar(field *descriptor.FieldDescriptorProto) bool { 2730 if field.Type == nil { 2731 return false 2732 } 2733 switch *field.Type { 2734 case descriptor.FieldDescriptorProto_TYPE_DOUBLE, 2735 descriptor.FieldDescriptorProto_TYPE_FLOAT, 2736 descriptor.FieldDescriptorProto_TYPE_INT64, 2737 descriptor.FieldDescriptorProto_TYPE_UINT64, 2738 descriptor.FieldDescriptorProto_TYPE_INT32, 2739 descriptor.FieldDescriptorProto_TYPE_FIXED64, 2740 descriptor.FieldDescriptorProto_TYPE_FIXED32, 2741 descriptor.FieldDescriptorProto_TYPE_BOOL, 2742 descriptor.FieldDescriptorProto_TYPE_UINT32, 2743 descriptor.FieldDescriptorProto_TYPE_ENUM, 2744 descriptor.FieldDescriptorProto_TYPE_SFIXED32, 2745 descriptor.FieldDescriptorProto_TYPE_SFIXED64, 2746 descriptor.FieldDescriptorProto_TYPE_SINT32, 2747 descriptor.FieldDescriptorProto_TYPE_SINT64: 2748 return true 2749 default: 2750 return false 2751 } 2752} 2753 2754// badToUnderscore is the mapping function used to generate Go names from package names, 2755// which can be dotted in the input .proto file. It replaces non-identifier characters such as 2756// dot or dash with underscore. 2757func badToUnderscore(r rune) rune { 2758 if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' { 2759 return r 2760 } 2761 return '_' 2762} 2763 2764// baseName returns the last path element of the name, with the last dotted suffix removed. 2765func baseName(name string) string { 2766 // First, find the last element 2767 if i := strings.LastIndex(name, "/"); i >= 0 { 2768 name = name[i+1:] 2769 } 2770 // Now drop the suffix 2771 if i := strings.LastIndex(name, "."); i >= 0 { 2772 name = name[0:i] 2773 } 2774 return name 2775} 2776 2777// The SourceCodeInfo message describes the location of elements of a parsed 2778// .proto file by way of a "path", which is a sequence of integers that 2779// describe the route from a FileDescriptorProto to the relevant submessage. 2780// The path alternates between a field number of a repeated field, and an index 2781// into that repeated field. The constants below define the field numbers that 2782// are used. 2783// 2784// See descriptor.proto for more information about this. 2785const ( 2786 // tag numbers in FileDescriptorProto 2787 packagePath = 2 // package 2788 messagePath = 4 // message_type 2789 enumPath = 5 // enum_type 2790 // tag numbers in DescriptorProto 2791 messageFieldPath = 2 // field 2792 messageMessagePath = 3 // nested_type 2793 messageEnumPath = 4 // enum_type 2794 messageOneofPath = 8 // oneof_decl 2795 // tag numbers in EnumDescriptorProto 2796 enumValuePath = 2 // value 2797) 2798 2799var supportTypeAliases bool 2800 2801func init() { 2802 for _, tag := range build.Default.ReleaseTags { 2803 if tag == "go1.9" { 2804 supportTypeAliases = true 2805 return 2806 } 2807 } 2808} 2809