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