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