github.com/bakjos/protoreflect@v1.9.2/desc/protoprint/print.go (about) 1 package protoprint 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "math" 8 "os" 9 "path/filepath" 10 "reflect" 11 "sort" 12 "strings" 13 14 "github.com/golang/protobuf/proto" 15 "github.com/golang/protobuf/protoc-gen-go/descriptor" 16 17 "github.com/bakjos/protoreflect/desc" 18 "github.com/bakjos/protoreflect/desc/internal" 19 "github.com/bakjos/protoreflect/dynamic" 20 ) 21 22 // Printer knows how to format file descriptors as proto source code. Its fields 23 // provide some control over how the resulting source file is constructed and 24 // formatted. 25 type Printer struct { 26 // If true, comments are rendered using "/*" style comments. Otherwise, they 27 // are printed using "//" style line comments. 28 PreferMultiLineStyleComments bool 29 30 // If true, elements are sorted into a canonical order. 31 // 32 // The canonical order for elements in a file follows: 33 // 1. Syntax 34 // 2. Package 35 // 3. Imports (sorted lexically) 36 // 4. Options (sorted by name, standard options before custom options) 37 // 5. Messages (sorted by name) 38 // 6. Enums (sorted by name) 39 // 7. Services (sorted by name) 40 // 8. Extensions (grouped by extendee, sorted by extendee+tag) 41 // 42 // The canonical order of elements in a message follows: 43 // 1. Options (sorted by name, standard options before custom options) 44 // 2. Fields and One-Ofs (sorted by tag; one-ofs interleaved based on the 45 // minimum tag therein) 46 // 3. Nested Messages (sorted by name) 47 // 4. Nested Enums (sorted by name) 48 // 5. Extension ranges (sorted by starting tag number) 49 // 6. Nested Extensions (grouped by extendee, sorted by extendee+tag) 50 // 7. Reserved ranges (sorted by starting tag number) 51 // 8. Reserved names (sorted lexically) 52 // 53 // Methods are sorted within a service by name and appear after any service 54 // options (which are sorted by name, standard options before custom ones). 55 // Enum values are sorted within an enum, first by numeric value then by 56 // name, and also appear after any enum options. 57 // 58 // Options for fields, enum values, and extension ranges are sorted by name, 59 // standard options before custom ones. 60 SortElements bool 61 62 // The indentation used. Any characters other than spaces or tabs will be 63 // replaced with spaces. If unset/empty, two spaces will be used. 64 Indent string 65 66 // If true, detached comments (between elements) will be ignored. 67 // 68 // Deprecated: Use OmitComments bitmask instead. 69 OmitDetachedComments bool 70 71 // A bitmask of comment types to omit. If unset, all comments will be 72 // included. Use CommentsAll to not print any comments. 73 OmitComments CommentType 74 75 // If true, trailing comments that typically appear on the same line as an 76 // element (option, field, enum value, method) will be printed on a separate 77 // line instead. 78 // 79 // So, with this set, you'll get output like so: 80 // 81 // // leading comment for field 82 // repeated string names = 1; 83 // // trailing comment 84 // 85 // If left false, the printer will try to emit trailing comments on the same 86 // line instead: 87 // 88 // // leading comment for field 89 // repeated string names = 1; // trailing comment 90 // 91 // If the trailing comment has more than one line, it will automatically be 92 // forced to the next line. Also, elements that end with "}" instead of ";" 93 // will have trailing comments rendered on the subsequent line. 94 TrailingCommentsOnSeparateLine bool 95 96 // If true, the printed output will eschew any blank lines, which otherwise 97 // appear between descriptor elements and comment blocks. Note that if 98 // detached comments are being printed, this will cause them to be merged 99 // into the subsequent leading comments. Similarly, any element trailing 100 // comments will be merged into the subsequent leading comments. 101 Compact bool 102 103 // If true, all references to messages, extensions, and enums (such as in 104 // options, field types, and method request and response types) will be 105 // fully-qualified. When left unset, the referenced elements will contain 106 // only as much qualifier as is required. 107 // 108 // For example, if a message is in the same package as the reference, the 109 // simple name can be used. If a message shares some context with the 110 // reference, only the unshared context needs to be included. For example: 111 // 112 // message Foo { 113 // message Bar { 114 // enum Baz { 115 // ZERO = 0; 116 // ONE = 1; 117 // } 118 // } 119 // 120 // // This field shares some context as the enum it references: they are 121 // // both inside of the namespace Foo: 122 // // field is "Foo.my_baz" 123 // // enum is "Foo.Bar.Baz" 124 // // So we only need to qualify the reference with the context that they 125 // // do NOT have in common: 126 // Bar.Baz my_baz = 1; 127 // } 128 // 129 // When printing fully-qualified names, they will be preceded by a dot, to 130 // avoid any ambiguity that they might be relative vs. fully-qualified. 131 ForceFullyQualifiedNames bool 132 } 133 134 // CommentType is a kind of comments in a proto source file. This can be used 135 // as a bitmask. 136 type CommentType int 137 138 const ( 139 // CommentsDetached refers to comments that are not "attached" to any 140 // source element. They are attributed to the subsequent element in the 141 // file as "detached" comments. 142 CommentsDetached CommentType = 1 << iota 143 // CommentsTrailing refers to a comment block immediately following an 144 // element in the source file. If another element immediately follows 145 // the trailing comment, it is instead considered a leading comment for 146 // that subsequent element. 147 CommentsTrailing 148 // CommentsLeading refers to a comment block immediately preceding an 149 // element in the source file. For high-level elements (those that have 150 // their own descriptor), these are used as doc comments for that element. 151 CommentsLeading 152 // CommentsTokens refers to any comments (leading, trailing, or detached) 153 // on low-level elements in the file. "High-level" elements have their own 154 // descriptors, e.g. messages, enums, fields, services, and methods. But 155 // comments can appear anywhere (such as around identifiers and keywords, 156 // sprinkled inside the declarations of a high-level element). This class 157 // of comments are for those extra comments sprinkled into the file. 158 CommentsTokens 159 160 // CommentsNonDoc refers to comments that are *not* doc comments. This is a 161 // bitwise union of everything other than CommentsLeading. If you configure 162 // a printer to omit this, only doc comments on descriptor elements will be 163 // included in the printed output. 164 CommentsNonDoc = CommentsDetached | CommentsTrailing | CommentsTokens 165 // CommentsAll indicates all kinds of comments. If you configure a printer 166 // to omit this, no comments will appear in the printed output, even if the 167 // input descriptors had source info and comments. 168 CommentsAll = -1 169 ) 170 171 // PrintProtoFiles prints all of the given file descriptors. The given open 172 // function is given a file name and is responsible for creating the outputs and 173 // returning the corresponding writer. 174 func (p *Printer) PrintProtoFiles(fds []*desc.FileDescriptor, open func(name string) (io.WriteCloser, error)) error { 175 for _, fd := range fds { 176 w, err := open(fd.GetName()) 177 if err != nil { 178 return fmt.Errorf("failed to open %s: %v", fd.GetName(), err) 179 } 180 err = func() error { 181 defer w.Close() 182 return p.PrintProtoFile(fd, w) 183 }() 184 if err != nil { 185 return fmt.Errorf("failed to write %s: %v", fd.GetName(), err) 186 } 187 } 188 return nil 189 } 190 191 // PrintProtosToFileSystem prints all of the given file descriptors to files in 192 // the given directory. If file names in the given descriptors include path 193 // information, they will be relative to the given root. 194 func (p *Printer) PrintProtosToFileSystem(fds []*desc.FileDescriptor, rootDir string) error { 195 return p.PrintProtoFiles(fds, func(name string) (io.WriteCloser, error) { 196 fullPath := filepath.Join(rootDir, name) 197 dir := filepath.Dir(fullPath) 198 if err := os.MkdirAll(dir, os.ModePerm); err != nil { 199 return nil, err 200 } 201 return os.OpenFile(fullPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) 202 }) 203 } 204 205 // pkg represents a package name 206 type pkg string 207 208 // imp represents an imported file name 209 type imp string 210 211 // ident represents an identifier 212 type ident string 213 214 // option represents a resolved descriptor option 215 type option struct { 216 name string 217 val interface{} 218 } 219 220 // reservedRange represents a reserved range from a message or enum 221 type reservedRange struct { 222 start, end int32 223 } 224 225 // PrintProtoFile prints the given single file descriptor to the given writer. 226 func (p *Printer) PrintProtoFile(fd *desc.FileDescriptor, out io.Writer) error { 227 return p.printProto(fd, out) 228 } 229 230 // PrintProto prints the given descriptor and returns the resulting string. This 231 // can be used to print proto files, but it can also be used to get the proto 232 // "source form" for any kind of descriptor, which can be a more user-friendly 233 // way to present descriptors that are intended for human consumption. 234 func (p *Printer) PrintProtoToString(dsc desc.Descriptor) (string, error) { 235 var buf bytes.Buffer 236 if err := p.printProto(dsc, &buf); err != nil { 237 return "", err 238 } 239 return buf.String(), nil 240 } 241 242 func (p *Printer) printProto(dsc desc.Descriptor, out io.Writer) error { 243 w := newWriter(out) 244 245 if p.Indent == "" { 246 // default indent to two spaces 247 p.Indent = " " 248 } else { 249 // indent must be all spaces or tabs, so convert other chars to spaces 250 ind := make([]rune, 0, len(p.Indent)) 251 for _, r := range p.Indent { 252 if r == '\t' { 253 ind = append(ind, r) 254 } else { 255 ind = append(ind, ' ') 256 } 257 } 258 p.Indent = string(ind) 259 } 260 if p.OmitDetachedComments { 261 p.OmitComments |= CommentsDetached 262 } 263 264 er := dynamic.ExtensionRegistry{} 265 er.AddExtensionsFromFileRecursively(dsc.GetFile()) 266 mf := dynamic.NewMessageFactoryWithExtensionRegistry(&er) 267 fdp := dsc.GetFile().AsFileDescriptorProto() 268 sourceInfo := internal.CreateSourceInfoMap(fdp) 269 extendOptionLocations(sourceInfo, fdp.GetSourceCodeInfo().GetLocation()) 270 271 path := findElement(dsc) 272 switch d := dsc.(type) { 273 case *desc.FileDescriptor: 274 p.printFile(d, mf, w, sourceInfo) 275 case *desc.MessageDescriptor: 276 p.printMessage(d, mf, w, sourceInfo, path, 0) 277 case *desc.FieldDescriptor: 278 var scope string 279 if md, ok := d.GetParent().(*desc.MessageDescriptor); ok { 280 scope = md.GetFullyQualifiedName() 281 } else { 282 scope = d.GetFile().GetPackage() 283 } 284 if d.IsExtension() { 285 fmt.Fprint(w, "extend ") 286 extNameSi := sourceInfo.Get(append(path, internal.Field_extendeeTag)) 287 p.printElementString(extNameSi, w, 0, p.qualifyName(d.GetFile().GetPackage(), scope, d.GetOwner().GetFullyQualifiedName())) 288 fmt.Fprintln(w, "{") 289 290 p.printField(d, mf, w, sourceInfo, path, scope, 1) 291 292 fmt.Fprintln(w, "}") 293 } else { 294 p.printField(d, mf, w, sourceInfo, path, scope, 0) 295 } 296 case *desc.OneOfDescriptor: 297 md := d.GetOwner() 298 elements := elementAddrs{dsc: md} 299 for i := range md.GetFields() { 300 elements.addrs = append(elements.addrs, elementAddr{elementType: internal.Message_fieldsTag, elementIndex: i}) 301 } 302 p.printOneOf(d, elements, 0, mf, w, sourceInfo, path[:len(path)-1], 0, path[len(path)-1]) 303 case *desc.EnumDescriptor: 304 p.printEnum(d, mf, w, sourceInfo, path, 0) 305 case *desc.EnumValueDescriptor: 306 p.printEnumValue(d, mf, w, sourceInfo, path, 0) 307 case *desc.ServiceDescriptor: 308 p.printService(d, mf, w, sourceInfo, path, 0) 309 case *desc.MethodDescriptor: 310 p.printMethod(d, mf, w, sourceInfo, path, 0) 311 } 312 313 return w.err 314 } 315 316 func findElement(dsc desc.Descriptor) []int32 { 317 if dsc.GetParent() == nil { 318 return nil 319 } 320 path := findElement(dsc.GetParent()) 321 switch d := dsc.(type) { 322 case *desc.MessageDescriptor: 323 if pm, ok := d.GetParent().(*desc.MessageDescriptor); ok { 324 return append(path, internal.Message_nestedMessagesTag, getMessageIndex(d, pm.GetNestedMessageTypes())) 325 } 326 return append(path, internal.File_messagesTag, getMessageIndex(d, d.GetFile().GetMessageTypes())) 327 328 case *desc.FieldDescriptor: 329 if d.IsExtension() { 330 if pm, ok := d.GetParent().(*desc.MessageDescriptor); ok { 331 return append(path, internal.Message_extensionsTag, getFieldIndex(d, pm.GetNestedExtensions())) 332 } 333 return append(path, internal.File_extensionsTag, getFieldIndex(d, d.GetFile().GetExtensions())) 334 } 335 return append(path, internal.Message_fieldsTag, getFieldIndex(d, d.GetOwner().GetFields())) 336 337 case *desc.OneOfDescriptor: 338 return append(path, internal.Message_oneOfsTag, getOneOfIndex(d, d.GetOwner().GetOneOfs())) 339 340 case *desc.EnumDescriptor: 341 if pm, ok := d.GetParent().(*desc.MessageDescriptor); ok { 342 return append(path, internal.Message_enumsTag, getEnumIndex(d, pm.GetNestedEnumTypes())) 343 } 344 return append(path, internal.File_enumsTag, getEnumIndex(d, d.GetFile().GetEnumTypes())) 345 346 case *desc.EnumValueDescriptor: 347 return append(path, internal.Enum_valuesTag, getEnumValueIndex(d, d.GetEnum().GetValues())) 348 349 case *desc.ServiceDescriptor: 350 return append(path, internal.File_servicesTag, getServiceIndex(d, d.GetFile().GetServices())) 351 352 case *desc.MethodDescriptor: 353 return append(path, internal.Service_methodsTag, getMethodIndex(d, d.GetService().GetMethods())) 354 355 default: 356 panic(fmt.Sprintf("unexpected descriptor type: %T", dsc)) 357 } 358 } 359 360 func getMessageIndex(md *desc.MessageDescriptor, list []*desc.MessageDescriptor) int32 { 361 for i := range list { 362 if md == list[i] { 363 return int32(i) 364 } 365 } 366 panic(fmt.Sprintf("unable to determine index of message %s", md.GetFullyQualifiedName())) 367 } 368 369 func getFieldIndex(fd *desc.FieldDescriptor, list []*desc.FieldDescriptor) int32 { 370 for i := range list { 371 if fd == list[i] { 372 return int32(i) 373 } 374 } 375 panic(fmt.Sprintf("unable to determine index of field %s", fd.GetFullyQualifiedName())) 376 } 377 378 func getOneOfIndex(ood *desc.OneOfDescriptor, list []*desc.OneOfDescriptor) int32 { 379 for i := range list { 380 if ood == list[i] { 381 return int32(i) 382 } 383 } 384 panic(fmt.Sprintf("unable to determine index of oneof %s", ood.GetFullyQualifiedName())) 385 } 386 387 func getEnumIndex(ed *desc.EnumDescriptor, list []*desc.EnumDescriptor) int32 { 388 for i := range list { 389 if ed == list[i] { 390 return int32(i) 391 } 392 } 393 panic(fmt.Sprintf("unable to determine index of enum %s", ed.GetFullyQualifiedName())) 394 } 395 396 func getEnumValueIndex(evd *desc.EnumValueDescriptor, list []*desc.EnumValueDescriptor) int32 { 397 for i := range list { 398 if evd == list[i] { 399 return int32(i) 400 } 401 } 402 panic(fmt.Sprintf("unable to determine index of enum value %s", evd.GetFullyQualifiedName())) 403 } 404 405 func getServiceIndex(sd *desc.ServiceDescriptor, list []*desc.ServiceDescriptor) int32 { 406 for i := range list { 407 if sd == list[i] { 408 return int32(i) 409 } 410 } 411 panic(fmt.Sprintf("unable to determine index of service %s", sd.GetFullyQualifiedName())) 412 } 413 414 func getMethodIndex(mtd *desc.MethodDescriptor, list []*desc.MethodDescriptor) int32 { 415 for i := range list { 416 if mtd == list[i] { 417 return int32(i) 418 } 419 } 420 panic(fmt.Sprintf("unable to determine index of method %s", mtd.GetFullyQualifiedName())) 421 } 422 423 func (p *Printer) newLine(w io.Writer) { 424 if !p.Compact { 425 fmt.Fprintln(w) 426 } 427 } 428 429 func (p *Printer) printFile(fd *desc.FileDescriptor, mf *dynamic.MessageFactory, w *writer, sourceInfo internal.SourceInfoMap) { 430 opts, err := p.extractOptions(fd, fd.GetOptions(), mf) 431 if err != nil { 432 return 433 } 434 435 fdp := fd.AsFileDescriptorProto() 436 path := make([]int32, 1) 437 438 path[0] = internal.File_packageTag 439 sourceInfo.PutIfAbsent(append(path, 0), sourceInfo.Get(path)) 440 441 path[0] = internal.File_syntaxTag 442 si := sourceInfo.Get(path) 443 p.printElement(false, si, w, 0, func(w *writer) { 444 syn := fdp.GetSyntax() 445 if syn == "" { 446 syn = "proto2" 447 } 448 fmt.Fprintf(w, "syntax = %q;", syn) 449 }) 450 p.newLine(w) 451 452 skip := map[interface{}]bool{} 453 454 elements := elementAddrs{dsc: fd, opts: opts} 455 if fdp.Package != nil { 456 elements.addrs = append(elements.addrs, elementAddr{elementType: internal.File_packageTag, elementIndex: 0, order: -3}) 457 } 458 for i := range fdp.GetDependency() { 459 elements.addrs = append(elements.addrs, elementAddr{elementType: internal.File_dependencyTag, elementIndex: i, order: -2}) 460 } 461 elements.addrs = append(elements.addrs, optionsAsElementAddrs(internal.File_optionsTag, -1, opts)...) 462 for i := range fd.GetMessageTypes() { 463 elements.addrs = append(elements.addrs, elementAddr{elementType: internal.File_messagesTag, elementIndex: i}) 464 } 465 for i := range fd.GetEnumTypes() { 466 elements.addrs = append(elements.addrs, elementAddr{elementType: internal.File_enumsTag, elementIndex: i}) 467 } 468 for i := range fd.GetServices() { 469 elements.addrs = append(elements.addrs, elementAddr{elementType: internal.File_servicesTag, elementIndex: i}) 470 } 471 exts := p.computeExtensions(sourceInfo, fd.GetExtensions(), []int32{internal.File_extensionsTag}) 472 for i, extd := range fd.GetExtensions() { 473 if extd.GetType() == descriptor.FieldDescriptorProto_TYPE_GROUP { 474 // we don't emit nested messages for groups since 475 // they get special treatment 476 skip[extd.GetMessageType()] = true 477 } 478 elements.addrs = append(elements.addrs, elementAddr{elementType: internal.File_extensionsTag, elementIndex: i}) 479 } 480 481 p.sort(elements, sourceInfo, nil) 482 483 pkgName := fd.GetPackage() 484 485 for i, el := range elements.addrs { 486 d := elements.at(el) 487 488 // skip[d] will panic if d is a slice (which it could be for []option), 489 // so just ignore it since we don't try to skip options 490 if reflect.TypeOf(d).Kind() != reflect.Slice && skip[d] { 491 // skip this element 492 continue 493 } 494 495 if i > 0 { 496 p.newLine(w) 497 } 498 499 path = []int32{el.elementType, int32(el.elementIndex)} 500 501 switch d := d.(type) { 502 case pkg: 503 si := sourceInfo.Get(path) 504 p.printElement(false, si, w, 0, func(w *writer) { 505 fmt.Fprintf(w, "package %s;", d) 506 }) 507 case imp: 508 si := sourceInfo.Get(path) 509 var modifier string 510 for _, idx := range fdp.PublicDependency { 511 if fdp.Dependency[idx] == string(d) { 512 modifier = "public " 513 break 514 } 515 } 516 if modifier == "" { 517 for _, idx := range fdp.WeakDependency { 518 if fdp.Dependency[idx] == string(d) { 519 modifier = "weak " 520 break 521 } 522 } 523 } 524 p.printElement(false, si, w, 0, func(w *writer) { 525 fmt.Fprintf(w, "import %s%q;", modifier, d) 526 }) 527 case []option: 528 p.printOptionsLong(d, w, sourceInfo, path, 0) 529 case *desc.MessageDescriptor: 530 p.printMessage(d, mf, w, sourceInfo, path, 0) 531 case *desc.EnumDescriptor: 532 p.printEnum(d, mf, w, sourceInfo, path, 0) 533 case *desc.ServiceDescriptor: 534 p.printService(d, mf, w, sourceInfo, path, 0) 535 case *desc.FieldDescriptor: 536 extDecl := exts[d] 537 p.printExtensions(extDecl, exts, elements, i, mf, w, sourceInfo, nil, internal.File_extensionsTag, pkgName, pkgName, 0) 538 // we printed all extensions in the group, so we can skip the others 539 for _, fld := range extDecl.fields { 540 skip[fld] = true 541 } 542 } 543 } 544 } 545 546 func findExtSi(fieldSi *descriptor.SourceCodeInfo_Location, extSis []*descriptor.SourceCodeInfo_Location) *descriptor.SourceCodeInfo_Location { 547 if len(fieldSi.GetSpan()) == 0 { 548 return nil 549 } 550 for _, extSi := range extSis { 551 if isSpanWithin(fieldSi.Span, extSi.Span) { 552 return extSi 553 } 554 } 555 return nil 556 } 557 558 func isSpanWithin(span, enclosing []int32) bool { 559 start := enclosing[0] 560 var end int32 561 if len(enclosing) == 3 { 562 end = enclosing[0] 563 } else { 564 end = enclosing[2] 565 } 566 if span[0] < start || span[0] > end { 567 return false 568 } 569 570 if span[0] == start { 571 return span[1] >= enclosing[1] 572 } else if span[0] == end { 573 return span[1] <= enclosing[len(enclosing)-1] 574 } 575 return true 576 } 577 578 type extensionDecl struct { 579 extendee string 580 sourceInfo *descriptor.SourceCodeInfo_Location 581 fields []*desc.FieldDescriptor 582 } 583 584 type extensions map[*desc.FieldDescriptor]*extensionDecl 585 586 func (p *Printer) computeExtensions(sourceInfo internal.SourceInfoMap, exts []*desc.FieldDescriptor, path []int32) extensions { 587 extsMap := map[string]map[*descriptor.SourceCodeInfo_Location]*extensionDecl{} 588 extSis := sourceInfo.GetAll(path) 589 for _, extd := range exts { 590 name := extd.GetOwner().GetFullyQualifiedName() 591 extSi := findExtSi(extd.GetSourceInfo(), extSis) 592 extsBySi := extsMap[name] 593 if extsBySi == nil { 594 extsBySi = map[*descriptor.SourceCodeInfo_Location]*extensionDecl{} 595 extsMap[name] = extsBySi 596 } 597 extDecl := extsBySi[extSi] 598 if extDecl == nil { 599 extDecl = &extensionDecl{ 600 sourceInfo: extSi, 601 extendee: name, 602 } 603 extsBySi[extSi] = extDecl 604 } 605 extDecl.fields = append(extDecl.fields, extd) 606 } 607 608 ret := extensions{} 609 for _, extsBySi := range extsMap { 610 for _, extDecl := range extsBySi { 611 for _, extd := range extDecl.fields { 612 ret[extd] = extDecl 613 } 614 } 615 } 616 return ret 617 } 618 619 func (p *Printer) sort(elements elementAddrs, sourceInfo internal.SourceInfoMap, path []int32) { 620 if p.SortElements { 621 // canonical sorted order 622 sort.Stable(elements) 623 } else { 624 // use source order (per location information in SourceCodeInfo); or 625 // if that isn't present use declaration order, but grouped by type 626 sort.Stable(elementSrcOrder{ 627 elementAddrs: elements, 628 sourceInfo: sourceInfo, 629 prefix: path, 630 }) 631 } 632 } 633 634 func (p *Printer) qualifyName(pkg, scope string, fqn string) string { 635 if p.ForceFullyQualifiedNames { 636 // forcing fully-qualified names; make sure to include preceding dot 637 if fqn[0] == '.' { 638 return fqn 639 } 640 return fmt.Sprintf(".%s", fqn) 641 } 642 643 // compute relative name (so no leading dot) 644 if fqn[0] == '.' { 645 fqn = fqn[1:] 646 } 647 if len(scope) > 0 && scope[len(scope)-1] != '.' { 648 scope = scope + "." 649 } 650 for scope != "" { 651 if strings.HasPrefix(fqn, scope) { 652 return fqn[len(scope):] 653 } 654 if scope == pkg+"." { 655 break 656 } 657 pos := strings.LastIndex(scope[:len(scope)-1], ".") 658 scope = scope[:pos+1] 659 } 660 return fqn 661 } 662 663 func (p *Printer) typeString(fld *desc.FieldDescriptor, scope string) string { 664 if fld.IsMap() { 665 return fmt.Sprintf("map<%s, %s>", p.typeString(fld.GetMapKeyType(), scope), p.typeString(fld.GetMapValueType(), scope)) 666 } 667 switch fld.GetType() { 668 case descriptor.FieldDescriptorProto_TYPE_INT32: 669 return "int32" 670 case descriptor.FieldDescriptorProto_TYPE_INT64: 671 return "int64" 672 case descriptor.FieldDescriptorProto_TYPE_UINT32: 673 return "uint32" 674 case descriptor.FieldDescriptorProto_TYPE_UINT64: 675 return "uint64" 676 case descriptor.FieldDescriptorProto_TYPE_SINT32: 677 return "sint32" 678 case descriptor.FieldDescriptorProto_TYPE_SINT64: 679 return "sint64" 680 case descriptor.FieldDescriptorProto_TYPE_FIXED32: 681 return "fixed32" 682 case descriptor.FieldDescriptorProto_TYPE_FIXED64: 683 return "fixed64" 684 case descriptor.FieldDescriptorProto_TYPE_SFIXED32: 685 return "sfixed32" 686 case descriptor.FieldDescriptorProto_TYPE_SFIXED64: 687 return "sfixed64" 688 case descriptor.FieldDescriptorProto_TYPE_FLOAT: 689 return "float" 690 case descriptor.FieldDescriptorProto_TYPE_DOUBLE: 691 return "double" 692 case descriptor.FieldDescriptorProto_TYPE_BOOL: 693 return "bool" 694 case descriptor.FieldDescriptorProto_TYPE_STRING: 695 return "string" 696 case descriptor.FieldDescriptorProto_TYPE_BYTES: 697 return "bytes" 698 case descriptor.FieldDescriptorProto_TYPE_ENUM: 699 return p.qualifyName(fld.GetFile().GetPackage(), scope, fld.GetEnumType().GetFullyQualifiedName()) 700 case descriptor.FieldDescriptorProto_TYPE_MESSAGE: 701 return p.qualifyName(fld.GetFile().GetPackage(), scope, fld.GetMessageType().GetFullyQualifiedName()) 702 case descriptor.FieldDescriptorProto_TYPE_GROUP: 703 return fld.GetMessageType().GetName() 704 } 705 panic(fmt.Sprintf("invalid type: %v", fld.GetType())) 706 } 707 708 func (p *Printer) printMessage(md *desc.MessageDescriptor, mf *dynamic.MessageFactory, w *writer, sourceInfo internal.SourceInfoMap, path []int32, indent int) { 709 si := sourceInfo.Get(path) 710 p.printElement(true, si, w, indent, func(w *writer) { 711 p.indent(w, indent) 712 713 fmt.Fprint(w, "message ") 714 nameSi := sourceInfo.Get(append(path, internal.Message_nameTag)) 715 p.printElementString(nameSi, w, indent, md.GetName()) 716 fmt.Fprintln(w, "{") 717 718 p.printMessageBody(md, mf, w, sourceInfo, path, indent+1) 719 p.indent(w, indent) 720 fmt.Fprintln(w, "}") 721 }) 722 } 723 724 func (p *Printer) printMessageBody(md *desc.MessageDescriptor, mf *dynamic.MessageFactory, w *writer, sourceInfo internal.SourceInfoMap, path []int32, indent int) { 725 opts, err := p.extractOptions(md, md.GetOptions(), mf) 726 if err != nil { 727 if w.err == nil { 728 w.err = err 729 } 730 return 731 } 732 733 skip := map[interface{}]bool{} 734 maxTag := internal.GetMaxTag(md.GetMessageOptions().GetMessageSetWireFormat()) 735 736 elements := elementAddrs{dsc: md, opts: opts} 737 elements.addrs = append(elements.addrs, optionsAsElementAddrs(internal.Message_optionsTag, -1, opts)...) 738 for i := range md.AsDescriptorProto().GetReservedRange() { 739 elements.addrs = append(elements.addrs, elementAddr{elementType: internal.Message_reservedRangeTag, elementIndex: i}) 740 } 741 for i := range md.AsDescriptorProto().GetReservedName() { 742 elements.addrs = append(elements.addrs, elementAddr{elementType: internal.Message_reservedNameTag, elementIndex: i}) 743 } 744 for i := range md.AsDescriptorProto().GetExtensionRange() { 745 elements.addrs = append(elements.addrs, elementAddr{elementType: internal.Message_extensionRangeTag, elementIndex: i}) 746 } 747 for i, fld := range md.GetFields() { 748 if fld.IsMap() || fld.GetType() == descriptor.FieldDescriptorProto_TYPE_GROUP { 749 // we don't emit nested messages for map types or groups since 750 // they get special treatment 751 skip[fld.GetMessageType()] = true 752 } 753 elements.addrs = append(elements.addrs, elementAddr{elementType: internal.Message_fieldsTag, elementIndex: i}) 754 } 755 for i := range md.GetNestedMessageTypes() { 756 elements.addrs = append(elements.addrs, elementAddr{elementType: internal.Message_nestedMessagesTag, elementIndex: i}) 757 } 758 for i := range md.GetNestedEnumTypes() { 759 elements.addrs = append(elements.addrs, elementAddr{elementType: internal.Message_enumsTag, elementIndex: i}) 760 } 761 exts := p.computeExtensions(sourceInfo, md.GetNestedExtensions(), append(path, internal.Message_extensionsTag)) 762 for i, extd := range md.GetNestedExtensions() { 763 if extd.GetType() == descriptor.FieldDescriptorProto_TYPE_GROUP { 764 // we don't emit nested messages for groups since 765 // they get special treatment 766 skip[extd.GetMessageType()] = true 767 } 768 elements.addrs = append(elements.addrs, elementAddr{elementType: internal.Message_extensionsTag, elementIndex: i}) 769 } 770 771 p.sort(elements, sourceInfo, path) 772 773 pkg := md.GetFile().GetPackage() 774 scope := md.GetFullyQualifiedName() 775 776 for i, el := range elements.addrs { 777 d := elements.at(el) 778 779 // skip[d] will panic if d is a slice (which it could be for []option), 780 // so just ignore it since we don't try to skip options 781 if reflect.TypeOf(d).Kind() != reflect.Slice && skip[d] { 782 // skip this element 783 continue 784 } 785 786 if i > 0 { 787 p.newLine(w) 788 } 789 790 childPath := append(path, el.elementType, int32(el.elementIndex)) 791 792 switch d := d.(type) { 793 case []option: 794 p.printOptionsLong(d, w, sourceInfo, childPath, indent) 795 case *desc.FieldDescriptor: 796 if d.IsExtension() { 797 extDecl := exts[d] 798 p.printExtensions(extDecl, exts, elements, i, mf, w, sourceInfo, path, internal.Message_extensionsTag, pkg, scope, indent) 799 // we printed all extensions in the group, so we can skip the others 800 for _, fld := range extDecl.fields { 801 skip[fld] = true 802 } 803 } else { 804 ood := d.GetOneOf() 805 if ood == nil || ood.IsSynthetic() { 806 p.printField(d, mf, w, sourceInfo, childPath, scope, indent) 807 } else { 808 // print the one-of, including all of its fields 809 p.printOneOf(ood, elements, i, mf, w, sourceInfo, path, indent, d.AsFieldDescriptorProto().GetOneofIndex()) 810 for _, fld := range ood.GetChoices() { 811 skip[fld] = true 812 } 813 } 814 } 815 case *desc.MessageDescriptor: 816 p.printMessage(d, mf, w, sourceInfo, childPath, indent) 817 case *desc.EnumDescriptor: 818 p.printEnum(d, mf, w, sourceInfo, childPath, indent) 819 case *descriptor.DescriptorProto_ExtensionRange: 820 // collapse ranges into a single "extensions" block 821 ranges := []*descriptor.DescriptorProto_ExtensionRange{d} 822 addrs := []elementAddr{el} 823 for idx := i + 1; idx < len(elements.addrs); idx++ { 824 elnext := elements.addrs[idx] 825 if elnext.elementType != el.elementType { 826 break 827 } 828 extr := elements.at(elnext).(*descriptor.DescriptorProto_ExtensionRange) 829 if !areEqual(d.Options, extr.Options, mf) { 830 break 831 } 832 ranges = append(ranges, extr) 833 addrs = append(addrs, elnext) 834 skip[extr] = true 835 } 836 p.printExtensionRanges(md, ranges, maxTag, addrs, mf, w, sourceInfo, path, indent) 837 case reservedRange: 838 // collapse reserved ranges into a single "reserved" block 839 ranges := []reservedRange{d} 840 addrs := []elementAddr{el} 841 for idx := i + 1; idx < len(elements.addrs); idx++ { 842 elnext := elements.addrs[idx] 843 if elnext.elementType != el.elementType { 844 break 845 } 846 rr := elements.at(elnext).(reservedRange) 847 ranges = append(ranges, rr) 848 addrs = append(addrs, elnext) 849 skip[rr] = true 850 } 851 p.printReservedRanges(ranges, maxTag, addrs, w, sourceInfo, path, indent) 852 case string: // reserved name 853 // collapse reserved names into a single "reserved" block 854 names := []string{d} 855 addrs := []elementAddr{el} 856 for idx := i + 1; idx < len(elements.addrs); idx++ { 857 elnext := elements.addrs[idx] 858 if elnext.elementType != el.elementType { 859 break 860 } 861 rn := elements.at(elnext).(string) 862 names = append(names, rn) 863 addrs = append(addrs, elnext) 864 skip[rn] = true 865 } 866 p.printReservedNames(names, addrs, w, sourceInfo, path, indent) 867 } 868 } 869 } 870 871 func areEqual(a, b proto.Message, mf *dynamic.MessageFactory) bool { 872 // proto.Equal doesn't handle unknown extensions very well :( 873 // so we convert to a dynamic message (which should know about all extensions via 874 // extension registry) and then compare 875 return dynamic.MessagesEqual(asDynamicIfPossible(a, mf), asDynamicIfPossible(b, mf)) 876 } 877 878 func asDynamicIfPossible(msg proto.Message, mf *dynamic.MessageFactory) proto.Message { 879 if dm, ok := msg.(*dynamic.Message); ok { 880 return dm 881 } else { 882 md, err := desc.LoadMessageDescriptorForMessage(msg) 883 if err == nil { 884 dm := mf.NewDynamicMessage(md) 885 if dm.ConvertFrom(msg) == nil { 886 return dm 887 } 888 } 889 } 890 return msg 891 } 892 893 func (p *Printer) printField(fld *desc.FieldDescriptor, mf *dynamic.MessageFactory, w *writer, sourceInfo internal.SourceInfoMap, path []int32, scope string, indent int) { 894 var groupPath []int32 895 var si *descriptor.SourceCodeInfo_Location 896 897 group := isGroup(fld) 898 899 if group { 900 // compute path to group message type 901 groupPath = make([]int32, len(path)-2) 902 copy(groupPath, path) 903 904 var candidates []*desc.MessageDescriptor 905 var parentTag int32 906 switch parent := fld.GetParent().(type) { 907 case *desc.MessageDescriptor: 908 // group in a message 909 candidates = parent.GetNestedMessageTypes() 910 parentTag = internal.Message_nestedMessagesTag 911 case *desc.FileDescriptor: 912 // group that is a top-level extension 913 candidates = parent.GetMessageTypes() 914 parentTag = internal.File_messagesTag 915 } 916 917 var groupMsgIndex int32 918 for i, nmd := range candidates { 919 if nmd == fld.GetMessageType() { 920 // found it 921 groupMsgIndex = int32(i) 922 break 923 } 924 } 925 groupPath = append(groupPath, parentTag, groupMsgIndex) 926 927 // the group message is where the field's comments and position are stored 928 si = sourceInfo.Get(groupPath) 929 } else { 930 si = sourceInfo.Get(path) 931 } 932 933 p.printElement(true, si, w, indent, func(w *writer) { 934 p.indent(w, indent) 935 if shouldEmitLabel(fld) { 936 locSi := sourceInfo.Get(append(path, internal.Field_labelTag)) 937 p.printElementString(locSi, w, indent, labelString(fld.GetLabel())) 938 } 939 940 if group { 941 fmt.Fprint(w, "group ") 942 } 943 944 typeSi := sourceInfo.Get(append(path, internal.Field_typeTag)) 945 p.printElementString(typeSi, w, indent, p.typeString(fld, scope)) 946 947 if !group { 948 nameSi := sourceInfo.Get(append(path, internal.Field_nameTag)) 949 p.printElementString(nameSi, w, indent, fld.GetName()) 950 } 951 952 fmt.Fprint(w, "= ") 953 numSi := sourceInfo.Get(append(path, internal.Field_numberTag)) 954 p.printElementString(numSi, w, indent, fmt.Sprintf("%d", fld.GetNumber())) 955 956 opts, err := p.extractOptions(fld, fld.GetOptions(), mf) 957 if err != nil { 958 if w.err == nil { 959 w.err = err 960 } 961 return 962 } 963 964 // we use negative values for "extras" keys so they can't collide 965 // with legit option tags 966 967 if !fld.GetFile().IsProto3() && fld.AsFieldDescriptorProto().DefaultValue != nil { 968 defVal := fld.GetDefaultValue() 969 if fld.GetEnumType() != nil { 970 defVal = fld.GetEnumType().FindValueByNumber(defVal.(int32)) 971 } 972 opts[-internal.Field_defaultTag] = []option{{name: "default", val: defVal}} 973 } 974 975 jsn := fld.AsFieldDescriptorProto().GetJsonName() 976 if jsn != "" && jsn != internal.JsonName(fld.GetName()) { 977 opts[-internal.Field_jsonNameTag] = []option{{name: "json_name", val: jsn}} 978 } 979 980 elements := elementAddrs{dsc: fld, opts: opts} 981 elements.addrs = optionsAsElementAddrs(internal.Field_optionsTag, 0, opts) 982 p.sort(elements, sourceInfo, path) 983 p.printOptionElementsShort(elements, w, sourceInfo, path, indent) 984 985 if group { 986 fmt.Fprintln(w, "{") 987 p.printMessageBody(fld.GetMessageType(), mf, w, sourceInfo, groupPath, indent+1) 988 989 p.indent(w, indent) 990 fmt.Fprintln(w, "}") 991 992 } else { 993 fmt.Fprint(w, ";") 994 } 995 }) 996 } 997 998 func shouldEmitLabel(fld *desc.FieldDescriptor) bool { 999 return fld.IsProto3Optional() || 1000 (!fld.IsMap() && fld.GetOneOf() == nil && 1001 (fld.GetLabel() != descriptor.FieldDescriptorProto_LABEL_OPTIONAL || !fld.GetFile().IsProto3())) 1002 } 1003 1004 func labelString(lbl descriptor.FieldDescriptorProto_Label) string { 1005 switch lbl { 1006 case descriptor.FieldDescriptorProto_LABEL_OPTIONAL: 1007 return "optional" 1008 case descriptor.FieldDescriptorProto_LABEL_REQUIRED: 1009 return "required" 1010 case descriptor.FieldDescriptorProto_LABEL_REPEATED: 1011 return "repeated" 1012 } 1013 panic(fmt.Sprintf("invalid label: %v", lbl)) 1014 } 1015 1016 func isGroup(fld *desc.FieldDescriptor) bool { 1017 return fld.GetType() == descriptor.FieldDescriptorProto_TYPE_GROUP 1018 } 1019 1020 func (p *Printer) printOneOf(ood *desc.OneOfDescriptor, parentElements elementAddrs, startFieldIndex int, mf *dynamic.MessageFactory, w *writer, sourceInfo internal.SourceInfoMap, parentPath []int32, indent int, ooIndex int32) { 1021 oopath := append(parentPath, internal.Message_oneOfsTag, ooIndex) 1022 oosi := sourceInfo.Get(oopath) 1023 p.printElement(true, oosi, w, indent, func(w *writer) { 1024 p.indent(w, indent) 1025 fmt.Fprint(w, "oneof ") 1026 extNameSi := sourceInfo.Get(append(oopath, internal.OneOf_nameTag)) 1027 p.printElementString(extNameSi, w, indent, ood.GetName()) 1028 fmt.Fprintln(w, "{") 1029 1030 indent++ 1031 opts, err := p.extractOptions(ood, ood.GetOptions(), mf) 1032 if err != nil { 1033 if w.err == nil { 1034 w.err = err 1035 } 1036 return 1037 } 1038 1039 elements := elementAddrs{dsc: ood, opts: opts} 1040 elements.addrs = append(elements.addrs, optionsAsElementAddrs(internal.OneOf_optionsTag, -1, opts)...) 1041 1042 count := len(ood.GetChoices()) 1043 for idx := startFieldIndex; count > 0 && idx < len(parentElements.addrs); idx++ { 1044 el := parentElements.addrs[idx] 1045 if el.elementType != internal.Message_fieldsTag { 1046 continue 1047 } 1048 if parentElements.at(el).(*desc.FieldDescriptor).GetOneOf() == ood { 1049 // negative tag indicates that this element is actually a sibling, not a child 1050 elements.addrs = append(elements.addrs, elementAddr{elementType: -internal.Message_fieldsTag, elementIndex: el.elementIndex}) 1051 count-- 1052 } 1053 } 1054 1055 // the fields are already sorted, but we have to re-sort in order to 1056 // interleave the options (in the event that we are using file location 1057 // order and the option locations are interleaved with the fields) 1058 p.sort(elements, sourceInfo, oopath) 1059 scope := ood.GetOwner().GetFullyQualifiedName() 1060 1061 for i, el := range elements.addrs { 1062 if i > 0 { 1063 p.newLine(w) 1064 } 1065 1066 switch d := elements.at(el).(type) { 1067 case []option: 1068 childPath := append(oopath, el.elementType, int32(el.elementIndex)) 1069 p.printOptionsLong(d, w, sourceInfo, childPath, indent) 1070 case *desc.FieldDescriptor: 1071 childPath := append(parentPath, -el.elementType, int32(el.elementIndex)) 1072 p.printField(d, mf, w, sourceInfo, childPath, scope, indent) 1073 } 1074 } 1075 1076 p.indent(w, indent-1) 1077 fmt.Fprintln(w, "}") 1078 }) 1079 } 1080 1081 func (p *Printer) printExtensions(exts *extensionDecl, allExts extensions, parentElements elementAddrs, startFieldIndex int, mf *dynamic.MessageFactory, w *writer, sourceInfo internal.SourceInfoMap, parentPath []int32, extTag int32, pkg, scope string, indent int) { 1082 path := append(parentPath, extTag) 1083 p.printLeadingComments(exts.sourceInfo, w, indent) 1084 p.indent(w, indent) 1085 fmt.Fprint(w, "extend ") 1086 extNameSi := sourceInfo.Get(append(path, 0, internal.Field_extendeeTag)) 1087 p.printElementString(extNameSi, w, indent, p.qualifyName(pkg, scope, exts.extendee)) 1088 fmt.Fprintln(w, "{") 1089 1090 count := len(exts.fields) 1091 first := true 1092 for idx := startFieldIndex; count > 0 && idx < len(parentElements.addrs); idx++ { 1093 el := parentElements.addrs[idx] 1094 if el.elementType != extTag { 1095 continue 1096 } 1097 fld := parentElements.at(el).(*desc.FieldDescriptor) 1098 if allExts[fld] == exts { 1099 if first { 1100 first = false 1101 } else { 1102 p.newLine(w) 1103 } 1104 childPath := append(path, int32(el.elementIndex)) 1105 p.printField(fld, mf, w, sourceInfo, childPath, scope, indent+1) 1106 count-- 1107 } 1108 } 1109 1110 p.indent(w, indent) 1111 fmt.Fprintln(w, "}") 1112 p.printTrailingComments(exts.sourceInfo, w, indent) 1113 if indent >= 0 && !w.newline { 1114 // if we're not printing inline but element did not have trailing newline, add one now 1115 fmt.Fprintln(w) 1116 } 1117 } 1118 1119 func (p *Printer) printExtensionRanges(parent *desc.MessageDescriptor, ranges []*descriptor.DescriptorProto_ExtensionRange, maxTag int32, addrs []elementAddr, mf *dynamic.MessageFactory, w *writer, sourceInfo internal.SourceInfoMap, parentPath []int32, indent int) { 1120 p.indent(w, indent) 1121 fmt.Fprint(w, "extensions ") 1122 1123 var opts *descriptor.ExtensionRangeOptions 1124 var elPath []int32 1125 first := true 1126 for i, extr := range ranges { 1127 if first { 1128 first = false 1129 } else { 1130 fmt.Fprint(w, ", ") 1131 } 1132 opts = extr.Options 1133 el := addrs[i] 1134 elPath = append(parentPath, el.elementType, int32(el.elementIndex)) 1135 si := sourceInfo.Get(elPath) 1136 p.printElement(true, si, w, inline(indent), func(w *writer) { 1137 if extr.GetStart() == extr.GetEnd()-1 { 1138 fmt.Fprintf(w, "%d ", extr.GetStart()) 1139 } else if extr.GetEnd()-1 == maxTag { 1140 fmt.Fprintf(w, "%d to max ", extr.GetStart()) 1141 } else { 1142 fmt.Fprintf(w, "%d to %d ", extr.GetStart(), extr.GetEnd()-1) 1143 } 1144 }) 1145 } 1146 dsc := extensionRange{owner: parent, extRange: ranges[0]} 1147 p.printOptionsShort(dsc, opts, mf, internal.ExtensionRange_optionsTag, w, sourceInfo, elPath, indent) 1148 1149 fmt.Fprintln(w, ";") 1150 } 1151 1152 func (p *Printer) printReservedRanges(ranges []reservedRange, maxVal int32, addrs []elementAddr, w *writer, sourceInfo internal.SourceInfoMap, parentPath []int32, indent int) { 1153 p.indent(w, indent) 1154 fmt.Fprint(w, "reserved ") 1155 1156 first := true 1157 for i, rr := range ranges { 1158 if first { 1159 first = false 1160 } else { 1161 fmt.Fprint(w, ", ") 1162 } 1163 el := addrs[i] 1164 si := sourceInfo.Get(append(parentPath, el.elementType, int32(el.elementIndex))) 1165 p.printElement(false, si, w, inline(indent), func(w *writer) { 1166 if rr.start == rr.end { 1167 fmt.Fprintf(w, "%d ", rr.start) 1168 } else if rr.end == maxVal { 1169 fmt.Fprintf(w, "%d to max ", rr.start) 1170 } else { 1171 fmt.Fprintf(w, "%d to %d ", rr.start, rr.end) 1172 } 1173 }) 1174 } 1175 1176 fmt.Fprintln(w, ";") 1177 } 1178 1179 func (p *Printer) printReservedNames(names []string, addrs []elementAddr, w *writer, sourceInfo internal.SourceInfoMap, parentPath []int32, indent int) { 1180 p.indent(w, indent) 1181 fmt.Fprint(w, "reserved ") 1182 1183 first := true 1184 for i, name := range names { 1185 if first { 1186 first = false 1187 } else { 1188 fmt.Fprint(w, ", ") 1189 } 1190 el := addrs[i] 1191 si := sourceInfo.Get(append(parentPath, el.elementType, int32(el.elementIndex))) 1192 p.printElementString(si, w, indent, quotedString(name)) 1193 } 1194 1195 fmt.Fprintln(w, ";") 1196 } 1197 1198 func (p *Printer) printEnum(ed *desc.EnumDescriptor, mf *dynamic.MessageFactory, w *writer, sourceInfo internal.SourceInfoMap, path []int32, indent int) { 1199 si := sourceInfo.Get(path) 1200 p.printElement(true, si, w, indent, func(w *writer) { 1201 p.indent(w, indent) 1202 1203 fmt.Fprint(w, "enum ") 1204 nameSi := sourceInfo.Get(append(path, internal.Enum_nameTag)) 1205 p.printElementString(nameSi, w, indent, ed.GetName()) 1206 fmt.Fprintln(w, "{") 1207 1208 indent++ 1209 opts, err := p.extractOptions(ed, ed.GetOptions(), mf) 1210 if err != nil { 1211 if w.err == nil { 1212 w.err = err 1213 } 1214 return 1215 } 1216 1217 skip := map[interface{}]bool{} 1218 1219 elements := elementAddrs{dsc: ed, opts: opts} 1220 elements.addrs = append(elements.addrs, optionsAsElementAddrs(internal.Enum_optionsTag, -1, opts)...) 1221 for i := range ed.GetValues() { 1222 elements.addrs = append(elements.addrs, elementAddr{elementType: internal.Enum_valuesTag, elementIndex: i}) 1223 } 1224 for i := range ed.AsEnumDescriptorProto().GetReservedRange() { 1225 elements.addrs = append(elements.addrs, elementAddr{elementType: internal.Enum_reservedRangeTag, elementIndex: i}) 1226 } 1227 for i := range ed.AsEnumDescriptorProto().GetReservedName() { 1228 elements.addrs = append(elements.addrs, elementAddr{elementType: internal.Enum_reservedNameTag, elementIndex: i}) 1229 } 1230 1231 p.sort(elements, sourceInfo, path) 1232 1233 for i, el := range elements.addrs { 1234 d := elements.at(el) 1235 1236 // skip[d] will panic if d is a slice (which it could be for []option), 1237 // so just ignore it since we don't try to skip options 1238 if reflect.TypeOf(d).Kind() != reflect.Slice && skip[d] { 1239 // skip this element 1240 continue 1241 } 1242 1243 if i > 0 { 1244 p.newLine(w) 1245 } 1246 1247 childPath := append(path, el.elementType, int32(el.elementIndex)) 1248 1249 switch d := d.(type) { 1250 case []option: 1251 p.printOptionsLong(d, w, sourceInfo, childPath, indent) 1252 case *desc.EnumValueDescriptor: 1253 p.printEnumValue(d, mf, w, sourceInfo, childPath, indent) 1254 case reservedRange: 1255 // collapse reserved ranges into a single "reserved" block 1256 ranges := []reservedRange{d} 1257 addrs := []elementAddr{el} 1258 for idx := i + 1; idx < len(elements.addrs); idx++ { 1259 elnext := elements.addrs[idx] 1260 if elnext.elementType != el.elementType { 1261 break 1262 } 1263 rr := elements.at(elnext).(reservedRange) 1264 ranges = append(ranges, rr) 1265 addrs = append(addrs, elnext) 1266 skip[rr] = true 1267 } 1268 p.printReservedRanges(ranges, math.MaxInt32, addrs, w, sourceInfo, path, indent) 1269 case string: // reserved name 1270 // collapse reserved names into a single "reserved" block 1271 names := []string{d} 1272 addrs := []elementAddr{el} 1273 for idx := i + 1; idx < len(elements.addrs); idx++ { 1274 elnext := elements.addrs[idx] 1275 if elnext.elementType != el.elementType { 1276 break 1277 } 1278 rn := elements.at(elnext).(string) 1279 names = append(names, rn) 1280 addrs = append(addrs, elnext) 1281 skip[rn] = true 1282 } 1283 p.printReservedNames(names, addrs, w, sourceInfo, path, indent) 1284 } 1285 } 1286 1287 p.indent(w, indent-1) 1288 fmt.Fprintln(w, "}") 1289 }) 1290 } 1291 1292 func (p *Printer) printEnumValue(evd *desc.EnumValueDescriptor, mf *dynamic.MessageFactory, w *writer, sourceInfo internal.SourceInfoMap, path []int32, indent int) { 1293 si := sourceInfo.Get(path) 1294 p.printElement(true, si, w, indent, func(w *writer) { 1295 p.indent(w, indent) 1296 1297 nameSi := sourceInfo.Get(append(path, internal.EnumVal_nameTag)) 1298 p.printElementString(nameSi, w, indent, evd.GetName()) 1299 fmt.Fprint(w, "= ") 1300 1301 numSi := sourceInfo.Get(append(path, internal.EnumVal_numberTag)) 1302 p.printElementString(numSi, w, indent, fmt.Sprintf("%d", evd.GetNumber())) 1303 1304 p.printOptionsShort(evd, evd.GetOptions(), mf, internal.EnumVal_optionsTag, w, sourceInfo, path, indent) 1305 1306 fmt.Fprint(w, ";") 1307 }) 1308 } 1309 1310 func (p *Printer) printService(sd *desc.ServiceDescriptor, mf *dynamic.MessageFactory, w *writer, sourceInfo internal.SourceInfoMap, path []int32, indent int) { 1311 si := sourceInfo.Get(path) 1312 p.printElement(true, si, w, indent, func(w *writer) { 1313 p.indent(w, indent) 1314 1315 fmt.Fprint(w, "service ") 1316 nameSi := sourceInfo.Get(append(path, internal.Service_nameTag)) 1317 p.printElementString(nameSi, w, indent, sd.GetName()) 1318 fmt.Fprintln(w, "{") 1319 1320 indent++ 1321 1322 opts, err := p.extractOptions(sd, sd.GetOptions(), mf) 1323 if err != nil { 1324 if w.err == nil { 1325 w.err = err 1326 } 1327 return 1328 } 1329 1330 elements := elementAddrs{dsc: sd, opts: opts} 1331 elements.addrs = append(elements.addrs, optionsAsElementAddrs(internal.Service_optionsTag, -1, opts)...) 1332 for i := range sd.GetMethods() { 1333 elements.addrs = append(elements.addrs, elementAddr{elementType: internal.Service_methodsTag, elementIndex: i}) 1334 } 1335 1336 p.sort(elements, sourceInfo, path) 1337 1338 for i, el := range elements.addrs { 1339 if i > 0 { 1340 p.newLine(w) 1341 } 1342 1343 childPath := append(path, el.elementType, int32(el.elementIndex)) 1344 1345 switch d := elements.at(el).(type) { 1346 case []option: 1347 p.printOptionsLong(d, w, sourceInfo, childPath, indent) 1348 case *desc.MethodDescriptor: 1349 p.printMethod(d, mf, w, sourceInfo, childPath, indent) 1350 } 1351 } 1352 1353 p.indent(w, indent-1) 1354 fmt.Fprintln(w, "}") 1355 }) 1356 } 1357 1358 func (p *Printer) printMethod(mtd *desc.MethodDescriptor, mf *dynamic.MessageFactory, w *writer, sourceInfo internal.SourceInfoMap, path []int32, indent int) { 1359 si := sourceInfo.Get(path) 1360 pkg := mtd.GetFile().GetPackage() 1361 p.printElement(true, si, w, indent, func(w *writer) { 1362 p.indent(w, indent) 1363 1364 fmt.Fprint(w, "rpc ") 1365 nameSi := sourceInfo.Get(append(path, internal.Method_nameTag)) 1366 p.printElementString(nameSi, w, indent, mtd.GetName()) 1367 1368 fmt.Fprint(w, "( ") 1369 inSi := sourceInfo.Get(append(path, internal.Method_inputTag)) 1370 inName := p.qualifyName(pkg, pkg, mtd.GetInputType().GetFullyQualifiedName()) 1371 if mtd.IsClientStreaming() { 1372 inName = "stream " + inName 1373 } 1374 p.printElementString(inSi, w, indent, inName) 1375 1376 fmt.Fprint(w, ") returns ( ") 1377 1378 outSi := sourceInfo.Get(append(path, internal.Method_outputTag)) 1379 outName := p.qualifyName(pkg, pkg, mtd.GetOutputType().GetFullyQualifiedName()) 1380 if mtd.IsServerStreaming() { 1381 outName = "stream " + outName 1382 } 1383 p.printElementString(outSi, w, indent, outName) 1384 fmt.Fprint(w, ") ") 1385 1386 opts, err := p.extractOptions(mtd, mtd.GetOptions(), mf) 1387 if err != nil { 1388 if w.err == nil { 1389 w.err = err 1390 } 1391 return 1392 } 1393 1394 if len(opts) > 0 { 1395 fmt.Fprintln(w, "{") 1396 indent++ 1397 1398 elements := elementAddrs{dsc: mtd, opts: opts} 1399 elements.addrs = optionsAsElementAddrs(internal.Method_optionsTag, 0, opts) 1400 p.sort(elements, sourceInfo, path) 1401 path = append(path, internal.Method_optionsTag) 1402 1403 for i, addr := range elements.addrs { 1404 if i > 0 { 1405 p.newLine(w) 1406 } 1407 o := elements.at(addr).([]option) 1408 p.printOptionsLong(o, w, sourceInfo, path, indent) 1409 } 1410 1411 p.indent(w, indent-1) 1412 fmt.Fprintln(w, "}") 1413 } else { 1414 fmt.Fprint(w, ";") 1415 } 1416 }) 1417 } 1418 1419 func (p *Printer) printOptionsLong(opts []option, w *writer, sourceInfo internal.SourceInfoMap, path []int32, indent int) { 1420 p.printOptions(opts, w, indent, 1421 func(i int32) *descriptor.SourceCodeInfo_Location { 1422 return sourceInfo.Get(append(path, i)) 1423 }, 1424 func(w *writer, indent int, opt option) { 1425 p.indent(w, indent) 1426 fmt.Fprint(w, "option ") 1427 p.printOption(opt.name, opt.val, w, indent) 1428 fmt.Fprint(w, ";") 1429 }) 1430 } 1431 1432 func (p *Printer) printOptionsShort(dsc interface{}, optsMsg proto.Message, mf *dynamic.MessageFactory, optsTag int32, w *writer, sourceInfo internal.SourceInfoMap, path []int32, indent int) { 1433 d, ok := dsc.(desc.Descriptor) 1434 if !ok { 1435 d = dsc.(extensionRange).owner 1436 } 1437 opts, err := p.extractOptions(d, optsMsg, mf) 1438 if err != nil { 1439 if w.err == nil { 1440 w.err = err 1441 } 1442 return 1443 } 1444 1445 elements := elementAddrs{dsc: dsc, opts: opts} 1446 elements.addrs = optionsAsElementAddrs(optsTag, 0, opts) 1447 p.sort(elements, sourceInfo, path) 1448 p.printOptionElementsShort(elements, w, sourceInfo, path, indent) 1449 } 1450 1451 func (p *Printer) printOptionElementsShort(addrs elementAddrs, w *writer, sourceInfo internal.SourceInfoMap, path []int32, indent int) { 1452 if len(addrs.addrs) == 0 { 1453 return 1454 } 1455 first := true 1456 fmt.Fprint(w, "[") 1457 for _, addr := range addrs.addrs { 1458 opts := addrs.at(addr).([]option) 1459 var childPath []int32 1460 if addr.elementIndex < 0 { 1461 // pseudo-option 1462 childPath = append(path, int32(-addr.elementIndex)) 1463 } else { 1464 childPath = append(path, addr.elementType, int32(addr.elementIndex)) 1465 } 1466 p.printOptions(opts, w, inline(indent), 1467 func(i int32) *descriptor.SourceCodeInfo_Location { 1468 p := childPath 1469 if addr.elementIndex >= 0 { 1470 p = append(p, i) 1471 } 1472 return sourceInfo.Get(p) 1473 }, 1474 func(w *writer, indent int, opt option) { 1475 if first { 1476 first = false 1477 } else { 1478 fmt.Fprint(w, ", ") 1479 } 1480 p.printOption(opt.name, opt.val, w, indent) 1481 fmt.Fprint(w, " ") // trailing space 1482 }) 1483 } 1484 fmt.Fprint(w, "] ") 1485 } 1486 1487 func (p *Printer) printOptions(opts []option, w *writer, indent int, siFetch func(i int32) *descriptor.SourceCodeInfo_Location, fn func(w *writer, indent int, opt option)) { 1488 for i, opt := range opts { 1489 si := siFetch(int32(i)) 1490 p.printElement(false, si, w, indent, func(w *writer) { 1491 fn(w, indent, opt) 1492 }) 1493 } 1494 } 1495 1496 func inline(indent int) int { 1497 if indent < 0 { 1498 // already inlined 1499 return indent 1500 } 1501 // negative indent means inline; indent 2 stops further in case value wraps 1502 return -indent - 2 1503 } 1504 1505 func sortKeys(m map[interface{}]interface{}) []interface{} { 1506 res := make(sortedKeys, len(m)) 1507 i := 0 1508 for k := range m { 1509 res[i] = k 1510 i++ 1511 } 1512 sort.Sort(res) 1513 return ([]interface{})(res) 1514 } 1515 1516 type sortedKeys []interface{} 1517 1518 func (k sortedKeys) Len() int { 1519 return len(k) 1520 } 1521 1522 func (k sortedKeys) Swap(i, j int) { 1523 k[i], k[j] = k[j], k[i] 1524 } 1525 1526 func (k sortedKeys) Less(i, j int) bool { 1527 switch i := k[i].(type) { 1528 case int32: 1529 return i < k[j].(int32) 1530 case uint32: 1531 return i < k[j].(uint32) 1532 case int64: 1533 return i < k[j].(int64) 1534 case uint64: 1535 return i < k[j].(uint64) 1536 case string: 1537 return i < k[j].(string) 1538 case bool: 1539 return !i && k[j].(bool) 1540 default: 1541 panic(fmt.Sprintf("invalid type for map key: %T", i)) 1542 } 1543 } 1544 1545 func (p *Printer) printOption(name string, optVal interface{}, w *writer, indent int) { 1546 fmt.Fprintf(w, "%s = ", name) 1547 1548 switch optVal := optVal.(type) { 1549 case int32, uint32, int64, uint64: 1550 fmt.Fprintf(w, "%d", optVal) 1551 case float32, float64: 1552 fmt.Fprintf(w, "%f", optVal) 1553 case string: 1554 fmt.Fprintf(w, "%s", quotedString(optVal)) 1555 case []byte: 1556 fmt.Fprintf(w, "%s", quotedString(string(optVal))) 1557 case bool: 1558 fmt.Fprintf(w, "%v", optVal) 1559 case ident: 1560 fmt.Fprintf(w, "%s", optVal) 1561 case *desc.EnumValueDescriptor: 1562 fmt.Fprintf(w, "%s", optVal.GetName()) 1563 case proto.Message: 1564 // TODO: if value is too long, marshal to text format with indentation to 1565 // make output prettier (also requires correctly indenting subsequent lines) 1566 1567 // TODO: alternate approach so we can apply p.ForceFullyQualifiedNames 1568 // inside the resulting value? 1569 1570 fmt.Fprintf(w, "{ %s }", proto.CompactTextString(optVal)) 1571 default: 1572 panic(fmt.Sprintf("unknown type of value %T for field %s", optVal, name)) 1573 } 1574 } 1575 1576 type edgeKind int 1577 1578 const ( 1579 edgeKindOption edgeKind = iota 1580 edgeKindFile 1581 edgeKindMessage 1582 edgeKindField 1583 edgeKindOneOf 1584 edgeKindExtensionRange 1585 edgeKindEnum 1586 edgeKindEnumVal 1587 edgeKindService 1588 edgeKindMethod 1589 ) 1590 1591 // edges in simple state machine for matching options paths 1592 // whose prefix should be included in source info to handle 1593 // the way options are printed (which cannot always include 1594 // the full path from original source) 1595 var edges = map[edgeKind]map[int32]edgeKind{ 1596 edgeKindFile: { 1597 internal.File_optionsTag: edgeKindOption, 1598 internal.File_messagesTag: edgeKindMessage, 1599 internal.File_enumsTag: edgeKindEnum, 1600 internal.File_extensionsTag: edgeKindField, 1601 internal.File_servicesTag: edgeKindService, 1602 }, 1603 edgeKindMessage: { 1604 internal.Message_optionsTag: edgeKindOption, 1605 internal.Message_fieldsTag: edgeKindField, 1606 internal.Message_oneOfsTag: edgeKindOneOf, 1607 internal.Message_nestedMessagesTag: edgeKindMessage, 1608 internal.Message_enumsTag: edgeKindEnum, 1609 internal.Message_extensionsTag: edgeKindField, 1610 internal.Message_extensionRangeTag: edgeKindExtensionRange, 1611 // TODO: reserved range tag 1612 }, 1613 edgeKindField: { 1614 internal.Field_optionsTag: edgeKindOption, 1615 }, 1616 edgeKindOneOf: { 1617 internal.OneOf_optionsTag: edgeKindOption, 1618 }, 1619 edgeKindExtensionRange: { 1620 internal.ExtensionRange_optionsTag: edgeKindOption, 1621 }, 1622 edgeKindEnum: { 1623 internal.Enum_optionsTag: edgeKindOption, 1624 internal.Enum_valuesTag: edgeKindEnumVal, 1625 }, 1626 edgeKindEnumVal: { 1627 internal.EnumVal_optionsTag: edgeKindOption, 1628 }, 1629 edgeKindService: { 1630 internal.Service_optionsTag: edgeKindOption, 1631 internal.Service_methodsTag: edgeKindMethod, 1632 }, 1633 edgeKindMethod: { 1634 internal.Method_optionsTag: edgeKindOption, 1635 }, 1636 } 1637 1638 func extendOptionLocations(sc internal.SourceInfoMap, locs []*descriptor.SourceCodeInfo_Location) { 1639 // we iterate in the order that locations appear in descriptor 1640 // for determinism (if we ranged over the map, order and thus 1641 // potentially results are non-deterministic) 1642 for _, loc := range locs { 1643 allowed := edges[edgeKindFile] 1644 for i := 0; i+1 < len(loc.Path); i += 2 { 1645 nextKind, ok := allowed[loc.Path[i]] 1646 if !ok { 1647 break 1648 } 1649 if nextKind == edgeKindOption { 1650 // We've found an option entry. This could be arbitrarily 1651 // deep (for options that nested messages) or it could end 1652 // abruptly (for non-repeated fields). But we need a path 1653 // that is exactly the path-so-far plus two: the option tag 1654 // and an optional index for repeated option fields (zero 1655 // for non-repeated option fields). This is used for 1656 // querying source info when printing options. 1657 // for sorting elements 1658 newPath := make([]int32, i+3) 1659 copy(newPath, loc.Path) 1660 sc.PutIfAbsent(newPath, loc) 1661 // we do another path of path-so-far plus two, but with 1662 // explicit zero index -- just in case this actual path has 1663 // an extra path element, but it's not an index (e.g the 1664 // option field is not repeated, but the source info we are 1665 // looking at indicates a tag of a nested field) 1666 newPath[len(newPath)-1] = 0 1667 sc.PutIfAbsent(newPath, loc) 1668 // finally, we need the path-so-far plus one, just the option 1669 // tag, for sorting option groups 1670 newPath = newPath[:len(newPath)-1] 1671 sc.PutIfAbsent(newPath, loc) 1672 1673 break 1674 } else { 1675 allowed = edges[nextKind] 1676 } 1677 } 1678 } 1679 } 1680 1681 func (p *Printer) extractOptions(dsc desc.Descriptor, opts proto.Message, mf *dynamic.MessageFactory) (map[int32][]option, error) { 1682 md, err := desc.LoadMessageDescriptorForMessage(opts) 1683 if err != nil { 1684 return nil, err 1685 } 1686 dm := mf.NewDynamicMessage(md) 1687 if err = dm.ConvertFrom(opts); err != nil { 1688 return nil, fmt.Errorf("failed convert %s to dynamic message: %v", md.GetFullyQualifiedName(), err) 1689 } 1690 1691 pkg := dsc.GetFile().GetPackage() 1692 var scope string 1693 if _, ok := dsc.(*desc.FileDescriptor); ok { 1694 scope = pkg 1695 } else { 1696 scope = dsc.GetFullyQualifiedName() 1697 } 1698 1699 options := map[int32][]option{} 1700 var uninterpreted []interface{} 1701 for _, fldset := range [][]*desc.FieldDescriptor{md.GetFields(), mf.GetExtensionRegistry().AllExtensionsForType(md.GetFullyQualifiedName())} { 1702 for _, fld := range fldset { 1703 if dm.HasField(fld) { 1704 val := dm.GetField(fld) 1705 var opts []option 1706 var name string 1707 if fld.IsExtension() { 1708 name = fmt.Sprintf("(%s)", p.qualifyName(pkg, scope, fld.GetFullyQualifiedName())) 1709 } else { 1710 name = fld.GetName() 1711 } 1712 switch val := val.(type) { 1713 case []interface{}: 1714 if fld.GetNumber() == internal.UninterpretedOptionsTag { 1715 // we handle uninterpreted options differently 1716 uninterpreted = val 1717 continue 1718 } 1719 1720 for _, e := range val { 1721 if fld.GetType() == descriptor.FieldDescriptorProto_TYPE_ENUM { 1722 ev := fld.GetEnumType().FindValueByNumber(e.(int32)) 1723 if ev == nil { 1724 // have to skip unknown enum values :( 1725 continue 1726 } 1727 e = ev 1728 } 1729 var name string 1730 if fld.IsExtension() { 1731 name = fmt.Sprintf("(%s)", p.qualifyName(pkg, scope, fld.GetFullyQualifiedName())) 1732 } else { 1733 name = fld.GetName() 1734 } 1735 opts = append(opts, option{name: name, val: e}) 1736 } 1737 case map[interface{}]interface{}: 1738 for k := range sortKeys(val) { 1739 v := val[k] 1740 vf := fld.GetMapValueType() 1741 if vf.GetType() == descriptor.FieldDescriptorProto_TYPE_ENUM { 1742 ev := vf.GetEnumType().FindValueByNumber(v.(int32)) 1743 if ev == nil { 1744 // have to skip unknown enum values :( 1745 continue 1746 } 1747 v = ev 1748 } 1749 entry := mf.NewDynamicMessage(fld.GetMessageType()) 1750 entry.SetFieldByNumber(1, k) 1751 entry.SetFieldByNumber(2, v) 1752 opts = append(opts, option{name: name, val: entry}) 1753 } 1754 default: 1755 if fld.GetType() == descriptor.FieldDescriptorProto_TYPE_ENUM { 1756 ev := fld.GetEnumType().FindValueByNumber(val.(int32)) 1757 if ev == nil { 1758 // have to skip unknown enum values :( 1759 continue 1760 } 1761 val = ev 1762 } 1763 opts = append(opts, option{name: name, val: val}) 1764 } 1765 if len(opts) > 0 { 1766 options[fld.GetNumber()] = opts 1767 } 1768 } 1769 } 1770 } 1771 1772 // if there are uninterpreted options, add those too 1773 if len(uninterpreted) > 0 { 1774 opts := make([]option, len(uninterpreted)) 1775 for i, u := range uninterpreted { 1776 var unint *descriptor.UninterpretedOption 1777 if un, ok := u.(*descriptor.UninterpretedOption); ok { 1778 unint = un 1779 } else { 1780 dm := u.(*dynamic.Message) 1781 unint = &descriptor.UninterpretedOption{} 1782 if err := dm.ConvertTo(unint); err != nil { 1783 return nil, err 1784 } 1785 } 1786 1787 var buf bytes.Buffer 1788 for ni, n := range unint.Name { 1789 if ni > 0 { 1790 buf.WriteByte('.') 1791 } 1792 if n.GetIsExtension() { 1793 fmt.Fprintf(&buf, "(%s)", n.GetNamePart()) 1794 } else { 1795 buf.WriteString(n.GetNamePart()) 1796 } 1797 } 1798 1799 var v interface{} 1800 switch { 1801 case unint.IdentifierValue != nil: 1802 v = ident(unint.GetIdentifierValue()) 1803 case unint.StringValue != nil: 1804 v = string(unint.GetStringValue()) 1805 case unint.DoubleValue != nil: 1806 v = unint.GetDoubleValue() 1807 case unint.PositiveIntValue != nil: 1808 v = unint.GetPositiveIntValue() 1809 case unint.NegativeIntValue != nil: 1810 v = unint.GetNegativeIntValue() 1811 case unint.AggregateValue != nil: 1812 v = ident(unint.GetAggregateValue()) 1813 } 1814 1815 opts[i] = option{name: buf.String(), val: v} 1816 } 1817 options[internal.UninterpretedOptionsTag] = opts 1818 } 1819 1820 return options, nil 1821 } 1822 1823 func optionsAsElementAddrs(optionsTag int32, order int, opts map[int32][]option) []elementAddr { 1824 var optAddrs []elementAddr 1825 for tag := range opts { 1826 optAddrs = append(optAddrs, elementAddr{elementType: optionsTag, elementIndex: int(tag), order: order}) 1827 } 1828 sort.Sort(optionsByName{addrs: optAddrs, opts: opts}) 1829 return optAddrs 1830 } 1831 1832 // quotedString implements the text format for string literals for protocol 1833 // buffers. This form is also acceptable for string literals in option values 1834 // by the protocol buffer compiler, protoc. 1835 func quotedString(s string) string { 1836 var b bytes.Buffer 1837 // use WriteByte here to get any needed indent 1838 b.WriteByte('"') 1839 // Loop over the bytes, not the runes. 1840 for i := 0; i < len(s); i++ { 1841 // Divergence from C++: we don't escape apostrophes. 1842 // There's no need to escape them, and the C++ parser 1843 // copes with a naked apostrophe. 1844 switch c := s[i]; c { 1845 case '\n': 1846 b.WriteString("\\n") 1847 case '\r': 1848 b.WriteString("\\r") 1849 case '\t': 1850 b.WriteString("\\t") 1851 case '"': 1852 b.WriteString("\\") 1853 case '\\': 1854 b.WriteString("\\\\") 1855 default: 1856 if c >= 0x20 && c < 0x7f { 1857 b.WriteByte(c) 1858 } else { 1859 fmt.Fprintf(&b, "\\%03o", c) 1860 } 1861 } 1862 } 1863 b.WriteByte('"') 1864 1865 return b.String() 1866 } 1867 1868 type elementAddr struct { 1869 elementType int32 1870 elementIndex int 1871 order int 1872 } 1873 1874 type elementAddrs struct { 1875 addrs []elementAddr 1876 dsc interface{} 1877 opts map[int32][]option 1878 } 1879 1880 func (a elementAddrs) Len() int { 1881 return len(a.addrs) 1882 } 1883 1884 func (a elementAddrs) Less(i, j int) bool { 1885 // explicit order is considered first 1886 if a.addrs[i].order < a.addrs[j].order { 1887 return true 1888 } else if a.addrs[i].order > a.addrs[j].order { 1889 return false 1890 } 1891 // if order is equal, sort by element type 1892 if a.addrs[i].elementType < a.addrs[j].elementType { 1893 return true 1894 } else if a.addrs[i].elementType > a.addrs[j].elementType { 1895 return false 1896 } 1897 1898 di := a.at(a.addrs[i]) 1899 dj := a.at(a.addrs[j]) 1900 1901 switch vi := di.(type) { 1902 case *desc.FieldDescriptor: 1903 // fields are ordered by tag number 1904 vj := dj.(*desc.FieldDescriptor) 1905 // regular fields before extensions; extensions grouped by extendee 1906 if !vi.IsExtension() && vj.IsExtension() { 1907 return true 1908 } else if vi.IsExtension() && !vj.IsExtension() { 1909 return false 1910 } else if vi.IsExtension() && vj.IsExtension() { 1911 if vi.GetOwner() != vj.GetOwner() { 1912 return vi.GetOwner().GetFullyQualifiedName() < vj.GetOwner().GetFullyQualifiedName() 1913 } 1914 } 1915 return vi.GetNumber() < vj.GetNumber() 1916 1917 case *desc.EnumValueDescriptor: 1918 // enum values ordered by number then name 1919 vj := dj.(*desc.EnumValueDescriptor) 1920 if vi.GetNumber() == vj.GetNumber() { 1921 return vi.GetName() < vj.GetName() 1922 } 1923 return vi.GetNumber() < vj.GetNumber() 1924 1925 case *descriptor.DescriptorProto_ExtensionRange: 1926 // extension ranges ordered by tag 1927 return vi.GetStart() < dj.(*descriptor.DescriptorProto_ExtensionRange).GetStart() 1928 1929 case reservedRange: 1930 // reserved ranges ordered by tag, too 1931 return vi.start < dj.(reservedRange).start 1932 1933 case string: 1934 // reserved names lexically sorted 1935 return vi < dj.(string) 1936 1937 case pkg: 1938 // reserved names lexically sorted 1939 return vi < dj.(pkg) 1940 1941 case imp: 1942 // reserved names lexically sorted 1943 return vi < dj.(imp) 1944 1945 case []option: 1946 // options sorted by name, extensions last 1947 return optionLess(vi, dj.([]option)) 1948 1949 default: 1950 // all other descriptors ordered by name 1951 return di.(desc.Descriptor).GetName() < dj.(desc.Descriptor).GetName() 1952 } 1953 } 1954 1955 func (a elementAddrs) Swap(i, j int) { 1956 a.addrs[i], a.addrs[j] = a.addrs[j], a.addrs[i] 1957 } 1958 1959 func (a elementAddrs) at(addr elementAddr) interface{} { 1960 switch dsc := a.dsc.(type) { 1961 case *desc.FileDescriptor: 1962 switch addr.elementType { 1963 case internal.File_packageTag: 1964 return pkg(dsc.GetPackage()) 1965 case internal.File_dependencyTag: 1966 return imp(dsc.AsFileDescriptorProto().GetDependency()[addr.elementIndex]) 1967 case internal.File_optionsTag: 1968 return a.opts[int32(addr.elementIndex)] 1969 case internal.File_messagesTag: 1970 return dsc.GetMessageTypes()[addr.elementIndex] 1971 case internal.File_enumsTag: 1972 return dsc.GetEnumTypes()[addr.elementIndex] 1973 case internal.File_servicesTag: 1974 return dsc.GetServices()[addr.elementIndex] 1975 case internal.File_extensionsTag: 1976 return dsc.GetExtensions()[addr.elementIndex] 1977 } 1978 case *desc.MessageDescriptor: 1979 switch addr.elementType { 1980 case internal.Message_optionsTag: 1981 return a.opts[int32(addr.elementIndex)] 1982 case internal.Message_fieldsTag: 1983 return dsc.GetFields()[addr.elementIndex] 1984 case internal.Message_nestedMessagesTag: 1985 return dsc.GetNestedMessageTypes()[addr.elementIndex] 1986 case internal.Message_enumsTag: 1987 return dsc.GetNestedEnumTypes()[addr.elementIndex] 1988 case internal.Message_extensionsTag: 1989 return dsc.GetNestedExtensions()[addr.elementIndex] 1990 case internal.Message_extensionRangeTag: 1991 return dsc.AsDescriptorProto().GetExtensionRange()[addr.elementIndex] 1992 case internal.Message_reservedRangeTag: 1993 rng := dsc.AsDescriptorProto().GetReservedRange()[addr.elementIndex] 1994 return reservedRange{start: rng.GetStart(), end: rng.GetEnd() - 1} 1995 case internal.Message_reservedNameTag: 1996 return dsc.AsDescriptorProto().GetReservedName()[addr.elementIndex] 1997 } 1998 case *desc.FieldDescriptor: 1999 if addr.elementType == internal.Field_optionsTag { 2000 return a.opts[int32(addr.elementIndex)] 2001 } 2002 case *desc.OneOfDescriptor: 2003 switch addr.elementType { 2004 case internal.OneOf_optionsTag: 2005 return a.opts[int32(addr.elementIndex)] 2006 case -internal.Message_fieldsTag: 2007 return dsc.GetOwner().GetFields()[addr.elementIndex] 2008 } 2009 case *desc.EnumDescriptor: 2010 switch addr.elementType { 2011 case internal.Enum_optionsTag: 2012 return a.opts[int32(addr.elementIndex)] 2013 case internal.Enum_valuesTag: 2014 return dsc.GetValues()[addr.elementIndex] 2015 case internal.Enum_reservedRangeTag: 2016 rng := dsc.AsEnumDescriptorProto().GetReservedRange()[addr.elementIndex] 2017 return reservedRange{start: rng.GetStart(), end: rng.GetEnd()} 2018 case internal.Enum_reservedNameTag: 2019 return dsc.AsEnumDescriptorProto().GetReservedName()[addr.elementIndex] 2020 } 2021 case *desc.EnumValueDescriptor: 2022 if addr.elementType == internal.EnumVal_optionsTag { 2023 return a.opts[int32(addr.elementIndex)] 2024 } 2025 case *desc.ServiceDescriptor: 2026 switch addr.elementType { 2027 case internal.Service_optionsTag: 2028 return a.opts[int32(addr.elementIndex)] 2029 case internal.Service_methodsTag: 2030 return dsc.GetMethods()[addr.elementIndex] 2031 } 2032 case *desc.MethodDescriptor: 2033 if addr.elementType == internal.Method_optionsTag { 2034 return a.opts[int32(addr.elementIndex)] 2035 } 2036 case extensionRange: 2037 if addr.elementType == internal.ExtensionRange_optionsTag { 2038 return a.opts[int32(addr.elementIndex)] 2039 } 2040 } 2041 2042 panic(fmt.Sprintf("location for unknown field %d of %T", addr.elementType, a.dsc)) 2043 } 2044 2045 type extensionRange struct { 2046 owner *desc.MessageDescriptor 2047 extRange *descriptor.DescriptorProto_ExtensionRange 2048 } 2049 2050 type elementSrcOrder struct { 2051 elementAddrs 2052 sourceInfo internal.SourceInfoMap 2053 prefix []int32 2054 } 2055 2056 func (a elementSrcOrder) Less(i, j int) bool { 2057 ti := a.addrs[i].elementType 2058 ei := a.addrs[i].elementIndex 2059 2060 tj := a.addrs[j].elementType 2061 ej := a.addrs[j].elementIndex 2062 2063 var si, sj *descriptor.SourceCodeInfo_Location 2064 if ei < 0 { 2065 si = a.sourceInfo.Get(append(a.prefix, -int32(ei))) 2066 } else if ti < 0 { 2067 p := make([]int32, len(a.prefix)-2) 2068 copy(p, a.prefix) 2069 si = a.sourceInfo.Get(append(p, ti, int32(ei))) 2070 } else { 2071 si = a.sourceInfo.Get(append(a.prefix, ti, int32(ei))) 2072 } 2073 if ej < 0 { 2074 sj = a.sourceInfo.Get(append(a.prefix, -int32(ej))) 2075 } else if tj < 0 { 2076 p := make([]int32, len(a.prefix)-2) 2077 copy(p, a.prefix) 2078 sj = a.sourceInfo.Get(append(p, tj, int32(ej))) 2079 } else { 2080 sj = a.sourceInfo.Get(append(a.prefix, tj, int32(ej))) 2081 } 2082 2083 if (si == nil) != (sj == nil) { 2084 // generally, we put unknown elements after known ones; 2085 // except package, imports, and option elements go first 2086 2087 // i will be unknown and j will be known 2088 swapped := false 2089 if si != nil { 2090 ti, tj = tj, ti 2091 swapped = true 2092 } 2093 switch a.dsc.(type) { 2094 case *desc.FileDescriptor: 2095 // NB: These comparisons are *trying* to get things ordered so that 2096 // 1) If the package element has no source info, it appears _first_. 2097 // 2) If any import element has no source info, it appears _after_ 2098 // the package element but _before_ any other element. 2099 // 3) If any option element has no source info, it appears _after_ 2100 // the package and import elements but _before_ any other element. 2101 // If the package, imports, and options are all missing source info, 2102 // this will sort them all to the top in expected order. But if they 2103 // are mixed (some _do_ have source info, some do not), and elements 2104 // with source info have spans that positions them _after_ other 2105 // elements in the file, then this Less function will be unstable 2106 // since the above dual objectives for imports and options ("before 2107 // this but after that") may be in conflict with one another. This 2108 // should not cause any problems, other than elements being possibly 2109 // sorted in a confusing order. 2110 // 2111 // Well-formed descriptors should instead have consistent source 2112 // info: either all elements have source info or none do. So this 2113 // should not be an issue in practice. 2114 if ti == internal.File_packageTag { 2115 return !swapped 2116 } 2117 if ti == internal.File_dependencyTag { 2118 if tj == internal.File_packageTag { 2119 // imports will come *after* package 2120 return swapped 2121 } 2122 return !swapped 2123 } 2124 if ti == internal.File_optionsTag { 2125 if tj == internal.File_packageTag || tj == internal.File_dependencyTag { 2126 // options will come *after* package and imports 2127 return swapped 2128 } 2129 return !swapped 2130 } 2131 case *desc.MessageDescriptor: 2132 if ti == internal.Message_optionsTag { 2133 return !swapped 2134 } 2135 case *desc.EnumDescriptor: 2136 if ti == internal.Enum_optionsTag { 2137 return !swapped 2138 } 2139 case *desc.ServiceDescriptor: 2140 if ti == internal.Service_optionsTag { 2141 return !swapped 2142 } 2143 } 2144 return swapped 2145 2146 } else if si == nil || sj == nil { 2147 // let stable sort keep unknown elements in same relative order 2148 return false 2149 } 2150 2151 for idx := 0; idx < len(sj.Span); idx++ { 2152 if idx >= len(si.Span) { 2153 return true 2154 } 2155 if si.Span[idx] < sj.Span[idx] { 2156 return true 2157 } 2158 if si.Span[idx] > sj.Span[idx] { 2159 return false 2160 } 2161 } 2162 return false 2163 } 2164 2165 type optionsByName struct { 2166 addrs []elementAddr 2167 opts map[int32][]option 2168 } 2169 2170 func (o optionsByName) Len() int { 2171 return len(o.addrs) 2172 } 2173 2174 func (o optionsByName) Less(i, j int) bool { 2175 oi := o.opts[int32(o.addrs[i].elementIndex)] 2176 oj := o.opts[int32(o.addrs[j].elementIndex)] 2177 return optionLess(oi, oj) 2178 } 2179 2180 func optionLess(i, j []option) bool { 2181 ni := i[0].name 2182 nj := j[0].name 2183 if ni[0] != '(' && nj[0] == '(' { 2184 return true 2185 } else if ni[0] == '(' && nj[0] != '(' { 2186 return false 2187 } 2188 return ni < nj 2189 } 2190 2191 func (o optionsByName) Swap(i, j int) { 2192 o.addrs[i], o.addrs[j] = o.addrs[j], o.addrs[i] 2193 } 2194 2195 func (p *Printer) printElement(isDecriptor bool, si *descriptor.SourceCodeInfo_Location, w *writer, indent int, el func(*writer)) { 2196 includeComments := isDecriptor || p.includeCommentType(CommentsTokens) 2197 2198 if includeComments && si != nil { 2199 p.printLeadingComments(si, w, indent) 2200 } 2201 el(w) 2202 if includeComments && si != nil { 2203 p.printTrailingComments(si, w, indent) 2204 } 2205 if indent >= 0 && !w.newline { 2206 // if we're not printing inline but element did not have trailing newline, add one now 2207 fmt.Fprintln(w) 2208 } 2209 } 2210 2211 func (p *Printer) printElementString(si *descriptor.SourceCodeInfo_Location, w *writer, indent int, str string) { 2212 p.printElement(false, si, w, inline(indent), func(w *writer) { 2213 fmt.Fprintf(w, "%s ", str) 2214 }) 2215 } 2216 2217 func (p *Printer) includeCommentType(c CommentType) bool { 2218 return (p.OmitComments & c) == 0 2219 } 2220 2221 func (p *Printer) printLeadingComments(si *descriptor.SourceCodeInfo_Location, w *writer, indent int) bool { 2222 endsInNewLine := false 2223 2224 if p.includeCommentType(CommentsDetached) { 2225 for _, c := range si.GetLeadingDetachedComments() { 2226 if p.printComment(c, w, indent, true) { 2227 // if comment ended in newline, add another newline to separate 2228 // this comment from the next 2229 p.newLine(w) 2230 endsInNewLine = true 2231 } else if indent < 0 { 2232 // comment did not end in newline and we are trying to inline? 2233 // just add a space to separate this comment from what follows 2234 fmt.Fprint(w, " ") 2235 endsInNewLine = false 2236 } else { 2237 // comment did not end in newline and we are *not* trying to inline? 2238 // add newline to end of comment and add another to separate this 2239 // comment from what follows 2240 fmt.Fprintln(w) // needed to end comment, regardless of p.Compact 2241 p.newLine(w) 2242 endsInNewLine = true 2243 } 2244 } 2245 } 2246 2247 if p.includeCommentType(CommentsLeading) && si.GetLeadingComments() != "" { 2248 endsInNewLine = p.printComment(si.GetLeadingComments(), w, indent, true) 2249 if !endsInNewLine { 2250 if indent >= 0 { 2251 // leading comment didn't end with newline but needs one 2252 // (because we're *not* inlining) 2253 fmt.Fprintln(w) // needed to end comment, regardless of p.Compact 2254 endsInNewLine = true 2255 } else { 2256 // space between comment and following element when inlined 2257 fmt.Fprint(w, " ") 2258 } 2259 } 2260 } 2261 2262 return endsInNewLine 2263 } 2264 2265 func (p *Printer) printTrailingComments(si *descriptor.SourceCodeInfo_Location, w *writer, indent int) { 2266 if p.includeCommentType(CommentsTrailing) && si.GetTrailingComments() != "" { 2267 if !p.printComment(si.GetTrailingComments(), w, indent, p.TrailingCommentsOnSeparateLine) && indent >= 0 { 2268 // trailing comment didn't end with newline but needs one 2269 // (because we're *not* inlining) 2270 fmt.Fprintln(w) // needed to end comment, regardless of p.Compact 2271 } else if indent < 0 { 2272 fmt.Fprint(w, " ") 2273 } 2274 } 2275 } 2276 2277 func (p *Printer) printComment(comments string, w *writer, indent int, forceNextLine bool) bool { 2278 if comments == "" { 2279 return false 2280 } 2281 2282 var multiLine bool 2283 if indent < 0 { 2284 // use multi-line style when inlining 2285 multiLine = true 2286 } else { 2287 multiLine = p.PreferMultiLineStyleComments 2288 } 2289 if multiLine && strings.Contains(comments, "*/") { 2290 // can't emit '*/' in a multi-line style comment 2291 multiLine = false 2292 } 2293 2294 lines := strings.Split(comments, "\n") 2295 2296 // first, remove leading and trailing blank lines 2297 if lines[0] == "" { 2298 lines = lines[1:] 2299 } 2300 if lines[len(lines)-1] == "" { 2301 lines = lines[:len(lines)-1] 2302 } 2303 if len(lines) == 0 { 2304 return false 2305 } 2306 2307 if indent >= 0 && !w.newline { 2308 // last element did not have trailing newline, so we 2309 // either need to tack on newline or, if comment is 2310 // just one line, inline it on the end 2311 if forceNextLine || len(lines) > 1 { 2312 fmt.Fprintln(w) 2313 } else { 2314 if !w.space { 2315 fmt.Fprint(w, " ") 2316 } 2317 indent = inline(indent) 2318 } 2319 } 2320 2321 if len(lines) == 1 && multiLine { 2322 p.indent(w, indent) 2323 line := lines[0] 2324 if line[0] == ' ' && line[len(line)-1] != ' ' { 2325 // add trailing space for symmetry 2326 line += " " 2327 } 2328 fmt.Fprintf(w, "/*%s*/", line) 2329 if indent >= 0 { 2330 fmt.Fprintln(w) 2331 return true 2332 } 2333 return false 2334 } 2335 2336 if multiLine { 2337 // multi-line style comments that actually span multiple lines 2338 // get a blank line before and after so that comment renders nicely 2339 lines = append(lines, "", "") 2340 copy(lines[1:], lines) 2341 lines[0] = "" 2342 } 2343 2344 for i, l := range lines { 2345 p.maybeIndent(w, indent, i > 0) 2346 if multiLine { 2347 if i == 0 { 2348 // first line 2349 fmt.Fprintf(w, "/*%s\n", strings.TrimRight(l, " \t")) 2350 } else if i == len(lines)-1 { 2351 // last line 2352 if l == "" { 2353 fmt.Fprint(w, " */") 2354 } else { 2355 fmt.Fprintf(w, " *%s*/", l) 2356 } 2357 if indent >= 0 { 2358 fmt.Fprintln(w) 2359 } 2360 } else { 2361 fmt.Fprintf(w, " *%s\n", strings.TrimRight(l, " \t")) 2362 } 2363 } else { 2364 fmt.Fprintf(w, "//%s\n", strings.TrimRight(l, " \t")) 2365 } 2366 } 2367 2368 // single-line comments always end in newline; multi-line comments only 2369 // end in newline for non-negative (e.g. non-inlined) indentation 2370 return !multiLine || indent >= 0 2371 } 2372 2373 func (p *Printer) indent(w io.Writer, indent int) { 2374 for i := 0; i < indent; i++ { 2375 fmt.Fprint(w, p.Indent) 2376 } 2377 } 2378 2379 func (p *Printer) maybeIndent(w io.Writer, indent int, requireIndent bool) { 2380 if indent < 0 && requireIndent { 2381 p.indent(w, -indent) 2382 } else { 2383 p.indent(w, indent) 2384 } 2385 } 2386 2387 type writer struct { 2388 io.Writer 2389 err error 2390 space bool 2391 newline bool 2392 } 2393 2394 func newWriter(w io.Writer) *writer { 2395 return &writer{Writer: w, newline: true} 2396 } 2397 2398 func (w *writer) Write(p []byte) (int, error) { 2399 if len(p) == 0 { 2400 return 0, nil 2401 } 2402 2403 w.newline = false 2404 2405 if w.space { 2406 // skip any trailing space if the following 2407 // character is semicolon, comma, or close bracket 2408 if p[0] != ';' && p[0] != ',' && p[0] != ']' { 2409 _, err := w.Writer.Write([]byte{' '}) 2410 if err != nil { 2411 w.err = err 2412 return 0, err 2413 } 2414 } 2415 w.space = false 2416 } 2417 2418 if p[len(p)-1] == ' ' { 2419 w.space = true 2420 p = p[:len(p)-1] 2421 } 2422 if len(p) > 0 && p[len(p)-1] == '\n' { 2423 w.newline = true 2424 } 2425 2426 num, err := w.Writer.Write(p) 2427 if err != nil { 2428 w.err = err 2429 } else if w.space { 2430 // pretend space was written 2431 num++ 2432 } 2433 return num, err 2434 }