source.go raw

   1  // Copyright 2019 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  package protoreflect
   6  
   7  import (
   8  	"strconv"
   9  )
  10  
  11  // SourceLocations is a list of source locations.
  12  type SourceLocations interface {
  13  	// Len reports the number of source locations in the proto file.
  14  	Len() int
  15  	// Get returns the ith SourceLocation. It panics if out of bounds.
  16  	Get(int) SourceLocation
  17  
  18  	// ByPath returns the SourceLocation for the given path,
  19  	// returning the first location if multiple exist for the same path.
  20  	// If multiple locations exist for the same path,
  21  	// then SourceLocation.Next index can be used to identify the
  22  	// index of the next SourceLocation.
  23  	// If no location exists for this path, it returns the zero value.
  24  	ByPath(path SourcePath) SourceLocation
  25  
  26  	// ByDescriptor returns the SourceLocation for the given descriptor,
  27  	// returning the first location if multiple exist for the same path.
  28  	// If no location exists for this descriptor, it returns the zero value.
  29  	ByDescriptor(desc Descriptor) SourceLocation
  30  
  31  	doNotImplement
  32  }
  33  
  34  // SourceLocation describes a source location and
  35  // corresponds with the google.protobuf.SourceCodeInfo.Location message.
  36  type SourceLocation struct {
  37  	// Path is the path to the declaration from the root file descriptor.
  38  	// The contents of this slice must not be mutated.
  39  	Path SourcePath
  40  
  41  	// StartLine and StartColumn are the zero-indexed starting location
  42  	// in the source file for the declaration.
  43  	StartLine, StartColumn int
  44  	// EndLine and EndColumn are the zero-indexed ending location
  45  	// in the source file for the declaration.
  46  	// In the descriptor.proto, the end line may be omitted if it is identical
  47  	// to the start line. Here, it is always populated.
  48  	EndLine, EndColumn int
  49  
  50  	// LeadingDetachedComments are the leading detached comments
  51  	// for the declaration. The contents of this slice must not be mutated.
  52  	LeadingDetachedComments []string
  53  	// LeadingComments is the leading attached comment for the declaration.
  54  	LeadingComments string
  55  	// TrailingComments is the trailing attached comment for the declaration.
  56  	TrailingComments string
  57  
  58  	// Next is an index into SourceLocations for the next source location that
  59  	// has the same Path. It is zero if there is no next location.
  60  	Next int
  61  }
  62  
  63  // SourcePath identifies part of a file descriptor for a source location.
  64  // The SourcePath is a sequence of either field numbers or indexes into
  65  // a repeated field that form a path starting from the root file descriptor.
  66  //
  67  // See google.protobuf.SourceCodeInfo.Location.path.
  68  type SourcePath []int32
  69  
  70  // Equal reports whether p1 equals p2.
  71  func (p1 SourcePath) Equal(p2 SourcePath) bool {
  72  	if len(p1) != len(p2) {
  73  		return false
  74  	}
  75  	for i := range p1 {
  76  		if p1[i] != p2[i] {
  77  			return false
  78  		}
  79  	}
  80  	return true
  81  }
  82  
  83  // String formats the path in a humanly readable manner.
  84  // The output is guaranteed to be deterministic,
  85  // making it suitable for use as a key into a Go map.
  86  // It is not guaranteed to be stable as the exact output could change
  87  // in a future version of this module.
  88  //
  89  // Example output:
  90  //
  91  //	.message_type[6].nested_type[15].field[3]
  92  func (p SourcePath) String() string {
  93  	b := p.appendFileDescriptorProto(nil)
  94  	for _, i := range p {
  95  		b = append(b, '.')
  96  		b = strconv.AppendInt(b, int64(i), 10)
  97  	}
  98  	return string(b)
  99  }
 100  
 101  type appendFunc func(*SourcePath, []byte) []byte
 102  
 103  func (p *SourcePath) appendSingularField(b []byte, name string, f appendFunc) []byte {
 104  	if len(*p) == 0 {
 105  		return b
 106  	}
 107  	b = append(b, '.')
 108  	b = append(b, name...)
 109  	*p = (*p)[1:]
 110  	if f != nil {
 111  		b = f(p, b)
 112  	}
 113  	return b
 114  }
 115  
 116  func (p *SourcePath) appendRepeatedField(b []byte, name string, f appendFunc) []byte {
 117  	b = p.appendSingularField(b, name, nil)
 118  	if len(*p) == 0 || (*p)[0] < 0 {
 119  		return b
 120  	}
 121  	b = append(b, '[')
 122  	b = strconv.AppendUint(b, uint64((*p)[0]), 10)
 123  	b = append(b, ']')
 124  	*p = (*p)[1:]
 125  	if f != nil {
 126  		b = f(p, b)
 127  	}
 128  	return b
 129  }
 130