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