github.com/bakjos/protoreflect@v1.9.2/desc/protoprint/print.go (about)

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