gitee.com/sasukebo/go-micro/v4@v4.7.1/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 // wire encoding 1396 // protocol tag number 1397 // opt,req,rep for optional, required, or repeated 1398 // packed whether the encoding is "packed" (optional; repeated primitives only) 1399 // name= the original declared name 1400 // enum= the name of the enum type if it is an enum-typed field. 1401 // proto3 if this field is in a proto3 message 1402 // def= string representation of the default value, if any. 1403 // The default value must be in a representation that can be used at run-time 1404 // to generate the default value. Thus bools become 0 and 1, for instance. 1405 func (g *Generator) goTag(message *Descriptor, field *descriptor.FieldDescriptorProto, wiretype string) string { 1406 optrepreq := "" 1407 switch { 1408 case isOptional(field): 1409 optrepreq = "opt" 1410 case isRequired(field): 1411 optrepreq = "req" 1412 case isRepeated(field): 1413 optrepreq = "rep" 1414 } 1415 var defaultValue string 1416 if dv := field.DefaultValue; dv != nil { // set means an explicit default 1417 defaultValue = *dv 1418 // Some types need tweaking. 1419 switch *field.Type { 1420 case descriptor.FieldDescriptorProto_TYPE_BOOL: 1421 if defaultValue == "true" { 1422 defaultValue = "1" 1423 } else { 1424 defaultValue = "0" 1425 } 1426 case descriptor.FieldDescriptorProto_TYPE_STRING, 1427 descriptor.FieldDescriptorProto_TYPE_BYTES: 1428 // Nothing to do. Quoting is done for the whole tag. 1429 case descriptor.FieldDescriptorProto_TYPE_ENUM: 1430 // For enums we need to provide the integer constant. 1431 obj := g.ObjectNamed(field.GetTypeName()) 1432 if id, ok := obj.(*ImportedDescriptor); ok { 1433 // It is an enum that was publicly imported. 1434 // We need the underlying type. 1435 obj = id.o 1436 } 1437 enum, ok := obj.(*EnumDescriptor) 1438 if !ok { 1439 log.Printf("obj is a %T", obj) 1440 if id, ok := obj.(*ImportedDescriptor); ok { 1441 log.Printf("id.o is a %T", id.o) 1442 } 1443 g.Fail("unknown enum type", CamelCaseSlice(obj.TypeName())) 1444 } 1445 defaultValue = enum.integerValueAsString(defaultValue) 1446 case descriptor.FieldDescriptorProto_TYPE_FLOAT: 1447 if def := defaultValue; def != "inf" && def != "-inf" && def != "nan" { 1448 if f, err := strconv.ParseFloat(defaultValue, 32); err == nil { 1449 defaultValue = fmt.Sprint(float32(f)) 1450 } 1451 } 1452 case descriptor.FieldDescriptorProto_TYPE_DOUBLE: 1453 if def := defaultValue; def != "inf" && def != "-inf" && def != "nan" { 1454 if f, err := strconv.ParseFloat(defaultValue, 64); err == nil { 1455 defaultValue = fmt.Sprint(f) 1456 } 1457 } 1458 } 1459 defaultValue = ",def=" + defaultValue 1460 } 1461 enum := "" 1462 if *field.Type == descriptor.FieldDescriptorProto_TYPE_ENUM { 1463 // We avoid using obj.GoPackageName(), because we want to use the 1464 // original (proto-world) package name. 1465 obj := g.ObjectNamed(field.GetTypeName()) 1466 if id, ok := obj.(*ImportedDescriptor); ok { 1467 obj = id.o 1468 } 1469 enum = ",enum=" 1470 if pkg := obj.File().GetPackage(); pkg != "" { 1471 enum += pkg + "." 1472 } 1473 enum += CamelCaseSlice(obj.TypeName()) 1474 } 1475 packed := "" 1476 if (field.Options != nil && field.Options.GetPacked()) || 1477 // Per https://developers.google.com/protocol-buffers/docs/proto3#simple: 1478 // "In proto3, repeated fields of scalar numeric types use packed encoding by default." 1479 (message.proto3() && (field.Options == nil || field.Options.Packed == nil) && 1480 isRepeated(field) && isScalar(field)) { 1481 packed = ",packed" 1482 } 1483 fieldName := field.GetName() 1484 name := fieldName 1485 if *field.Type == descriptor.FieldDescriptorProto_TYPE_GROUP { 1486 // We must use the type name for groups instead of 1487 // the field name to preserve capitalization. 1488 // type_name in FieldDescriptorProto is fully-qualified, 1489 // but we only want the local part. 1490 name = *field.TypeName 1491 if i := strings.LastIndex(name, "."); i >= 0 { 1492 name = name[i+1:] 1493 } 1494 } 1495 if json := field.GetJsonName(); field.Extendee == nil && json != "" && json != name { 1496 // TODO: escaping might be needed, in which case 1497 // perhaps this should be in its own "json" tag. 1498 name += ",json=" + json 1499 } 1500 name = ",name=" + name 1501 if message.proto3() { 1502 name += ",proto3" 1503 } 1504 oneof := "" 1505 if field.OneofIndex != nil { 1506 oneof = ",oneof" 1507 } 1508 return strconv.Quote(fmt.Sprintf("%s,%d,%s%s%s%s%s%s", 1509 wiretype, 1510 field.GetNumber(), 1511 optrepreq, 1512 packed, 1513 name, 1514 enum, 1515 oneof, 1516 defaultValue)) 1517 } 1518 1519 func needsStar(typ descriptor.FieldDescriptorProto_Type) bool { 1520 switch typ { 1521 case descriptor.FieldDescriptorProto_TYPE_GROUP: 1522 return false 1523 case descriptor.FieldDescriptorProto_TYPE_MESSAGE: 1524 return false 1525 case descriptor.FieldDescriptorProto_TYPE_BYTES: 1526 return false 1527 } 1528 return true 1529 } 1530 1531 // TypeName is the printed name appropriate for an item. If the object is in the current file, 1532 // TypeName drops the package name and underscores the rest. 1533 // Otherwise the object is from another package; and the result is the underscored 1534 // package name followed by the item name. 1535 // The result always has an initial capital. 1536 func (g *Generator) TypeName(obj Object) string { 1537 return g.DefaultPackageName(obj) + CamelCaseSlice(obj.TypeName()) 1538 } 1539 1540 // GoType returns a string representing the type name, and the wire type 1541 func (g *Generator) GoType(message *Descriptor, field *descriptor.FieldDescriptorProto) (typ string, wire string) { 1542 // TODO: Options. 1543 switch *field.Type { 1544 case descriptor.FieldDescriptorProto_TYPE_DOUBLE: 1545 typ, wire = "float64", "fixed64" 1546 case descriptor.FieldDescriptorProto_TYPE_FLOAT: 1547 typ, wire = "float32", "fixed32" 1548 case descriptor.FieldDescriptorProto_TYPE_INT64: 1549 typ, wire = "int64", "varint" 1550 case descriptor.FieldDescriptorProto_TYPE_UINT64: 1551 typ, wire = "uint64", "varint" 1552 case descriptor.FieldDescriptorProto_TYPE_INT32: 1553 typ, wire = "int32", "varint" 1554 case descriptor.FieldDescriptorProto_TYPE_UINT32: 1555 typ, wire = "uint32", "varint" 1556 case descriptor.FieldDescriptorProto_TYPE_FIXED64: 1557 typ, wire = "uint64", "fixed64" 1558 case descriptor.FieldDescriptorProto_TYPE_FIXED32: 1559 typ, wire = "uint32", "fixed32" 1560 case descriptor.FieldDescriptorProto_TYPE_BOOL: 1561 typ, wire = "bool", "varint" 1562 case descriptor.FieldDescriptorProto_TYPE_STRING: 1563 typ, wire = "string", "bytes" 1564 case descriptor.FieldDescriptorProto_TYPE_GROUP: 1565 desc := g.ObjectNamed(field.GetTypeName()) 1566 typ, wire = "*"+g.TypeName(desc), "group" 1567 case descriptor.FieldDescriptorProto_TYPE_MESSAGE: 1568 desc := g.ObjectNamed(field.GetTypeName()) 1569 typ, wire = "*"+g.TypeName(desc), "bytes" 1570 case descriptor.FieldDescriptorProto_TYPE_BYTES: 1571 typ, wire = "[]byte", "bytes" 1572 case descriptor.FieldDescriptorProto_TYPE_ENUM: 1573 desc := g.ObjectNamed(field.GetTypeName()) 1574 typ, wire = g.TypeName(desc), "varint" 1575 case descriptor.FieldDescriptorProto_TYPE_SFIXED32: 1576 typ, wire = "int32", "fixed32" 1577 case descriptor.FieldDescriptorProto_TYPE_SFIXED64: 1578 typ, wire = "int64", "fixed64" 1579 case descriptor.FieldDescriptorProto_TYPE_SINT32: 1580 typ, wire = "int32", "zigzag32" 1581 case descriptor.FieldDescriptorProto_TYPE_SINT64: 1582 typ, wire = "int64", "zigzag64" 1583 default: 1584 g.Fail("unknown type for", field.GetName()) 1585 } 1586 if isRepeated(field) { 1587 typ = "[]" + typ 1588 } else if message != nil && message.proto3() { 1589 return 1590 } else if field.OneofIndex != nil && message != nil { 1591 return 1592 } else if needsStar(*field.Type) { 1593 typ = "*" + typ 1594 } 1595 return 1596 } 1597 1598 func (g *Generator) RecordTypeUse(t string) { 1599 if _, ok := g.typeNameToObject[t]; !ok { 1600 return 1601 } 1602 importPath := g.ObjectNamed(t).GoImportPath() 1603 if importPath == g.outputImportPath { 1604 // Don't record use of objects in our package. 1605 return 1606 } 1607 g.AddImport(importPath) 1608 g.usedPackages[importPath] = true 1609 } 1610 1611 // Method names that may be generated. Fields with these names get an 1612 // underscore appended. Any change to this set is a potential incompatible 1613 // API change because it changes generated field names. 1614 var methodNames = [...]string{ 1615 "Reset", 1616 "String", 1617 "ProtoMessage", 1618 "Marshal", 1619 "Unmarshal", 1620 "ExtensionRangeArray", 1621 "ExtensionMap", 1622 "Descriptor", 1623 } 1624 1625 // Names of messages in the `google.protobuf` package for which 1626 // we will generate XXX_WellKnownType methods. 1627 var wellKnownTypes = map[string]bool{ 1628 "Any": true, 1629 "Duration": true, 1630 "Empty": true, 1631 "Struct": true, 1632 "Timestamp": true, 1633 1634 "Value": true, 1635 "ListValue": true, 1636 "DoubleValue": true, 1637 "FloatValue": true, 1638 "Int64Value": true, 1639 "UInt64Value": true, 1640 "Int32Value": true, 1641 "UInt32Value": true, 1642 "BoolValue": true, 1643 "StringValue": true, 1644 "BytesValue": true, 1645 } 1646 1647 // getterDefault finds the default value for the field to return from a getter, 1648 // regardless of if it's a built in default or explicit from the source. Returns e.g. "nil", `""`, "Default_MessageType_FieldName" 1649 func (g *Generator) getterDefault(field *descriptor.FieldDescriptorProto, goMessageType string) string { 1650 if isRepeated(field) { 1651 return "nil" 1652 } 1653 if def := field.GetDefaultValue(); def != "" { 1654 defaultConstant := g.defaultConstantName(goMessageType, field.GetName()) 1655 if *field.Type != descriptor.FieldDescriptorProto_TYPE_BYTES { 1656 return defaultConstant 1657 } 1658 return "append([]byte(nil), " + defaultConstant + "...)" 1659 } 1660 switch *field.Type { 1661 case descriptor.FieldDescriptorProto_TYPE_BOOL: 1662 return "false" 1663 case descriptor.FieldDescriptorProto_TYPE_STRING: 1664 return `""` 1665 case descriptor.FieldDescriptorProto_TYPE_GROUP, descriptor.FieldDescriptorProto_TYPE_MESSAGE, descriptor.FieldDescriptorProto_TYPE_BYTES: 1666 return "nil" 1667 case descriptor.FieldDescriptorProto_TYPE_ENUM: 1668 obj := g.ObjectNamed(field.GetTypeName()) 1669 var enum *EnumDescriptor 1670 if id, ok := obj.(*ImportedDescriptor); ok { 1671 // The enum type has been publicly imported. 1672 enum, _ = id.o.(*EnumDescriptor) 1673 } else { 1674 enum, _ = obj.(*EnumDescriptor) 1675 } 1676 if enum == nil { 1677 log.Printf("don't know how to generate getter for %s", field.GetName()) 1678 return "nil" 1679 } 1680 if len(enum.Value) == 0 { 1681 return "0 // empty enum" 1682 } 1683 first := enum.Value[0].GetName() 1684 return g.DefaultPackageName(obj) + enum.prefix() + first 1685 default: 1686 return "0" 1687 } 1688 } 1689 1690 // defaultConstantName builds the name of the default constant from the message 1691 // type name and the untouched field name, e.g. "Default_MessageType_FieldName" 1692 func (g *Generator) defaultConstantName(goMessageType, protoFieldName string) string { 1693 return "Default_" + goMessageType + "_" + CamelCase(protoFieldName) 1694 } 1695 1696 // The different types of fields in a message and how to actually print them 1697 // Most of the logic for generateMessage is in the methods of these types. 1698 // 1699 // Note that the content of the field is irrelevant, a simpleField can contain 1700 // anything from a scalar to a group (which is just a message). 1701 // 1702 // Extension fields (and message sets) are however handled separately. 1703 // 1704 // simpleField - a field that is neiter weak nor oneof, possibly repeated 1705 // oneofField - field containing list of subfields: 1706 // - oneofSubField - a field within the oneof 1707 1708 // msgCtx contains the context for the generator functions. 1709 type msgCtx struct { 1710 goName string // Go struct name of the message, e.g. MessageName 1711 message *Descriptor // The descriptor for the message 1712 } 1713 1714 // fieldCommon contains data common to all types of fields. 1715 type fieldCommon struct { 1716 goName string // Go name of field, e.g. "FieldName" or "Descriptor_" 1717 protoName string // Name of field in proto language, e.g. "field_name" or "descriptor" 1718 getterName string // Name of the getter, e.g. "GetFieldName" or "GetDescriptor_" 1719 goType string // The Go type as a string, e.g. "*int32" or "*OtherMessage" 1720 tags string // The tag string/annotation for the type, e.g. `protobuf:"varint,8,opt,name=region_id,json=regionId"` 1721 fullPath string // The full path of the field as used by Annotate etc, e.g. "4,0,2,0" 1722 } 1723 1724 // getProtoName gets the proto name of a field, e.g. "field_name" or "descriptor". 1725 func (f *fieldCommon) getProtoName() string { 1726 return f.protoName 1727 } 1728 1729 // getGoType returns the go type of the field as a string, e.g. "*int32". 1730 func (f *fieldCommon) getGoType() string { 1731 return f.goType 1732 } 1733 1734 // simpleField is not weak, not a oneof, not an extension. Can be required, optional or repeated. 1735 type simpleField struct { 1736 fieldCommon 1737 protoTypeName string // Proto type name, empty if primitive, e.g. ".google.protobuf.Duration" 1738 protoType descriptor.FieldDescriptorProto_Type // Actual type enum value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64 1739 deprecated string // Deprecation comment, if any, e.g. "// Deprecated: Do not use." 1740 getterDef string // Default for getters, e.g. "nil", `""` or "Default_MessageType_FieldName" 1741 protoDef string // Default value as defined in the proto file, e.g "yoshi" or "5" 1742 comment string // The full comment for the field, e.g. "// Useful information" 1743 } 1744 1745 // decl prints the declaration of the field in the struct (if any). 1746 func (f *simpleField) decl(g *Generator, mc *msgCtx) { 1747 g.P(f.comment, Annotate(mc.message.file, f.fullPath, f.goName), "\t", f.goType, "\t`", f.tags, "`", f.deprecated) 1748 } 1749 1750 // getter prints the getter for the field. 1751 func (f *simpleField) getter(g *Generator, mc *msgCtx) { 1752 star := "" 1753 tname := f.goType 1754 if needsStar(f.protoType) && tname[0] == '*' { 1755 tname = tname[1:] 1756 star = "*" 1757 } 1758 if f.deprecated != "" { 1759 g.P(f.deprecated) 1760 } 1761 g.P("func (m *", mc.goName, ") ", Annotate(mc.message.file, f.fullPath, f.getterName), "() "+tname+" {") 1762 if f.getterDef == "nil" { // Simpler getter 1763 g.P("if m != nil {") 1764 g.P("return m." + f.goName) 1765 g.P("}") 1766 g.P("return nil") 1767 g.P("}") 1768 g.P() 1769 return 1770 } 1771 if mc.message.proto3() { 1772 g.P("if m != nil {") 1773 } else { 1774 g.P("if m != nil && m." + f.goName + " != nil {") 1775 } 1776 g.P("return " + star + "m." + f.goName) 1777 g.P("}") 1778 g.P("return ", f.getterDef) 1779 g.P("}") 1780 g.P() 1781 } 1782 1783 // setter prints the setter method of the field. 1784 func (f *simpleField) setter(g *Generator, mc *msgCtx) { 1785 // No setter for regular fields yet 1786 } 1787 1788 // getProtoDef returns the default value explicitly stated in the proto file, e.g "yoshi" or "5". 1789 func (f *simpleField) getProtoDef() string { 1790 return f.protoDef 1791 } 1792 1793 // getProtoTypeName returns the protobuf type name for the field as returned by field.GetTypeName(), e.g. ".google.protobuf.Duration". 1794 func (f *simpleField) getProtoTypeName() string { 1795 return f.protoTypeName 1796 } 1797 1798 // getProtoType returns the *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64. 1799 func (f *simpleField) getProtoType() descriptor.FieldDescriptorProto_Type { 1800 return f.protoType 1801 } 1802 1803 // oneofSubFields are kept slize held by each oneofField. They do not appear in the top level slize of fields for the message. 1804 type oneofSubField struct { 1805 fieldCommon 1806 protoTypeName string // Proto type name, empty if primitive, e.g. ".google.protobuf.Duration" 1807 protoType descriptor.FieldDescriptorProto_Type // Actual type enum value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64 1808 oneofTypeName string // Type name of the enclosing struct, e.g. "MessageName_FieldName" 1809 fieldNumber int // Actual field number, as defined in proto, e.g. 12 1810 getterDef string // Default for getters, e.g. "nil", `""` or "Default_MessageType_FieldName" 1811 protoDef string // Default value as defined in the proto file, e.g "yoshi" or "5" 1812 deprecated string // Deprecation comment, if any. 1813 } 1814 1815 // typedNil prints a nil casted to the pointer to this field. 1816 // - for XXX_OneofWrappers 1817 func (f *oneofSubField) typedNil(g *Generator) { 1818 g.P("(*", f.oneofTypeName, ")(nil),") 1819 } 1820 1821 // getProtoDef returns the default value explicitly stated in the proto file, e.g "yoshi" or "5". 1822 func (f *oneofSubField) getProtoDef() string { 1823 return f.protoDef 1824 } 1825 1826 // getProtoTypeName returns the protobuf type name for the field as returned by field.GetTypeName(), e.g. ".google.protobuf.Duration". 1827 func (f *oneofSubField) getProtoTypeName() string { 1828 return f.protoTypeName 1829 } 1830 1831 // getProtoType returns the *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64. 1832 func (f *oneofSubField) getProtoType() descriptor.FieldDescriptorProto_Type { 1833 return f.protoType 1834 } 1835 1836 // oneofField represents the oneof on top level. 1837 // The alternative fields within the oneof are represented by oneofSubField. 1838 type oneofField struct { 1839 fieldCommon 1840 subFields []*oneofSubField // All the possible oneof fields 1841 comment string // The full comment for the field, e.g. "// Types that are valid to be assigned to MyOneof:\n\\" 1842 } 1843 1844 // decl prints the declaration of the field in the struct (if any). 1845 func (f *oneofField) decl(g *Generator, mc *msgCtx) { 1846 comment := f.comment 1847 for _, sf := range f.subFields { 1848 comment += "//\t*" + sf.oneofTypeName + "\n" 1849 } 1850 g.P(comment, Annotate(mc.message.file, f.fullPath, f.goName), " ", f.goType, " `", f.tags, "`") 1851 } 1852 1853 // getter for a oneof field will print additional discriminators and interfaces for the oneof, 1854 // also it prints all the getters for the sub fields. 1855 func (f *oneofField) getter(g *Generator, mc *msgCtx) { 1856 // The discriminator type 1857 g.P("type ", f.goType, " interface {") 1858 g.P(f.goType, "()") 1859 g.P("}") 1860 g.P() 1861 // The subField types, fulfilling the discriminator type contract 1862 for _, sf := range f.subFields { 1863 g.P("type ", Annotate(mc.message.file, sf.fullPath, sf.oneofTypeName), " struct {") 1864 g.P(Annotate(mc.message.file, sf.fullPath, sf.goName), " ", sf.goType, " `", sf.tags, "`") 1865 g.P("}") 1866 g.P() 1867 } 1868 for _, sf := range f.subFields { 1869 g.P("func (*", sf.oneofTypeName, ") ", f.goType, "() {}") 1870 g.P() 1871 } 1872 // Getter for the oneof field 1873 g.P("func (m *", mc.goName, ") ", Annotate(mc.message.file, f.fullPath, f.getterName), "() ", f.goType, " {") 1874 g.P("if m != nil { return m.", f.goName, " }") 1875 g.P("return nil") 1876 g.P("}") 1877 g.P() 1878 // Getters for each oneof 1879 for _, sf := range f.subFields { 1880 if sf.deprecated != "" { 1881 g.P(sf.deprecated) 1882 } 1883 g.P("func (m *", mc.goName, ") ", Annotate(mc.message.file, sf.fullPath, sf.getterName), "() "+sf.goType+" {") 1884 g.P("if x, ok := m.", f.getterName, "().(*", sf.oneofTypeName, "); ok {") 1885 g.P("return x.", sf.goName) 1886 g.P("}") 1887 g.P("return ", sf.getterDef) 1888 g.P("}") 1889 g.P() 1890 } 1891 } 1892 1893 // setter prints the setter method of the field. 1894 func (f *oneofField) setter(g *Generator, mc *msgCtx) { 1895 // No setters for oneof yet 1896 } 1897 1898 // topLevelField interface implemented by all types of fields on the top level (not oneofSubField). 1899 type topLevelField interface { 1900 decl(g *Generator, mc *msgCtx) // print declaration within the struct 1901 getter(g *Generator, mc *msgCtx) // print getter 1902 setter(g *Generator, mc *msgCtx) // print setter if applicable 1903 } 1904 1905 // defField interface implemented by all types of fields that can have defaults (not oneofField, but instead oneofSubField). 1906 type defField interface { 1907 getProtoDef() string // default value explicitly stated in the proto file, e.g "yoshi" or "5" 1908 getProtoName() string // proto name of a field, e.g. "field_name" or "descriptor" 1909 getGoType() string // go type of the field as a string, e.g. "*int32" 1910 getProtoTypeName() string // protobuf type name for the field, e.g. ".google.protobuf.Duration" 1911 getProtoType() descriptor.FieldDescriptorProto_Type // *field.Type value, e.g. descriptor.FieldDescriptorProto_TYPE_FIXED64 1912 } 1913 1914 // generateDefaultConstants adds constants for default values if needed, which is only if the default value is. 1915 // explicit in the proto. 1916 func (g *Generator) generateDefaultConstants(mc *msgCtx, topLevelFields []topLevelField) { 1917 // Collect fields that can have defaults 1918 dFields := []defField{} 1919 for _, pf := range topLevelFields { 1920 if f, ok := pf.(*oneofField); ok { 1921 for _, osf := range f.subFields { 1922 dFields = append(dFields, osf) 1923 } 1924 continue 1925 } 1926 dFields = append(dFields, pf.(defField)) 1927 } 1928 for _, df := range dFields { 1929 def := df.getProtoDef() 1930 if def == "" { 1931 continue 1932 } 1933 fieldname := g.defaultConstantName(mc.goName, df.getProtoName()) 1934 typename := df.getGoType() 1935 if typename[0] == '*' { 1936 typename = typename[1:] 1937 } 1938 kind := "const " 1939 switch { 1940 case typename == "bool": 1941 case typename == "string": 1942 def = strconv.Quote(def) 1943 case typename == "[]byte": 1944 def = "[]byte(" + strconv.Quote(unescape(def)) + ")" 1945 kind = "var " 1946 case def == "inf", def == "-inf", def == "nan": 1947 // These names are known to, and defined by, the protocol language. 1948 switch def { 1949 case "inf": 1950 def = "math.Inf(1)" 1951 case "-inf": 1952 def = "math.Inf(-1)" 1953 case "nan": 1954 def = "math.NaN()" 1955 } 1956 if df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_FLOAT { 1957 def = "float32(" + def + ")" 1958 } 1959 kind = "var " 1960 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_FLOAT: 1961 if f, err := strconv.ParseFloat(def, 32); err == nil { 1962 def = fmt.Sprint(float32(f)) 1963 } 1964 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_DOUBLE: 1965 if f, err := strconv.ParseFloat(def, 64); err == nil { 1966 def = fmt.Sprint(f) 1967 } 1968 case df.getProtoType() == descriptor.FieldDescriptorProto_TYPE_ENUM: 1969 // Must be an enum. Need to construct the prefixed name. 1970 obj := g.ObjectNamed(df.getProtoTypeName()) 1971 var enum *EnumDescriptor 1972 if id, ok := obj.(*ImportedDescriptor); ok { 1973 // The enum type has been publicly imported. 1974 enum, _ = id.o.(*EnumDescriptor) 1975 } else { 1976 enum, _ = obj.(*EnumDescriptor) 1977 } 1978 if enum == nil { 1979 log.Printf("don't know how to generate constant for %s", fieldname) 1980 continue 1981 } 1982 def = g.DefaultPackageName(obj) + enum.prefix() + def 1983 } 1984 g.P(kind, fieldname, " ", typename, " = ", def) 1985 g.file.addExport(mc.message, constOrVarSymbol{fieldname, kind, ""}) 1986 } 1987 g.P() 1988 } 1989 1990 // generateInternalStructFields just adds the XXX_<something> fields to the message struct. 1991 func (g *Generator) generateInternalStructFields(mc *msgCtx, topLevelFields []topLevelField) { 1992 g.P("XXX_NoUnkeyedLiteral\tstruct{} `json:\"-\"`") // prevent unkeyed struct literals 1993 if len(mc.message.ExtensionRange) > 0 { 1994 messageset := "" 1995 if opts := mc.message.Options; opts != nil && opts.GetMessageSetWireFormat() { 1996 messageset = "protobuf_messageset:\"1\" " 1997 } 1998 g.P(g.Pkg["proto"], ".XXX_InternalExtensions `", messageset, "json:\"-\"`") 1999 } 2000 g.P("XXX_unrecognized\t[]byte `json:\"-\"`") 2001 g.P("XXX_sizecache\tint32 `json:\"-\"`") 2002 2003 } 2004 2005 // generateOneofFuncs adds all the utility functions for oneof, including marshalling, unmarshalling and sizer. 2006 func (g *Generator) generateOneofFuncs(mc *msgCtx, topLevelFields []topLevelField) { 2007 ofields := []*oneofField{} 2008 for _, f := range topLevelFields { 2009 if o, ok := f.(*oneofField); ok { 2010 ofields = append(ofields, o) 2011 } 2012 } 2013 if len(ofields) == 0 { 2014 return 2015 } 2016 2017 // OneofFuncs 2018 g.P("// XXX_OneofWrappers is for the internal use of the proto package.") 2019 g.P("func (*", mc.goName, ") XXX_OneofWrappers() []interface{} {") 2020 g.P("return []interface{}{") 2021 for _, of := range ofields { 2022 for _, sf := range of.subFields { 2023 sf.typedNil(g) 2024 } 2025 } 2026 g.P("}") 2027 g.P("}") 2028 g.P() 2029 } 2030 2031 // generateMessageStruct adds the actual struct with it's members (but not methods) to the output. 2032 func (g *Generator) generateMessageStruct(mc *msgCtx, topLevelFields []topLevelField) { 2033 comments := g.PrintComments(mc.message.path) 2034 2035 // Guarantee deprecation comments appear after user-provided comments. 2036 if mc.message.GetOptions().GetDeprecated() { 2037 if comments { 2038 // Convention: Separate deprecation comments from original 2039 // comments with an empty line. 2040 g.P("//") 2041 } 2042 g.P(deprecationComment) 2043 } 2044 2045 g.P("type ", Annotate(mc.message.file, mc.message.path, mc.goName), " struct {") 2046 for _, pf := range topLevelFields { 2047 pf.decl(g, mc) 2048 } 2049 g.generateInternalStructFields(mc, topLevelFields) 2050 g.P("}") 2051 } 2052 2053 // generateGetters adds getters for all fields, including oneofs and weak fields when applicable. 2054 func (g *Generator) generateGetters(mc *msgCtx, topLevelFields []topLevelField) { 2055 for _, pf := range topLevelFields { 2056 pf.getter(g, mc) 2057 } 2058 } 2059 2060 // generateSetters add setters for all fields, including oneofs and weak fields when applicable. 2061 func (g *Generator) generateSetters(mc *msgCtx, topLevelFields []topLevelField) { 2062 for _, pf := range topLevelFields { 2063 pf.setter(g, mc) 2064 } 2065 } 2066 2067 // generateCommonMethods adds methods to the message that are not on a per field basis. 2068 func (g *Generator) generateCommonMethods(mc *msgCtx) { 2069 // Reset, String and ProtoMessage methods. 2070 g.P("func (m *", mc.goName, ") Reset() { *m = ", mc.goName, "{} }") 2071 g.P("func (m *", mc.goName, ") String() string { return ", g.Pkg["proto"], ".CompactTextString(m) }") 2072 g.P("func (*", mc.goName, ") ProtoMessage() {}") 2073 var indexes []string 2074 for m := mc.message; m != nil; m = m.parent { 2075 indexes = append([]string{strconv.Itoa(m.index)}, indexes...) 2076 } 2077 g.P("func (*", mc.goName, ") Descriptor() ([]byte, []int) {") 2078 g.P("return ", g.file.VarName(), ", []int{", strings.Join(indexes, ", "), "}") 2079 g.P("}") 2080 g.P() 2081 // TODO: Revisit the decision to use a XXX_WellKnownType method 2082 // if we change proto.MessageName to work with multiple equivalents. 2083 if mc.message.file.GetPackage() == "google.protobuf" && wellKnownTypes[mc.message.GetName()] { 2084 g.P("func (*", mc.goName, `) XXX_WellKnownType() string { return "`, mc.message.GetName(), `" }`) 2085 g.P() 2086 } 2087 2088 // Extension support methods 2089 if len(mc.message.ExtensionRange) > 0 { 2090 g.P() 2091 g.P("var extRange_", mc.goName, " = []", g.Pkg["proto"], ".ExtensionRange{") 2092 for _, r := range mc.message.ExtensionRange { 2093 end := fmt.Sprint(*r.End - 1) // make range inclusive on both ends 2094 g.P("{Start: ", r.Start, ", End: ", end, "},") 2095 } 2096 g.P("}") 2097 g.P("func (*", mc.goName, ") ExtensionRangeArray() []", g.Pkg["proto"], ".ExtensionRange {") 2098 g.P("return extRange_", mc.goName) 2099 g.P("}") 2100 g.P() 2101 } 2102 2103 // TODO: It does not scale to keep adding another method for every 2104 // operation on protos that we want to switch over to using the 2105 // table-driven approach. Instead, we should only add a single method 2106 // that allows getting access to the *InternalMessageInfo struct and then 2107 // calling Unmarshal, Marshal, Merge, Size, and Discard directly on that. 2108 2109 // Wrapper for table-driven marshaling and unmarshaling. 2110 g.P("func (m *", mc.goName, ") XXX_Unmarshal(b []byte) error {") 2111 g.P("return xxx_messageInfo_", mc.goName, ".Unmarshal(m, b)") 2112 g.P("}") 2113 2114 g.P("func (m *", mc.goName, ") XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {") 2115 g.P("return xxx_messageInfo_", mc.goName, ".Marshal(b, m, deterministic)") 2116 g.P("}") 2117 2118 g.P("func (m *", mc.goName, ") XXX_Merge(src ", g.Pkg["proto"], ".Message) {") 2119 g.P("xxx_messageInfo_", mc.goName, ".Merge(m, src)") 2120 g.P("}") 2121 2122 g.P("func (m *", mc.goName, ") XXX_Size() int {") // avoid name clash with "Size" field in some message 2123 g.P("return xxx_messageInfo_", mc.goName, ".Size(m)") 2124 g.P("}") 2125 2126 g.P("func (m *", mc.goName, ") XXX_DiscardUnknown() {") 2127 g.P("xxx_messageInfo_", mc.goName, ".DiscardUnknown(m)") 2128 g.P("}") 2129 2130 g.P("var xxx_messageInfo_", mc.goName, " ", g.Pkg["proto"], ".InternalMessageInfo") 2131 g.P() 2132 } 2133 2134 // Generate the type, methods and default constant definitions for this Descriptor. 2135 func (g *Generator) generateMessage(message *Descriptor) { 2136 topLevelFields := []topLevelField{} 2137 oFields := make(map[int32]*oneofField) 2138 // The full type name 2139 typeName := message.TypeName() 2140 // The full type name, CamelCased. 2141 goTypeName := CamelCaseSlice(typeName) 2142 2143 usedNames := make(map[string]bool) 2144 for _, n := range methodNames { 2145 usedNames[n] = true 2146 } 2147 2148 // allocNames finds a conflict-free variation of the given strings, 2149 // consistently mutating their suffixes. 2150 // It returns the same number of strings. 2151 allocNames := func(ns ...string) []string { 2152 Loop: 2153 for { 2154 for _, n := range ns { 2155 if usedNames[n] { 2156 for i := range ns { 2157 ns[i] += "_" 2158 } 2159 continue Loop 2160 } 2161 } 2162 for _, n := range ns { 2163 usedNames[n] = true 2164 } 2165 return ns 2166 } 2167 } 2168 2169 mapFieldTypes := make(map[*descriptor.FieldDescriptorProto]string) // keep track of the map fields to be added later 2170 2171 // Build a structure more suitable for generating the text in one pass 2172 for i, field := range message.Field { 2173 // Allocate the getter and the field at the same time so name 2174 // collisions create field/method consistent names. 2175 // TODO: This allocation occurs based on the order of the fields 2176 // in the proto file, meaning that a change in the field 2177 // ordering can change generated Method/Field names. 2178 base := CamelCase(*field.Name) 2179 ns := allocNames(base, "Get"+base) 2180 fieldName, fieldGetterName := ns[0], ns[1] 2181 typename, wiretype := g.GoType(message, field) 2182 jsonName := *field.Name 2183 tag := fmt.Sprintf("protobuf:%s json:%q", g.goTag(message, field, wiretype), jsonName+",omitempty") 2184 2185 oneof := field.OneofIndex != nil 2186 if oneof && oFields[*field.OneofIndex] == nil { 2187 odp := message.OneofDecl[int(*field.OneofIndex)] 2188 base := CamelCase(odp.GetName()) 2189 fname := allocNames(base)[0] 2190 2191 // This is the first field of a oneof we haven't seen before. 2192 // Generate the union field. 2193 oneofFullPath := fmt.Sprintf("%s,%d,%d", message.path, messageOneofPath, *field.OneofIndex) 2194 c, ok := g.makeComments(oneofFullPath) 2195 if ok { 2196 c += "\n//\n" 2197 } 2198 c += "// Types that are valid to be assigned to " + fname + ":\n" 2199 // Generate the rest of this comment later, 2200 // when we've computed any disambiguation. 2201 2202 dname := "is" + goTypeName + "_" + fname 2203 tag := `protobuf_oneof:"` + odp.GetName() + `"` 2204 of := oneofField{ 2205 fieldCommon: fieldCommon{ 2206 goName: fname, 2207 getterName: "Get" + fname, 2208 goType: dname, 2209 tags: tag, 2210 protoName: odp.GetName(), 2211 fullPath: oneofFullPath, 2212 }, 2213 comment: c, 2214 } 2215 topLevelFields = append(topLevelFields, &of) 2216 oFields[*field.OneofIndex] = &of 2217 } 2218 2219 if *field.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE { 2220 desc := g.ObjectNamed(field.GetTypeName()) 2221 if d, ok := desc.(*Descriptor); ok && d.GetOptions().GetMapEntry() { 2222 // Figure out the Go types and tags for the key and value types. 2223 keyField, valField := d.Field[0], d.Field[1] 2224 keyType, keyWire := g.GoType(d, keyField) 2225 valType, valWire := g.GoType(d, valField) 2226 keyTag, valTag := g.goTag(d, keyField, keyWire), g.goTag(d, valField, valWire) 2227 2228 // We don't use stars, except for message-typed values. 2229 // Message and enum types are the only two possibly foreign types used in maps, 2230 // so record their use. They are not permitted as map keys. 2231 keyType = strings.TrimPrefix(keyType, "*") 2232 switch *valField.Type { 2233 case descriptor.FieldDescriptorProto_TYPE_ENUM: 2234 valType = strings.TrimPrefix(valType, "*") 2235 g.RecordTypeUse(valField.GetTypeName()) 2236 case descriptor.FieldDescriptorProto_TYPE_MESSAGE: 2237 g.RecordTypeUse(valField.GetTypeName()) 2238 default: 2239 valType = strings.TrimPrefix(valType, "*") 2240 } 2241 2242 typename = fmt.Sprintf("map[%s]%s", keyType, valType) 2243 mapFieldTypes[field] = typename // record for the getter generation 2244 2245 tag += fmt.Sprintf(" protobuf_key:%s protobuf_val:%s", keyTag, valTag) 2246 } 2247 } 2248 2249 fieldDeprecated := "" 2250 if field.GetOptions().GetDeprecated() { 2251 fieldDeprecated = deprecationComment 2252 } 2253 2254 dvalue := g.getterDefault(field, goTypeName) 2255 if oneof { 2256 tname := goTypeName + "_" + fieldName 2257 // It is possible for this to collide with a message or enum 2258 // nested in this message. Check for collisions. 2259 for { 2260 ok := true 2261 for _, desc := range message.nested { 2262 if CamelCaseSlice(desc.TypeName()) == tname { 2263 ok = false 2264 break 2265 } 2266 } 2267 for _, enum := range message.enums { 2268 if CamelCaseSlice(enum.TypeName()) == tname { 2269 ok = false 2270 break 2271 } 2272 } 2273 if !ok { 2274 tname += "_" 2275 continue 2276 } 2277 break 2278 } 2279 2280 oneofField := oFields[*field.OneofIndex] 2281 tag := "protobuf:" + g.goTag(message, field, wiretype) 2282 sf := oneofSubField{ 2283 fieldCommon: fieldCommon{ 2284 goName: fieldName, 2285 getterName: fieldGetterName, 2286 goType: typename, 2287 tags: tag, 2288 protoName: field.GetName(), 2289 fullPath: fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i), 2290 }, 2291 protoTypeName: field.GetTypeName(), 2292 fieldNumber: int(*field.Number), 2293 protoType: *field.Type, 2294 getterDef: dvalue, 2295 protoDef: field.GetDefaultValue(), 2296 oneofTypeName: tname, 2297 deprecated: fieldDeprecated, 2298 } 2299 oneofField.subFields = append(oneofField.subFields, &sf) 2300 g.RecordTypeUse(field.GetTypeName()) 2301 continue 2302 } 2303 2304 fieldFullPath := fmt.Sprintf("%s,%d,%d", message.path, messageFieldPath, i) 2305 c, ok := g.makeComments(fieldFullPath) 2306 if ok { 2307 c += "\n" 2308 } 2309 rf := simpleField{ 2310 fieldCommon: fieldCommon{ 2311 goName: fieldName, 2312 getterName: fieldGetterName, 2313 goType: typename, 2314 tags: tag, 2315 protoName: field.GetName(), 2316 fullPath: fieldFullPath, 2317 }, 2318 protoTypeName: field.GetTypeName(), 2319 protoType: *field.Type, 2320 deprecated: fieldDeprecated, 2321 getterDef: dvalue, 2322 protoDef: field.GetDefaultValue(), 2323 comment: c, 2324 } 2325 var pf topLevelField = &rf 2326 2327 topLevelFields = append(topLevelFields, pf) 2328 g.RecordTypeUse(field.GetTypeName()) 2329 } 2330 2331 mc := &msgCtx{ 2332 goName: goTypeName, 2333 message: message, 2334 } 2335 2336 g.generateMessageStruct(mc, topLevelFields) 2337 g.P() 2338 g.generateCommonMethods(mc) 2339 g.P() 2340 g.generateDefaultConstants(mc, topLevelFields) 2341 g.P() 2342 g.generateGetters(mc, topLevelFields) 2343 g.P() 2344 g.generateSetters(mc, topLevelFields) 2345 g.P() 2346 g.generateOneofFuncs(mc, topLevelFields) 2347 g.P() 2348 2349 var oneofTypes []string 2350 for _, f := range topLevelFields { 2351 if of, ok := f.(*oneofField); ok { 2352 for _, osf := range of.subFields { 2353 oneofTypes = append(oneofTypes, osf.oneofTypeName) 2354 } 2355 } 2356 } 2357 2358 opts := message.Options 2359 ms := &messageSymbol{ 2360 sym: goTypeName, 2361 hasExtensions: len(message.ExtensionRange) > 0, 2362 isMessageSet: opts != nil && opts.GetMessageSetWireFormat(), 2363 oneofTypes: oneofTypes, 2364 } 2365 g.file.addExport(message, ms) 2366 2367 for _, ext := range message.ext { 2368 g.generateExtension(ext) 2369 } 2370 2371 fullName := strings.Join(message.TypeName(), ".") 2372 if g.file.Package != nil { 2373 fullName = *g.file.Package + "." + fullName 2374 } 2375 2376 g.addInitf("%s.RegisterType((*%s)(nil), %q)", g.Pkg["proto"], goTypeName, fullName) 2377 // Register types for native map types. 2378 for _, k := range mapFieldKeys(mapFieldTypes) { 2379 fullName := strings.TrimPrefix(*k.TypeName, ".") 2380 g.addInitf("%s.RegisterMapType((%s)(nil), %q)", g.Pkg["proto"], mapFieldTypes[k], fullName) 2381 } 2382 2383 } 2384 2385 type byTypeName []*descriptor.FieldDescriptorProto 2386 2387 func (a byTypeName) Len() int { return len(a) } 2388 func (a byTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 2389 func (a byTypeName) Less(i, j int) bool { return *a[i].TypeName < *a[j].TypeName } 2390 2391 // mapFieldKeys returns the keys of m in a consistent order. 2392 func mapFieldKeys(m map[*descriptor.FieldDescriptorProto]string) []*descriptor.FieldDescriptorProto { 2393 keys := make([]*descriptor.FieldDescriptorProto, 0, len(m)) 2394 for k := range m { 2395 keys = append(keys, k) 2396 } 2397 sort.Sort(byTypeName(keys)) 2398 return keys 2399 } 2400 2401 var escapeChars = [256]byte{ 2402 'a': '\a', 'b': '\b', 'f': '\f', 'n': '\n', 'r': '\r', 't': '\t', 'v': '\v', '\\': '\\', '"': '"', '\'': '\'', '?': '?', 2403 } 2404 2405 // unescape reverses the "C" escaping that protoc does for default values of bytes fields. 2406 // It is best effort in that it effectively ignores malformed input. Seemingly invalid escape 2407 // sequences are conveyed, unmodified, into the decoded result. 2408 func unescape(s string) string { 2409 // NB: Sadly, we can't use strconv.Unquote because protoc will escape both 2410 // single and double quotes, but strconv.Unquote only allows one or the 2411 // other (based on actual surrounding quotes of its input argument). 2412 2413 var out []byte 2414 for len(s) > 0 { 2415 // regular character, or too short to be valid escape 2416 if s[0] != '\\' || len(s) < 2 { 2417 out = append(out, s[0]) 2418 s = s[1:] 2419 } else if c := escapeChars[s[1]]; c != 0 { 2420 // escape sequence 2421 out = append(out, c) 2422 s = s[2:] 2423 } else if s[1] == 'x' || s[1] == 'X' { 2424 // hex escape, e.g. "\x80 2425 if len(s) < 4 { 2426 // too short to be valid 2427 out = append(out, s[:2]...) 2428 s = s[2:] 2429 continue 2430 } 2431 v, err := strconv.ParseUint(s[2:4], 16, 8) 2432 if err != nil { 2433 out = append(out, s[:4]...) 2434 } else { 2435 out = append(out, byte(v)) 2436 } 2437 s = s[4:] 2438 } else if '0' <= s[1] && s[1] <= '7' { 2439 // octal escape, can vary from 1 to 3 octal digits; e.g., "\0" "\40" or "\164" 2440 // so consume up to 2 more bytes or up to end-of-string 2441 n := len(s[1:]) - len(strings.TrimLeft(s[1:], "01234567")) 2442 if n > 3 { 2443 n = 3 2444 } 2445 v, err := strconv.ParseUint(s[1:1+n], 8, 8) 2446 if err != nil { 2447 out = append(out, s[:1+n]...) 2448 } else { 2449 out = append(out, byte(v)) 2450 } 2451 s = s[1+n:] 2452 } else { 2453 // bad escape, just propagate the slash as-is 2454 out = append(out, s[0]) 2455 s = s[1:] 2456 } 2457 } 2458 2459 return string(out) 2460 } 2461 2462 func (g *Generator) generateExtension(ext *ExtensionDescriptor) { 2463 ccTypeName := ext.DescName() 2464 2465 extObj := g.ObjectNamed(*ext.Extendee) 2466 var extDesc *Descriptor 2467 if id, ok := extObj.(*ImportedDescriptor); ok { 2468 // This is extending a publicly imported message. 2469 // We need the underlying type for goTag. 2470 extDesc = id.o.(*Descriptor) 2471 } else { 2472 extDesc = extObj.(*Descriptor) 2473 } 2474 extendedType := "*" + g.TypeName(extObj) // always use the original 2475 field := ext.FieldDescriptorProto 2476 fieldType, wireType := g.GoType(ext.parent, field) 2477 tag := g.goTag(extDesc, field, wireType) 2478 g.RecordTypeUse(*ext.Extendee) 2479 if n := ext.FieldDescriptorProto.TypeName; n != nil { 2480 // foreign extension type 2481 g.RecordTypeUse(*n) 2482 } 2483 2484 typeName := ext.TypeName() 2485 2486 // Special case for proto2 message sets: If this extension is extending 2487 // proto2.bridge.MessageSet, and its final name component is "message_set_extension", 2488 // then drop that last component. 2489 // 2490 // TODO: This should be implemented in the text formatter rather than the generator. 2491 // In addition, the situation for when to apply this special case is implemented 2492 // differently in other languages: 2493 // https://github.com/google/protobuf/blob/aff10976/src/google/protobuf/text_format.cc#L1560 2494 if extDesc.GetOptions().GetMessageSetWireFormat() && typeName[len(typeName)-1] == "message_set_extension" { 2495 typeName = typeName[:len(typeName)-1] 2496 } 2497 2498 // For text formatting, the package must be exactly what the .proto file declares, 2499 // ignoring overrides such as the go_package option, and with no dot/underscore mapping. 2500 extName := strings.Join(typeName, ".") 2501 if g.file.Package != nil { 2502 extName = *g.file.Package + "." + extName 2503 } 2504 2505 g.P("var ", ccTypeName, " = &", g.Pkg["proto"], ".ExtensionDesc{") 2506 g.P("ExtendedType: (", extendedType, ")(nil),") 2507 g.P("ExtensionType: (", fieldType, ")(nil),") 2508 g.P("Field: ", field.Number, ",") 2509 g.P(`Name: "`, extName, `",`) 2510 g.P("Tag: ", tag, ",") 2511 g.P(`Filename: "`, g.file.GetName(), `",`) 2512 2513 g.P("}") 2514 g.P() 2515 2516 g.addInitf("%s.RegisterExtension(%s)", g.Pkg["proto"], ext.DescName()) 2517 2518 g.file.addExport(ext, constOrVarSymbol{ccTypeName, "var", ""}) 2519 } 2520 2521 func (g *Generator) generateInitFunction() { 2522 if len(g.init) == 0 { 2523 return 2524 } 2525 g.P("func init() {") 2526 for _, l := range g.init { 2527 g.P(l) 2528 } 2529 g.P("}") 2530 g.init = nil 2531 } 2532 2533 func (g *Generator) generateFileDescriptor(file *FileDescriptor) { 2534 // Make a copy and trim source_code_info data. 2535 // TODO: Trim this more when we know exactly what we need. 2536 pb := proto.Clone(file.FileDescriptorProto).(*descriptor.FileDescriptorProto) 2537 pb.SourceCodeInfo = nil 2538 2539 b, err := proto.Marshal(pb) 2540 if err != nil { 2541 g.Fail(err.Error()) 2542 } 2543 2544 var buf bytes.Buffer 2545 w, _ := gzip.NewWriterLevel(&buf, gzip.BestCompression) 2546 w.Write(b) 2547 w.Close() 2548 b = buf.Bytes() 2549 2550 v := file.VarName() 2551 g.P() 2552 g.P("func init() { ", g.Pkg["proto"], ".RegisterFile(", strconv.Quote(*file.Name), ", ", v, ") }") 2553 g.P("var ", v, " = []byte{") 2554 g.P("// ", len(b), " bytes of a gzipped FileDescriptorProto") 2555 for len(b) > 0 { 2556 n := 16 2557 if n > len(b) { 2558 n = len(b) 2559 } 2560 2561 s := "" 2562 for _, c := range b[:n] { 2563 s += fmt.Sprintf("0x%02x,", c) 2564 } 2565 g.P(s) 2566 2567 b = b[n:] 2568 } 2569 g.P("}") 2570 } 2571 2572 func (g *Generator) generateEnumRegistration(enum *EnumDescriptor) { 2573 // // We always print the full (proto-world) package name here. 2574 pkg := enum.File().GetPackage() 2575 if pkg != "" { 2576 pkg += "." 2577 } 2578 // The full type name 2579 typeName := enum.TypeName() 2580 // The full type name, CamelCased. 2581 ccTypeName := CamelCaseSlice(typeName) 2582 g.addInitf("%s.RegisterEnum(%q, %[3]s_name, %[3]s_value)", g.Pkg["proto"], pkg+ccTypeName, ccTypeName) 2583 } 2584 2585 // And now lots of helper functions. 2586 2587 // Is c an ASCII lower-case letter? 2588 func isASCIILower(c byte) bool { 2589 return 'a' <= c && c <= 'z' 2590 } 2591 2592 // Is c an ASCII digit? 2593 func isASCIIDigit(c byte) bool { 2594 return '0' <= c && c <= '9' 2595 } 2596 2597 // CamelCase returns the CamelCased name. 2598 // If there is an interior underscore followed by a lower case letter, 2599 // drop the underscore and convert the letter to upper case. 2600 // There is a remote possibility of this rewrite causing a name collision, 2601 // but it's so remote we're prepared to pretend it's nonexistent - since the 2602 // C++ generator lowercases names, it's extremely unlikely to have two fields 2603 // with different capitalizations. 2604 // In short, _my_field_name_2 becomes XMyFieldName_2. 2605 func CamelCase(s string) string { 2606 if s == "" { 2607 return "" 2608 } 2609 t := make([]byte, 0, 32) 2610 i := 0 2611 if s[0] == '_' { 2612 // Need a capital letter; drop the '_'. 2613 t = append(t, 'X') 2614 i++ 2615 } 2616 // Invariant: if the next letter is lower case, it must be converted 2617 // to upper case. 2618 // That is, we process a word at a time, where words are marked by _ or 2619 // upper case letter. Digits are treated as words. 2620 for ; i < len(s); i++ { 2621 c := s[i] 2622 if c == '_' && i+1 < len(s) && isASCIILower(s[i+1]) { 2623 continue // Skip the underscore in s. 2624 } 2625 if isASCIIDigit(c) { 2626 t = append(t, c) 2627 continue 2628 } 2629 // Assume we have a letter now - if not, it's a bogus identifier. 2630 // The next word is a sequence of characters that must start upper case. 2631 if isASCIILower(c) { 2632 c ^= ' ' // Make it a capital letter. 2633 } 2634 t = append(t, c) // Guaranteed not lower case. 2635 // Accept lower case sequence that follows. 2636 for i+1 < len(s) && isASCIILower(s[i+1]) { 2637 i++ 2638 t = append(t, s[i]) 2639 } 2640 } 2641 return string(t) 2642 } 2643 2644 // CamelCaseSlice is like CamelCase, but the argument is a slice of strings to 2645 // be joined with "_". 2646 func CamelCaseSlice(elem []string) string { return CamelCase(strings.Join(elem, "_")) } 2647 2648 // dottedSlice turns a sliced name into a dotted name. 2649 func dottedSlice(elem []string) string { return strings.Join(elem, ".") } 2650 2651 // Is this field optional? 2652 func isOptional(field *descriptor.FieldDescriptorProto) bool { 2653 return *field.Proto3Optional 2654 } 2655 2656 // Is this field required? 2657 func isRequired(field *descriptor.FieldDescriptorProto) bool { 2658 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REQUIRED 2659 } 2660 2661 // Is this field repeated? 2662 func isRepeated(field *descriptor.FieldDescriptorProto) bool { 2663 return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED 2664 } 2665 2666 // Is this field a scalar numeric type? 2667 func isScalar(field *descriptor.FieldDescriptorProto) bool { 2668 if field.Type == nil { 2669 return false 2670 } 2671 switch *field.Type { 2672 case descriptor.FieldDescriptorProto_TYPE_DOUBLE, 2673 descriptor.FieldDescriptorProto_TYPE_FLOAT, 2674 descriptor.FieldDescriptorProto_TYPE_INT64, 2675 descriptor.FieldDescriptorProto_TYPE_UINT64, 2676 descriptor.FieldDescriptorProto_TYPE_INT32, 2677 descriptor.FieldDescriptorProto_TYPE_FIXED64, 2678 descriptor.FieldDescriptorProto_TYPE_FIXED32, 2679 descriptor.FieldDescriptorProto_TYPE_BOOL, 2680 descriptor.FieldDescriptorProto_TYPE_UINT32, 2681 descriptor.FieldDescriptorProto_TYPE_ENUM, 2682 descriptor.FieldDescriptorProto_TYPE_SFIXED32, 2683 descriptor.FieldDescriptorProto_TYPE_SFIXED64, 2684 descriptor.FieldDescriptorProto_TYPE_SINT32, 2685 descriptor.FieldDescriptorProto_TYPE_SINT64: 2686 return true 2687 default: 2688 return false 2689 } 2690 } 2691 2692 // badToUnderscore is the mapping function used to generate Go names from package names, 2693 // which can be dotted in the input .proto file. It replaces non-identifier characters such as 2694 // dot or dash with underscore. 2695 func badToUnderscore(r rune) rune { 2696 if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' { 2697 return r 2698 } 2699 return '_' 2700 } 2701 2702 // baseName returns the last path element of the name, with the last dotted suffix removed. 2703 func baseName(name string) string { 2704 // First, find the last element 2705 if i := strings.LastIndex(name, "/"); i >= 0 { 2706 name = name[i+1:] 2707 } 2708 // Now drop the suffix 2709 if i := strings.LastIndex(name, "."); i >= 0 { 2710 name = name[0:i] 2711 } 2712 return name 2713 } 2714 2715 // The SourceCodeInfo message describes the location of elements of a parsed 2716 // .proto file by way of a "path", which is a sequence of integers that 2717 // describe the route from a FileDescriptorProto to the relevant submessage. 2718 // The path alternates between a field number of a repeated field, and an index 2719 // into that repeated field. The constants below define the field numbers that 2720 // are used. 2721 // 2722 // See descriptor.proto for more information about this. 2723 const ( 2724 // tag numbers in FileDescriptorProto 2725 packagePath = 2 // package 2726 messagePath = 4 // message_type 2727 enumPath = 5 // enum_type 2728 // tag numbers in DescriptorProto 2729 messageFieldPath = 2 // field 2730 messageMessagePath = 3 // nested_type 2731 messageEnumPath = 4 // enum_type 2732 messageOneofPath = 8 // oneof_decl 2733 // tag numbers in EnumDescriptorProto 2734 enumValuePath = 2 // value 2735 ) 2736 2737 var supportTypeAliases bool 2738 2739 func init() { 2740 for _, tag := range build.Default.ReleaseTags { 2741 if tag == "go1.9" { 2742 supportTypeAliases = true 2743 return 2744 } 2745 } 2746 }