mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-03-25 16:43:37 +00:00
reflect/protoreflect: improve source information usability
Added API: SourceLocations.ByPath SourceLocations.ByDescriptor SourceLocation.Next SourcePath.String SourcePath.Equal We modify compiler/protogen to use SourceLocations.ByDescriptor. In retrospect, if this had existed during the development of protogen, we would not have exposed protogen.Location and related fields. Change-Id: I58f17e59f90b9ba16f0982c4b71c2542e4ff6e75 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/238000 Reviewed-by: Damien Neil <dneil@google.com>
This commit is contained in:
parent
1a290e9a0e
commit
42cc4c592f
@ -115,17 +115,14 @@ func GenerateFile(gen *protogen.Plugin, file *protogen.File) *protogen.Generated
|
|||||||
// genStandaloneComments prints all leading comments for a FileDescriptorProto
|
// genStandaloneComments prints all leading comments for a FileDescriptorProto
|
||||||
// location identified by the field number n.
|
// location identified by the field number n.
|
||||||
func genStandaloneComments(g *protogen.GeneratedFile, f *fileInfo, n int32) {
|
func genStandaloneComments(g *protogen.GeneratedFile, f *fileInfo, n int32) {
|
||||||
for _, loc := range f.Proto.GetSourceCodeInfo().GetLocation() {
|
loc := f.Desc.SourceLocations().ByPath(protoreflect.SourcePath{n})
|
||||||
if len(loc.Path) == 1 && loc.Path[0] == n {
|
for _, s := range loc.LeadingDetachedComments {
|
||||||
for _, s := range loc.GetLeadingDetachedComments() {
|
g.P(protogen.Comments(s))
|
||||||
g.P(protogen.Comments(s))
|
g.P()
|
||||||
g.P()
|
}
|
||||||
}
|
if s := loc.LeadingComments; s != "" {
|
||||||
if s := loc.GetLeadingComments(); s != "" {
|
g.P(protogen.Comments(s))
|
||||||
g.P(protogen.Comments(s))
|
g.P()
|
||||||
g.P()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@ package protogen
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
@ -482,7 +481,7 @@ type File struct {
|
|||||||
// of "dir/foo". Appending ".pb.go" produces an output file of "dir/foo.pb.go".
|
// of "dir/foo". Appending ".pb.go" produces an output file of "dir/foo.pb.go".
|
||||||
GeneratedFilenamePrefix string
|
GeneratedFilenamePrefix string
|
||||||
|
|
||||||
comments map[pathKey]CommentSet
|
location Location
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFile(gen *Plugin, p *descriptorpb.FileDescriptorProto, packageName GoPackageName, importPath GoImportPath) (*File, error) {
|
func newFile(gen *Plugin, p *descriptorpb.FileDescriptorProto, packageName GoPackageName, importPath GoImportPath) (*File, error) {
|
||||||
@ -498,7 +497,7 @@ func newFile(gen *Plugin, p *descriptorpb.FileDescriptorProto, packageName GoPac
|
|||||||
Proto: p,
|
Proto: p,
|
||||||
GoPackageName: packageName,
|
GoPackageName: packageName,
|
||||||
GoImportPath: importPath,
|
GoImportPath: importPath,
|
||||||
comments: make(map[pathKey]CommentSet),
|
location: Location{SourceFile: desc.Path()},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the prefix for generated Go files.
|
// Determine the prefix for generated Go files.
|
||||||
@ -526,19 +525,6 @@ func newFile(gen *Plugin, p *descriptorpb.FileDescriptorProto, packageName GoPac
|
|||||||
}
|
}
|
||||||
f.GeneratedFilenamePrefix = prefix
|
f.GeneratedFilenamePrefix = prefix
|
||||||
|
|
||||||
for _, loc := range p.GetSourceCodeInfo().GetLocation() {
|
|
||||||
// Descriptors declarations are guaranteed to have unique comment sets.
|
|
||||||
// Other locations may not be unique, but we don't use them.
|
|
||||||
var leadingDetached []Comments
|
|
||||||
for _, s := range loc.GetLeadingDetachedComments() {
|
|
||||||
leadingDetached = append(leadingDetached, Comments(s))
|
|
||||||
}
|
|
||||||
f.comments[newPathKey(loc.Path)] = CommentSet{
|
|
||||||
LeadingDetached: leadingDetached,
|
|
||||||
Leading: Comments(loc.GetLeadingComments()),
|
|
||||||
Trailing: Comments(loc.GetTrailingComments()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i, eds := 0, desc.Enums(); i < eds.Len(); i++ {
|
for i, eds := 0, desc.Enums(); i < eds.Len(); i++ {
|
||||||
f.Enums = append(f.Enums, newEnum(gen, f, nil, eds.Get(i)))
|
f.Enums = append(f.Enums, newEnum(gen, f, nil, eds.Get(i)))
|
||||||
}
|
}
|
||||||
@ -571,13 +557,6 @@ func newFile(gen *Plugin, p *descriptorpb.FileDescriptorProto, packageName GoPac
|
|||||||
return f, nil
|
return f, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *File) location(idxPath ...int32) Location {
|
|
||||||
return Location{
|
|
||||||
SourceFile: f.Desc.Path(),
|
|
||||||
Path: idxPath,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// goPackageOption interprets a file's go_package option.
|
// goPackageOption interprets a file's go_package option.
|
||||||
// If there is no go_package, it returns ("", "").
|
// If there is no go_package, it returns ("", "").
|
||||||
// If there's a simple name, it returns (pkg, "").
|
// If there's a simple name, it returns (pkg, "").
|
||||||
@ -625,15 +604,15 @@ type Enum struct {
|
|||||||
func newEnum(gen *Plugin, f *File, parent *Message, desc protoreflect.EnumDescriptor) *Enum {
|
func newEnum(gen *Plugin, f *File, parent *Message, desc protoreflect.EnumDescriptor) *Enum {
|
||||||
var loc Location
|
var loc Location
|
||||||
if parent != nil {
|
if parent != nil {
|
||||||
loc = parent.Location.appendPath(int32(genid.DescriptorProto_EnumType_field_number), int32(desc.Index()))
|
loc = parent.Location.appendPath(genid.DescriptorProto_EnumType_field_number, desc.Index())
|
||||||
} else {
|
} else {
|
||||||
loc = f.location(int32(genid.FileDescriptorProto_EnumType_field_number), int32(desc.Index()))
|
loc = f.location.appendPath(genid.FileDescriptorProto_EnumType_field_number, desc.Index())
|
||||||
}
|
}
|
||||||
enum := &Enum{
|
enum := &Enum{
|
||||||
Desc: desc,
|
Desc: desc,
|
||||||
GoIdent: newGoIdent(f, desc),
|
GoIdent: newGoIdent(f, desc),
|
||||||
Location: loc,
|
Location: loc,
|
||||||
Comments: f.comments[newPathKey(loc.Path)],
|
Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)),
|
||||||
}
|
}
|
||||||
gen.enumsByName[desc.FullName()] = enum
|
gen.enumsByName[desc.FullName()] = enum
|
||||||
for i, vds := 0, enum.Desc.Values(); i < vds.Len(); i++ {
|
for i, vds := 0, enum.Desc.Values(); i < vds.Len(); i++ {
|
||||||
@ -664,13 +643,13 @@ func newEnumValue(gen *Plugin, f *File, message *Message, enum *Enum, desc proto
|
|||||||
parentIdent = message.GoIdent
|
parentIdent = message.GoIdent
|
||||||
}
|
}
|
||||||
name := parentIdent.GoName + "_" + string(desc.Name())
|
name := parentIdent.GoName + "_" + string(desc.Name())
|
||||||
loc := enum.Location.appendPath(int32(genid.EnumDescriptorProto_Value_field_number), int32(desc.Index()))
|
loc := enum.Location.appendPath(genid.EnumDescriptorProto_Value_field_number, desc.Index())
|
||||||
return &EnumValue{
|
return &EnumValue{
|
||||||
Desc: desc,
|
Desc: desc,
|
||||||
GoIdent: f.GoImportPath.Ident(name),
|
GoIdent: f.GoImportPath.Ident(name),
|
||||||
Parent: enum,
|
Parent: enum,
|
||||||
Location: loc,
|
Location: loc,
|
||||||
Comments: f.comments[newPathKey(loc.Path)],
|
Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -694,15 +673,15 @@ type Message struct {
|
|||||||
func newMessage(gen *Plugin, f *File, parent *Message, desc protoreflect.MessageDescriptor) *Message {
|
func newMessage(gen *Plugin, f *File, parent *Message, desc protoreflect.MessageDescriptor) *Message {
|
||||||
var loc Location
|
var loc Location
|
||||||
if parent != nil {
|
if parent != nil {
|
||||||
loc = parent.Location.appendPath(int32(genid.DescriptorProto_NestedType_field_number), int32(desc.Index()))
|
loc = parent.Location.appendPath(genid.DescriptorProto_NestedType_field_number, desc.Index())
|
||||||
} else {
|
} else {
|
||||||
loc = f.location(int32(genid.FileDescriptorProto_MessageType_field_number), int32(desc.Index()))
|
loc = f.location.appendPath(genid.FileDescriptorProto_MessageType_field_number, desc.Index())
|
||||||
}
|
}
|
||||||
message := &Message{
|
message := &Message{
|
||||||
Desc: desc,
|
Desc: desc,
|
||||||
GoIdent: newGoIdent(f, desc),
|
GoIdent: newGoIdent(f, desc),
|
||||||
Location: loc,
|
Location: loc,
|
||||||
Comments: f.comments[newPathKey(loc.Path)],
|
Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)),
|
||||||
}
|
}
|
||||||
gen.messagesByName[desc.FullName()] = message
|
gen.messagesByName[desc.FullName()] = message
|
||||||
for i, eds := 0, desc.Enums(); i < eds.Len(); i++ {
|
for i, eds := 0, desc.Enums(); i < eds.Len(); i++ {
|
||||||
@ -852,11 +831,11 @@ func newField(gen *Plugin, f *File, message *Message, desc protoreflect.FieldDes
|
|||||||
var loc Location
|
var loc Location
|
||||||
switch {
|
switch {
|
||||||
case desc.IsExtension() && message == nil:
|
case desc.IsExtension() && message == nil:
|
||||||
loc = f.location(int32(genid.FileDescriptorProto_Extension_field_number), int32(desc.Index()))
|
loc = f.location.appendPath(genid.FileDescriptorProto_Extension_field_number, desc.Index())
|
||||||
case desc.IsExtension() && message != nil:
|
case desc.IsExtension() && message != nil:
|
||||||
loc = message.Location.appendPath(int32(genid.DescriptorProto_Extension_field_number), int32(desc.Index()))
|
loc = message.Location.appendPath(genid.DescriptorProto_Extension_field_number, desc.Index())
|
||||||
default:
|
default:
|
||||||
loc = message.Location.appendPath(int32(genid.DescriptorProto_Field_field_number), int32(desc.Index()))
|
loc = message.Location.appendPath(genid.DescriptorProto_Field_field_number, desc.Index())
|
||||||
}
|
}
|
||||||
camelCased := strs.GoCamelCase(string(desc.Name()))
|
camelCased := strs.GoCamelCase(string(desc.Name()))
|
||||||
var parentPrefix string
|
var parentPrefix string
|
||||||
@ -872,7 +851,7 @@ func newField(gen *Plugin, f *File, message *Message, desc protoreflect.FieldDes
|
|||||||
},
|
},
|
||||||
Parent: message,
|
Parent: message,
|
||||||
Location: loc,
|
Location: loc,
|
||||||
Comments: f.comments[newPathKey(loc.Path)],
|
Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)),
|
||||||
}
|
}
|
||||||
return field
|
return field
|
||||||
}
|
}
|
||||||
@ -927,7 +906,7 @@ type Oneof struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newOneof(gen *Plugin, f *File, message *Message, desc protoreflect.OneofDescriptor) *Oneof {
|
func newOneof(gen *Plugin, f *File, message *Message, desc protoreflect.OneofDescriptor) *Oneof {
|
||||||
loc := message.Location.appendPath(int32(genid.DescriptorProto_OneofDecl_field_number), int32(desc.Index()))
|
loc := message.Location.appendPath(genid.DescriptorProto_OneofDecl_field_number, desc.Index())
|
||||||
camelCased := strs.GoCamelCase(string(desc.Name()))
|
camelCased := strs.GoCamelCase(string(desc.Name()))
|
||||||
parentPrefix := message.GoIdent.GoName + "_"
|
parentPrefix := message.GoIdent.GoName + "_"
|
||||||
return &Oneof{
|
return &Oneof{
|
||||||
@ -939,7 +918,7 @@ func newOneof(gen *Plugin, f *File, message *Message, desc protoreflect.OneofDes
|
|||||||
GoName: parentPrefix + camelCased,
|
GoName: parentPrefix + camelCased,
|
||||||
},
|
},
|
||||||
Location: loc,
|
Location: loc,
|
||||||
Comments: f.comments[newPathKey(loc.Path)],
|
Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -959,12 +938,12 @@ type Service struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newService(gen *Plugin, f *File, desc protoreflect.ServiceDescriptor) *Service {
|
func newService(gen *Plugin, f *File, desc protoreflect.ServiceDescriptor) *Service {
|
||||||
loc := f.location(int32(genid.FileDescriptorProto_Service_field_number), int32(desc.Index()))
|
loc := f.location.appendPath(genid.FileDescriptorProto_Service_field_number, desc.Index())
|
||||||
service := &Service{
|
service := &Service{
|
||||||
Desc: desc,
|
Desc: desc,
|
||||||
GoName: strs.GoCamelCase(string(desc.Name())),
|
GoName: strs.GoCamelCase(string(desc.Name())),
|
||||||
Location: loc,
|
Location: loc,
|
||||||
Comments: f.comments[newPathKey(loc.Path)],
|
Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)),
|
||||||
}
|
}
|
||||||
for i, mds := 0, desc.Methods(); i < mds.Len(); i++ {
|
for i, mds := 0, desc.Methods(); i < mds.Len(); i++ {
|
||||||
service.Methods = append(service.Methods, newMethod(gen, f, service, mds.Get(i)))
|
service.Methods = append(service.Methods, newMethod(gen, f, service, mds.Get(i)))
|
||||||
@ -988,13 +967,13 @@ type Method struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newMethod(gen *Plugin, f *File, service *Service, desc protoreflect.MethodDescriptor) *Method {
|
func newMethod(gen *Plugin, f *File, service *Service, desc protoreflect.MethodDescriptor) *Method {
|
||||||
loc := service.Location.appendPath(int32(genid.ServiceDescriptorProto_Method_field_number), int32(desc.Index()))
|
loc := service.Location.appendPath(genid.ServiceDescriptorProto_Method_field_number, desc.Index())
|
||||||
method := &Method{
|
method := &Method{
|
||||||
Desc: desc,
|
Desc: desc,
|
||||||
GoName: strs.GoCamelCase(string(desc.Name())),
|
GoName: strs.GoCamelCase(string(desc.Name())),
|
||||||
Parent: service,
|
Parent: service,
|
||||||
Location: loc,
|
Location: loc,
|
||||||
Comments: f.comments[newPathKey(loc.Path)],
|
Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)),
|
||||||
}
|
}
|
||||||
return method
|
return method
|
||||||
}
|
}
|
||||||
@ -1359,28 +1338,10 @@ type Location struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// appendPath add elements to a Location's path, returning a new Location.
|
// appendPath add elements to a Location's path, returning a new Location.
|
||||||
func (loc Location) appendPath(a ...int32) Location {
|
func (loc Location) appendPath(num protoreflect.FieldNumber, idx int) Location {
|
||||||
var n protoreflect.SourcePath
|
loc.Path = append(protoreflect.SourcePath(nil), loc.Path...) // make copy
|
||||||
n = append(n, loc.Path...)
|
loc.Path = append(loc.Path, int32(num), int32(idx))
|
||||||
n = append(n, a...)
|
return loc
|
||||||
return Location{
|
|
||||||
SourceFile: loc.SourceFile,
|
|
||||||
Path: n,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// A pathKey is a representation of a location path suitable for use as a map key.
|
|
||||||
type pathKey struct {
|
|
||||||
s string
|
|
||||||
}
|
|
||||||
|
|
||||||
// newPathKey converts a location path to a pathKey.
|
|
||||||
func newPathKey(idxPath []int32) pathKey {
|
|
||||||
buf := make([]byte, 4*len(idxPath))
|
|
||||||
for i, x := range idxPath {
|
|
||||||
binary.LittleEndian.PutUint32(buf[i*4:], uint32(x))
|
|
||||||
}
|
|
||||||
return pathKey{string(buf)}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommentSet is a set of leading and trailing comments associated
|
// CommentSet is a set of leading and trailing comments associated
|
||||||
@ -1391,6 +1352,18 @@ type CommentSet struct {
|
|||||||
Trailing Comments
|
Trailing Comments
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeCommentSet(loc protoreflect.SourceLocation) CommentSet {
|
||||||
|
var leadingDetached []Comments
|
||||||
|
for _, s := range loc.LeadingDetachedComments {
|
||||||
|
leadingDetached = append(leadingDetached, Comments(s))
|
||||||
|
}
|
||||||
|
return CommentSet{
|
||||||
|
LeadingDetached: leadingDetached,
|
||||||
|
Leading: Comments(loc.LeadingComments),
|
||||||
|
Trailing: Comments(loc.TrailingComments),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Comments is a comments string as provided by protoc.
|
// Comments is a comments string as provided by protoc.
|
||||||
type Comments string
|
type Comments string
|
||||||
|
|
||||||
|
@ -93,6 +93,7 @@ func init() {
|
|||||||
gengo.GenerateVersionMarkers = false
|
gengo.GenerateVersionMarkers = false
|
||||||
gengo.GenerateFile(gen, file)
|
gengo.GenerateFile(gen, file)
|
||||||
generateIdentifiers(gen, file)
|
generateIdentifiers(gen, file)
|
||||||
|
generateSouceContextStringer(gen, file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gen.SupportedFeatures = gengo.SupportedFeatures
|
gen.SupportedFeatures = gengo.SupportedFeatures
|
||||||
@ -361,6 +362,66 @@ func generateIdentifiers(gen *protogen.Plugin, file *protogen.File) {
|
|||||||
processMessages(file.Messages)
|
processMessages(file.Messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generateSouceContextStringer generates the implementation for the
|
||||||
|
// protoreflect.SourcePath.String method by using information present
|
||||||
|
// in the descriptor.proto.
|
||||||
|
func generateSouceContextStringer(gen *protogen.Plugin, file *protogen.File) {
|
||||||
|
if file.Desc.Path() != "google/protobuf/descriptor.proto" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
importPath := modulePath + "/reflect/protoreflect"
|
||||||
|
g := gen.NewGeneratedFile(importPath+"/source_gen.go", protogen.GoImportPath(importPath))
|
||||||
|
for _, s := range generatedPreamble {
|
||||||
|
g.P(s)
|
||||||
|
}
|
||||||
|
g.P("package ", path.Base(importPath))
|
||||||
|
g.P()
|
||||||
|
|
||||||
|
var messages []*protogen.Message
|
||||||
|
for _, message := range file.Messages {
|
||||||
|
if message.Desc.Name() == "FileDescriptorProto" {
|
||||||
|
messages = append(messages, message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seen := make(map[*protogen.Message]bool)
|
||||||
|
|
||||||
|
for len(messages) > 0 {
|
||||||
|
m := messages[0]
|
||||||
|
messages = messages[1:]
|
||||||
|
if seen[m] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[m] = true
|
||||||
|
|
||||||
|
g.P("func (p *SourcePath) append", m.GoIdent.GoName, "(b []byte) []byte {")
|
||||||
|
g.P("if len(*p) == 0 { return b }")
|
||||||
|
g.P("switch (*p)[0] {")
|
||||||
|
for _, f := range m.Fields {
|
||||||
|
g.P("case ", f.Desc.Number(), ":")
|
||||||
|
var cardinality string
|
||||||
|
switch {
|
||||||
|
case f.Desc.IsMap():
|
||||||
|
panic("maps are not supported")
|
||||||
|
case f.Desc.IsList():
|
||||||
|
cardinality = "Repeated"
|
||||||
|
default:
|
||||||
|
cardinality = "Singular"
|
||||||
|
}
|
||||||
|
nextAppender := "nil"
|
||||||
|
if f.Message != nil {
|
||||||
|
nextAppender = "(*SourcePath).append" + f.Message.GoIdent.GoName
|
||||||
|
messages = append(messages, f.Message)
|
||||||
|
}
|
||||||
|
g.P("b = p.append", cardinality, "Field(b, ", strconv.Quote(string(f.Desc.Name())), ", ", nextAppender, ")")
|
||||||
|
}
|
||||||
|
g.P("}")
|
||||||
|
g.P("return b")
|
||||||
|
g.P("}")
|
||||||
|
g.P()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func syncOutput(dstDir, srcDir string) {
|
func syncOutput(dstDir, srcDir string) {
|
||||||
filepath.Walk(srcDir, func(srcPath string, _ os.FileInfo, _ error) error {
|
filepath.Walk(srcDir, func(srcPath string, _ os.FileInfo, _ error) error {
|
||||||
if !strings.HasSuffix(srcPath, ".go") && !strings.HasSuffix(srcPath, ".meta") {
|
if !strings.HasSuffix(srcPath, ".go") && !strings.HasSuffix(srcPath, ".meta") {
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// Package filedesc provides functionality for constructing descriptors.
|
// Package filedesc provides functionality for constructing descriptors.
|
||||||
|
//
|
||||||
|
// The types in this package implement interfaces in the protoreflect package
|
||||||
|
// related to protobuf descripriptors.
|
||||||
package filedesc
|
package filedesc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -6,9 +6,12 @@ package filedesc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"google.golang.org/protobuf/internal/genid"
|
||||||
|
|
||||||
"google.golang.org/protobuf/encoding/protowire"
|
"google.golang.org/protobuf/encoding/protowire"
|
||||||
"google.golang.org/protobuf/internal/descfmt"
|
"google.golang.org/protobuf/internal/descfmt"
|
||||||
"google.golang.org/protobuf/internal/errors"
|
"google.golang.org/protobuf/internal/errors"
|
||||||
@ -278,9 +281,170 @@ func (p *OneofFields) lazyInit() *OneofFields {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SourceLocations struct {
|
type SourceLocations struct {
|
||||||
|
// List is a list of SourceLocations.
|
||||||
|
// The SourceLocation.Next field does not need to be populated
|
||||||
|
// as it will be lazily populated upon first need.
|
||||||
List []pref.SourceLocation
|
List []pref.SourceLocation
|
||||||
|
|
||||||
|
// File is the parent file descriptor that these locations are relative to.
|
||||||
|
// If non-nil, ByDescriptor verifies that the provided descriptor
|
||||||
|
// is a child of this file descriptor.
|
||||||
|
File pref.FileDescriptor
|
||||||
|
|
||||||
|
once sync.Once
|
||||||
|
byPath map[pathKey]int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *SourceLocations) Len() int { return len(p.List) }
|
func (p *SourceLocations) Len() int { return len(p.List) }
|
||||||
func (p *SourceLocations) Get(i int) pref.SourceLocation { return p.List[i] }
|
func (p *SourceLocations) Get(i int) pref.SourceLocation { return p.lazyInit().List[i] }
|
||||||
|
func (p *SourceLocations) byKey(k pathKey) pref.SourceLocation {
|
||||||
|
if i, ok := p.lazyInit().byPath[k]; ok {
|
||||||
|
return p.List[i]
|
||||||
|
}
|
||||||
|
return pref.SourceLocation{}
|
||||||
|
}
|
||||||
|
func (p *SourceLocations) ByPath(path pref.SourcePath) pref.SourceLocation {
|
||||||
|
return p.byKey(newPathKey(path))
|
||||||
|
}
|
||||||
|
func (p *SourceLocations) ByDescriptor(desc pref.Descriptor) pref.SourceLocation {
|
||||||
|
if p.File != nil && desc != nil && p.File != desc.ParentFile() {
|
||||||
|
return pref.SourceLocation{} // mismatching parent files
|
||||||
|
}
|
||||||
|
var pathArr [16]int32
|
||||||
|
path := pathArr[:0]
|
||||||
|
for {
|
||||||
|
switch desc.(type) {
|
||||||
|
case pref.FileDescriptor:
|
||||||
|
// Reverse the path since it was constructed in reverse.
|
||||||
|
for i, j := 0, len(path)-1; i < j; i, j = i+1, j-1 {
|
||||||
|
path[i], path[j] = path[j], path[i]
|
||||||
|
}
|
||||||
|
return p.byKey(newPathKey(path))
|
||||||
|
case pref.MessageDescriptor:
|
||||||
|
path = append(path, int32(desc.Index()))
|
||||||
|
desc = desc.Parent()
|
||||||
|
switch desc.(type) {
|
||||||
|
case pref.FileDescriptor:
|
||||||
|
path = append(path, int32(genid.FileDescriptorProto_MessageType_field_number))
|
||||||
|
case pref.MessageDescriptor:
|
||||||
|
path = append(path, int32(genid.DescriptorProto_NestedType_field_number))
|
||||||
|
default:
|
||||||
|
return pref.SourceLocation{}
|
||||||
|
}
|
||||||
|
case pref.FieldDescriptor:
|
||||||
|
isExtension := desc.(pref.FieldDescriptor).IsExtension()
|
||||||
|
path = append(path, int32(desc.Index()))
|
||||||
|
desc = desc.Parent()
|
||||||
|
if isExtension {
|
||||||
|
switch desc.(type) {
|
||||||
|
case pref.FileDescriptor:
|
||||||
|
path = append(path, int32(genid.FileDescriptorProto_Extension_field_number))
|
||||||
|
case pref.MessageDescriptor:
|
||||||
|
path = append(path, int32(genid.DescriptorProto_Extension_field_number))
|
||||||
|
default:
|
||||||
|
return pref.SourceLocation{}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch desc.(type) {
|
||||||
|
case pref.MessageDescriptor:
|
||||||
|
path = append(path, int32(genid.DescriptorProto_Field_field_number))
|
||||||
|
default:
|
||||||
|
return pref.SourceLocation{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case pref.OneofDescriptor:
|
||||||
|
path = append(path, int32(desc.Index()))
|
||||||
|
desc = desc.Parent()
|
||||||
|
switch desc.(type) {
|
||||||
|
case pref.MessageDescriptor:
|
||||||
|
path = append(path, int32(genid.DescriptorProto_OneofDecl_field_number))
|
||||||
|
default:
|
||||||
|
return pref.SourceLocation{}
|
||||||
|
}
|
||||||
|
case pref.EnumDescriptor:
|
||||||
|
path = append(path, int32(desc.Index()))
|
||||||
|
desc = desc.Parent()
|
||||||
|
switch desc.(type) {
|
||||||
|
case pref.FileDescriptor:
|
||||||
|
path = append(path, int32(genid.FileDescriptorProto_EnumType_field_number))
|
||||||
|
case pref.MessageDescriptor:
|
||||||
|
path = append(path, int32(genid.DescriptorProto_EnumType_field_number))
|
||||||
|
default:
|
||||||
|
return pref.SourceLocation{}
|
||||||
|
}
|
||||||
|
case pref.EnumValueDescriptor:
|
||||||
|
path = append(path, int32(desc.Index()))
|
||||||
|
desc = desc.Parent()
|
||||||
|
switch desc.(type) {
|
||||||
|
case pref.EnumDescriptor:
|
||||||
|
path = append(path, int32(genid.EnumDescriptorProto_Value_field_number))
|
||||||
|
default:
|
||||||
|
return pref.SourceLocation{}
|
||||||
|
}
|
||||||
|
case pref.ServiceDescriptor:
|
||||||
|
path = append(path, int32(desc.Index()))
|
||||||
|
desc = desc.Parent()
|
||||||
|
switch desc.(type) {
|
||||||
|
case pref.FileDescriptor:
|
||||||
|
path = append(path, int32(genid.FileDescriptorProto_Service_field_number))
|
||||||
|
default:
|
||||||
|
return pref.SourceLocation{}
|
||||||
|
}
|
||||||
|
case pref.MethodDescriptor:
|
||||||
|
path = append(path, int32(desc.Index()))
|
||||||
|
desc = desc.Parent()
|
||||||
|
switch desc.(type) {
|
||||||
|
case pref.ServiceDescriptor:
|
||||||
|
path = append(path, int32(genid.ServiceDescriptorProto_Method_field_number))
|
||||||
|
default:
|
||||||
|
return pref.SourceLocation{}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return pref.SourceLocation{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (p *SourceLocations) lazyInit() *SourceLocations {
|
||||||
|
p.once.Do(func() {
|
||||||
|
if len(p.List) > 0 {
|
||||||
|
// Collect all the indexes for a given path.
|
||||||
|
pathIdxs := make(map[pathKey][]int, len(p.List))
|
||||||
|
for i, l := range p.List {
|
||||||
|
k := newPathKey(l.Path)
|
||||||
|
pathIdxs[k] = append(pathIdxs[k], i)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the next index for all locations.
|
||||||
|
p.byPath = make(map[pathKey]int, len(p.List))
|
||||||
|
for k, idxs := range pathIdxs {
|
||||||
|
for i := 0; i < len(idxs)-1; i++ {
|
||||||
|
p.List[idxs[i]].Next = idxs[i+1]
|
||||||
|
}
|
||||||
|
p.List[idxs[len(idxs)-1]].Next = 0
|
||||||
|
p.byPath[k] = idxs[0] // record the first location for this path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return p
|
||||||
|
}
|
||||||
func (p *SourceLocations) ProtoInternal(pragma.DoNotImplement) {}
|
func (p *SourceLocations) ProtoInternal(pragma.DoNotImplement) {}
|
||||||
|
|
||||||
|
// pathKey is a comparable representation of protoreflect.SourcePath.
|
||||||
|
type pathKey struct {
|
||||||
|
arr [16]uint8 // first n-1 path segments; last element is the length
|
||||||
|
str string // used if the path does not fit in arr
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPathKey(p pref.SourcePath) (k pathKey) {
|
||||||
|
if len(p) < len(k.arr) {
|
||||||
|
for i, ps := range p {
|
||||||
|
if ps < 0 || math.MaxUint8 <= ps {
|
||||||
|
return pathKey{str: p.String()}
|
||||||
|
}
|
||||||
|
k.arr[i] = uint8(ps)
|
||||||
|
}
|
||||||
|
k.arr[len(k.arr)-1] = uint8(len(p))
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
return pathKey{str: p.String()}
|
||||||
|
}
|
||||||
|
@ -144,6 +144,7 @@ func (o FileOptions) New(fd *descriptorpb.FileDescriptorProto, r Resolver) (prot
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle source locations.
|
// Handle source locations.
|
||||||
|
f.L2.Locations.File = f
|
||||||
for _, loc := range fd.GetSourceCodeInfo().GetLocation() {
|
for _, loc := range fd.GetSourceCodeInfo().GetLocation() {
|
||||||
var l protoreflect.SourceLocation
|
var l protoreflect.SourceLocation
|
||||||
// TODO: Validate that the path points to an actual declaration?
|
// TODO: Validate that the path points to an actual declaration?
|
||||||
|
@ -994,3 +994,241 @@ func TestNewFilesImportCycle(t *testing.T) {
|
|||||||
t.Fatal("NewFiles with import cycle: success, want error")
|
t.Fatal("NewFiles with import cycle: success, want error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSourceLocations(t *testing.T) {
|
||||||
|
fd := mustParseFile(`
|
||||||
|
name: "comments.proto"
|
||||||
|
message_type: [{
|
||||||
|
name: "Message1"
|
||||||
|
field: [
|
||||||
|
{name:"field1" number:1 label:LABEL_OPTIONAL type:TYPE_STRING},
|
||||||
|
{name:"field2" number:2 label:LABEL_OPTIONAL type:TYPE_STRING},
|
||||||
|
{name:"field3" number:3 label:LABEL_OPTIONAL type:TYPE_STRING oneof_index:0},
|
||||||
|
{name:"field4" number:4 label:LABEL_OPTIONAL type:TYPE_STRING oneof_index:0},
|
||||||
|
{name:"field5" number:5 label:LABEL_OPTIONAL type:TYPE_STRING oneof_index:1},
|
||||||
|
{name:"field6" number:6 label:LABEL_OPTIONAL type:TYPE_STRING oneof_index:1}
|
||||||
|
]
|
||||||
|
extension: [
|
||||||
|
{name:"extension1" number:100 label:LABEL_OPTIONAL type:TYPE_STRING extendee:".Message1"},
|
||||||
|
{name:"extension2" number:101 label:LABEL_OPTIONAL type:TYPE_STRING extendee:".Message1"}
|
||||||
|
]
|
||||||
|
nested_type: [{name:"Message1"}, {name:"Message2"}]
|
||||||
|
extension_range: {start:100 end:536870912}
|
||||||
|
oneof_decl: [{name:"oneof1"}, {name:"oneof2"}]
|
||||||
|
}, {
|
||||||
|
name: "Message2"
|
||||||
|
enum_type: {
|
||||||
|
name: "Enum1"
|
||||||
|
value: [
|
||||||
|
{name: "FOO", number: 0},
|
||||||
|
{name: "BAR", number: 1}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
enum_type: {
|
||||||
|
name: "Enum1"
|
||||||
|
value: [
|
||||||
|
{name: "FOO", number: 0},
|
||||||
|
{name: "BAR", number: 1}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
service: {
|
||||||
|
name: "Service1"
|
||||||
|
method: [
|
||||||
|
{name:"Method1" input_type:".Message1" output_type:".Message1"},
|
||||||
|
{name:"Method2" input_type:".Message2" output_type:".Message2"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
extension: [
|
||||||
|
{name:"extension1" number:102 label:LABEL_OPTIONAL type:TYPE_STRING extendee:".Message1"},
|
||||||
|
{name:"extension2" number:103 label:LABEL_OPTIONAL type:TYPE_STRING extendee:".Message1"}
|
||||||
|
]
|
||||||
|
source_code_info: {
|
||||||
|
location: [
|
||||||
|
{span:[0,0,69,1]},
|
||||||
|
{path:[12] span:[0,0,18]},
|
||||||
|
{path:[5,0] span:[3,0,8,1] leading_comments:" Enum1\r\n"},
|
||||||
|
{path:[5,0,1] span:[3,5,10]},
|
||||||
|
{path:[5,0,2,0] span:[5,2,10] leading_comments:" FOO\r\n"},
|
||||||
|
{path:[5,0,2,0,1] span:[5,2,5]},
|
||||||
|
{path:[5,0,2,0,2] span:[5,8,9]},
|
||||||
|
{path:[5,0,2,1] span:[7,2,10] leading_comments:" BAR\r\n"},
|
||||||
|
{path:[5,0,2,1,1] span:[7,2,5]},
|
||||||
|
{path:[5,0,2,1,2] span:[7,8,9]},
|
||||||
|
{path:[4,0] span:[11,0,43,1] leading_comments:" Message1\r\n"},
|
||||||
|
{path:[4,0,1] span:[11,8,16]},
|
||||||
|
{path:[4,0,3,0] span:[13,2,21] leading_comments:" Message1.Message1\r\n"},
|
||||||
|
{path:[4,0,3,0,1] span:[13,10,18]},
|
||||||
|
{path:[4,0,3,1] span:[15,2,21] leading_comments:" Message1.Message2\r\n"},
|
||||||
|
{path:[4,0,3,1,1] span:[15,10,18]},
|
||||||
|
{path:[4,0,2,0] span:[18,2,29] leading_comments:" Message1.field1\r\n"},
|
||||||
|
{path:[4,0,2,0,4] span:[18,2,10]},
|
||||||
|
{path:[4,0,2,0,5] span:[18,11,17]},
|
||||||
|
{path:[4,0,2,0,1] span:[18,18,24]},
|
||||||
|
{path:[4,0,2,0,3] span:[18,27,28]},
|
||||||
|
{path:[4,0,2,1] span:[20,2,29] leading_comments:" Message1.field2\r\n"},
|
||||||
|
{path:[4,0,2,1,4] span:[20,2,10]},
|
||||||
|
{path:[4,0,2,1,5] span:[20,11,17]},
|
||||||
|
{path:[4,0,2,1,1] span:[20,18,24]},
|
||||||
|
{path:[4,0,2,1,3] span:[20,27,28]},
|
||||||
|
{path:[4,0,8,0] span:[22,2,27,3] leading_comments:" Message1.oneof1\r\n"},
|
||||||
|
{path:[4,0,8,0,1] span:[22,8,14]},
|
||||||
|
{path:[4,0,2,2] span:[24,4,22] leading_comments:" Message1.field3\r\n"},
|
||||||
|
{path:[4,0,2,2,5] span:[24,4,10]},
|
||||||
|
{path:[4,0,2,2,1] span:[24,11,17]},
|
||||||
|
{path:[4,0,2,2,3] span:[24,20,21]},
|
||||||
|
{path:[4,0,2,3] span:[26,4,22] leading_comments:" Message1.field4\r\n"},
|
||||||
|
{path:[4,0,2,3,5] span:[26,4,10]},
|
||||||
|
{path:[4,0,2,3,1] span:[26,11,17]},
|
||||||
|
{path:[4,0,2,3,3] span:[26,20,21]},
|
||||||
|
{path:[4,0,8,1] span:[29,2,34,3] leading_comments:" Message1.oneof2\r\n"},
|
||||||
|
{path:[4,0,8,1,1] span:[29,8,14]},
|
||||||
|
{path:[4,0,2,4] span:[31,4,22] leading_comments:" Message1.field5\r\n"},
|
||||||
|
{path:[4,0,2,4,5] span:[31,4,10]},
|
||||||
|
{path:[4,0,2,4,1] span:[31,11,17]},
|
||||||
|
{path:[4,0,2,4,3] span:[31,20,21]},
|
||||||
|
{path:[4,0,2,5] span:[33,4,22] leading_comments:" Message1.field6\r\n"},
|
||||||
|
{path:[4,0,2,5,5] span:[33,4,10]},
|
||||||
|
{path:[4,0,2,5,1] span:[33,11,17]},
|
||||||
|
{path:[4,0,2,5,3] span:[33,20,21]},
|
||||||
|
{path:[4,0,5] span:[36,2,24]},
|
||||||
|
{path:[4,0,5,0] span:[36,13,23]},
|
||||||
|
{path:[4,0,5,0,1] span:[36,13,16]},
|
||||||
|
{path:[4,0,5,0,2] span:[36,20,23]},
|
||||||
|
{path:[4,0,6] span:[37,2,42,3]},
|
||||||
|
{path:[4,0,6,0] span:[39,4,37] leading_comments:" Message1.extension1\r\n"},
|
||||||
|
{path:[4,0,6,0,2] span:[37,9,18]},
|
||||||
|
{path:[4,0,6,0,4] span:[39,4,12]},
|
||||||
|
{path:[4,0,6,0,5] span:[39,13,19]},
|
||||||
|
{path:[4,0,6,0,1] span:[39,20,30]},
|
||||||
|
{path:[4,0,6,0,3] span:[39,33,36]},
|
||||||
|
{path:[4,0,6,1] span:[41,4,37] leading_comments:" Message1.extension2\r\n"},
|
||||||
|
{path:[4,0,6,1,2] span:[37,9,18]},
|
||||||
|
{path:[4,0,6,1,4] span:[41,4,12]},
|
||||||
|
{path:[4,0,6,1,5] span:[41,13,19]},
|
||||||
|
{path:[4,0,6,1,1] span:[41,20,30]},
|
||||||
|
{path:[4,0,6,1,3] span:[41,33,36]},
|
||||||
|
{path:[7] span:[45,0,50,1]},
|
||||||
|
{path:[7,0] span:[47,2,35] leading_comments:" extension1\r\n"},
|
||||||
|
{path:[7,0,2] span:[45,7,15]},
|
||||||
|
{path:[7,0,4] span:[47,2,10]},
|
||||||
|
{path:[7,0,5] span:[47,11,17]},
|
||||||
|
{path:[7,0,1] span:[47,18,28]},
|
||||||
|
{path:[7,0,3] span:[47,31,34]},
|
||||||
|
{path:[7,1] span:[49,2,35] leading_comments:" extension2\r\n"},
|
||||||
|
{path:[7,1,2] span:[45,7,15]},
|
||||||
|
{path:[7,1,4] span:[49,2,10]},
|
||||||
|
{path:[7,1,5] span:[49,11,17]},
|
||||||
|
{path:[7,1,1] span:[49,18,28]},
|
||||||
|
{path:[7,1,3] span:[49,31,34]},
|
||||||
|
{path:[4,1] span:[53,0,61,1] leading_comments:" Message2\r\n"},
|
||||||
|
{path:[4,1,1] span:[53,8,16]},
|
||||||
|
{path:[4,1,4,0] span:[55,2,60,3] leading_comments:" Message2.Enum1\r\n"},
|
||||||
|
{path:[4,1,4,0,1] span:[55,7,12]},
|
||||||
|
{path:[4,1,4,0,2,0] span:[57,4,12] leading_comments:" Message2.FOO\r\n"},
|
||||||
|
{path:[4,1,4,0,2,0,1] span:[57,4,7]},
|
||||||
|
{path:[4,1,4,0,2,0,2] span:[57,10,11]},
|
||||||
|
{path:[4,1,4,0,2,1] span:[59,4,12] leading_comments:" Message2.BAR\r\n"},
|
||||||
|
{path:[4,1,4,0,2,1,1] span:[59,4,7]},
|
||||||
|
{path:[4,1,4,0,2,1,2] span:[59,10,11]},
|
||||||
|
{path:[6,0] span:[64,0,69,1] leading_comments:" Service1\r\n"},
|
||||||
|
{path:[6,0,1] span:[64,8,16]},
|
||||||
|
{path:[6,0,2,0] span:[66,2,43] leading_comments:" Service1.Method1\r\n"},
|
||||||
|
{path:[6,0,2,0,1] span:[66,6,13]},
|
||||||
|
{path:[6,0,2,0,2] span:[66,14,22]},
|
||||||
|
{path:[6,0,2,0,3] span:[66,33,41]},
|
||||||
|
{path:[6,0,2,1] span:[68,2,43] leading_comments:" Service1.Method2\r\n"},
|
||||||
|
{path:[6,0,2,1,1] span:[68,6,13]},
|
||||||
|
{path:[6,0,2,1,2] span:[68,14,22]},
|
||||||
|
{path:[6,0,2,1,3] span:[68,33,41]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
fileDesc, err := NewFile(fd, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("NewFile error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var walkDescs func(protoreflect.Descriptor, func(protoreflect.Descriptor))
|
||||||
|
walkDescs = func(d protoreflect.Descriptor, f func(protoreflect.Descriptor)) {
|
||||||
|
f(d)
|
||||||
|
if d, ok := d.(interface {
|
||||||
|
Enums() protoreflect.EnumDescriptors
|
||||||
|
}); ok {
|
||||||
|
eds := d.Enums()
|
||||||
|
for i := 0; i < eds.Len(); i++ {
|
||||||
|
walkDescs(eds.Get(i), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if d, ok := d.(interface {
|
||||||
|
Values() protoreflect.EnumValueDescriptors
|
||||||
|
}); ok {
|
||||||
|
vds := d.Values()
|
||||||
|
for i := 0; i < vds.Len(); i++ {
|
||||||
|
walkDescs(vds.Get(i), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if d, ok := d.(interface {
|
||||||
|
Messages() protoreflect.MessageDescriptors
|
||||||
|
}); ok {
|
||||||
|
mds := d.Messages()
|
||||||
|
for i := 0; i < mds.Len(); i++ {
|
||||||
|
walkDescs(mds.Get(i), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if d, ok := d.(interface {
|
||||||
|
Fields() protoreflect.FieldDescriptors
|
||||||
|
}); ok {
|
||||||
|
fds := d.Fields()
|
||||||
|
for i := 0; i < fds.Len(); i++ {
|
||||||
|
walkDescs(fds.Get(i), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if d, ok := d.(interface {
|
||||||
|
Oneofs() protoreflect.OneofDescriptors
|
||||||
|
}); ok {
|
||||||
|
ods := d.Oneofs()
|
||||||
|
for i := 0; i < ods.Len(); i++ {
|
||||||
|
walkDescs(ods.Get(i), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if d, ok := d.(interface {
|
||||||
|
Extensions() protoreflect.ExtensionDescriptors
|
||||||
|
}); ok {
|
||||||
|
xds := d.Extensions()
|
||||||
|
for i := 0; i < xds.Len(); i++ {
|
||||||
|
walkDescs(xds.Get(i), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if d, ok := d.(interface {
|
||||||
|
Services() protoreflect.ServiceDescriptors
|
||||||
|
}); ok {
|
||||||
|
sds := d.Services()
|
||||||
|
for i := 0; i < sds.Len(); i++ {
|
||||||
|
walkDescs(sds.Get(i), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if d, ok := d.(interface {
|
||||||
|
Methods() protoreflect.MethodDescriptors
|
||||||
|
}); ok {
|
||||||
|
mds := d.Methods()
|
||||||
|
for i := 0; i < mds.Len(); i++ {
|
||||||
|
walkDescs(mds.Get(i), f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var numDescs int
|
||||||
|
walkDescs(fileDesc, func(d protoreflect.Descriptor) {
|
||||||
|
// The comment for every descriptor should be the full name itself.
|
||||||
|
got := strings.TrimSpace(fileDesc.SourceLocations().ByDescriptor(d).LeadingComments)
|
||||||
|
want := string(d.FullName())
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("comment mismatch: got %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
numDescs++
|
||||||
|
})
|
||||||
|
if numDescs != 30 {
|
||||||
|
t.Errorf("visited %d descriptor, expected 30", numDescs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -4,6 +4,10 @@
|
|||||||
|
|
||||||
package protoreflect
|
package protoreflect
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
// SourceLocations is a list of source locations.
|
// SourceLocations is a list of source locations.
|
||||||
type SourceLocations interface {
|
type SourceLocations interface {
|
||||||
// Len reports the number of source locations in the proto file.
|
// Len reports the number of source locations in the proto file.
|
||||||
@ -11,9 +15,20 @@ type SourceLocations interface {
|
|||||||
// Get returns the ith SourceLocation. It panics if out of bounds.
|
// Get returns the ith SourceLocation. It panics if out of bounds.
|
||||||
Get(int) SourceLocation
|
Get(int) SourceLocation
|
||||||
|
|
||||||
doNotImplement
|
// ByPath returns the SourceLocation for the given path,
|
||||||
|
// returning the first location if multiple exist for the same path.
|
||||||
|
// If multiple locations exist for the same path,
|
||||||
|
// then SourceLocation.Next index can be used to identify the
|
||||||
|
// index of the next SourceLocation.
|
||||||
|
// If no location exists for this path, it returns the zero value.
|
||||||
|
ByPath(path SourcePath) SourceLocation
|
||||||
|
|
||||||
// TODO: Add ByPath and ByDescriptor helper methods.
|
// ByDescriptor returns the SourceLocation for the given descriptor,
|
||||||
|
// returning the first location if multiple exist for the same path.
|
||||||
|
// If no location exists for this descriptor, it returns the zero value.
|
||||||
|
ByDescriptor(desc Descriptor) SourceLocation
|
||||||
|
|
||||||
|
doNotImplement
|
||||||
}
|
}
|
||||||
|
|
||||||
// SourceLocation describes a source location and
|
// SourceLocation describes a source location and
|
||||||
@ -39,6 +54,10 @@ type SourceLocation struct {
|
|||||||
LeadingComments string
|
LeadingComments string
|
||||||
// TrailingComments is the trailing attached comment for the declaration.
|
// TrailingComments is the trailing attached comment for the declaration.
|
||||||
TrailingComments string
|
TrailingComments string
|
||||||
|
|
||||||
|
// Next is an index into SourceLocations for the next source location that
|
||||||
|
// has the same Path. It is zero if there is no next location.
|
||||||
|
Next int
|
||||||
}
|
}
|
||||||
|
|
||||||
// SourcePath identifies part of a file descriptor for a source location.
|
// SourcePath identifies part of a file descriptor for a source location.
|
||||||
@ -48,5 +67,62 @@ type SourceLocation struct {
|
|||||||
// See google.protobuf.SourceCodeInfo.Location.path.
|
// See google.protobuf.SourceCodeInfo.Location.path.
|
||||||
type SourcePath []int32
|
type SourcePath []int32
|
||||||
|
|
||||||
// TODO: Add SourcePath.String method to pretty-print the path. For example:
|
// Equal reports whether p1 equals p2.
|
||||||
// ".message_type[6].nested_type[15].field[3]"
|
func (p1 SourcePath) Equal(p2 SourcePath) bool {
|
||||||
|
if len(p1) != len(p2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i := range p1 {
|
||||||
|
if p1[i] != p2[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// String formats the path in a humanly readable manner.
|
||||||
|
// The output is guaranteed to be deterministic,
|
||||||
|
// making it suitable for use as a key into a Go map.
|
||||||
|
// It is not guaranteed to be stable as the exact output could change
|
||||||
|
// in a future version of this module.
|
||||||
|
//
|
||||||
|
// Example output:
|
||||||
|
// .message_type[6].nested_type[15].field[3]
|
||||||
|
func (p SourcePath) String() string {
|
||||||
|
b := p.appendFileDescriptorProto(nil)
|
||||||
|
for _, i := range p {
|
||||||
|
b = append(b, '.')
|
||||||
|
b = strconv.AppendInt(b, int64(i), 10)
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
type appendFunc func(*SourcePath, []byte) []byte
|
||||||
|
|
||||||
|
func (p *SourcePath) appendSingularField(b []byte, name string, f appendFunc) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
b = append(b, '.')
|
||||||
|
b = append(b, name...)
|
||||||
|
*p = (*p)[1:]
|
||||||
|
if f != nil {
|
||||||
|
b = f(p, b)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendRepeatedField(b []byte, name string, f appendFunc) []byte {
|
||||||
|
b = p.appendSingularField(b, name, nil)
|
||||||
|
if len(*p) == 0 || (*p)[0] < 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
b = append(b, '[')
|
||||||
|
b = strconv.AppendUint(b, uint64((*p)[0]), 10)
|
||||||
|
b = append(b, ']')
|
||||||
|
*p = (*p)[1:]
|
||||||
|
if f != nil {
|
||||||
|
b = f(p, b)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
461
reflect/protoreflect/source_gen.go
Normal file
461
reflect/protoreflect/source_gen.go
Normal file
@ -0,0 +1,461 @@
|
|||||||
|
// Copyright 2019 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Code generated by generate-protos. DO NOT EDIT.
|
||||||
|
|
||||||
|
package protoreflect
|
||||||
|
|
||||||
|
func (p *SourcePath) appendFileDescriptorProto(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 1:
|
||||||
|
b = p.appendSingularField(b, "name", nil)
|
||||||
|
case 2:
|
||||||
|
b = p.appendSingularField(b, "package", nil)
|
||||||
|
case 3:
|
||||||
|
b = p.appendRepeatedField(b, "dependency", nil)
|
||||||
|
case 10:
|
||||||
|
b = p.appendRepeatedField(b, "public_dependency", nil)
|
||||||
|
case 11:
|
||||||
|
b = p.appendRepeatedField(b, "weak_dependency", nil)
|
||||||
|
case 4:
|
||||||
|
b = p.appendRepeatedField(b, "message_type", (*SourcePath).appendDescriptorProto)
|
||||||
|
case 5:
|
||||||
|
b = p.appendRepeatedField(b, "enum_type", (*SourcePath).appendEnumDescriptorProto)
|
||||||
|
case 6:
|
||||||
|
b = p.appendRepeatedField(b, "service", (*SourcePath).appendServiceDescriptorProto)
|
||||||
|
case 7:
|
||||||
|
b = p.appendRepeatedField(b, "extension", (*SourcePath).appendFieldDescriptorProto)
|
||||||
|
case 8:
|
||||||
|
b = p.appendSingularField(b, "options", (*SourcePath).appendFileOptions)
|
||||||
|
case 9:
|
||||||
|
b = p.appendSingularField(b, "source_code_info", (*SourcePath).appendSourceCodeInfo)
|
||||||
|
case 12:
|
||||||
|
b = p.appendSingularField(b, "syntax", nil)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendDescriptorProto(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 1:
|
||||||
|
b = p.appendSingularField(b, "name", nil)
|
||||||
|
case 2:
|
||||||
|
b = p.appendRepeatedField(b, "field", (*SourcePath).appendFieldDescriptorProto)
|
||||||
|
case 6:
|
||||||
|
b = p.appendRepeatedField(b, "extension", (*SourcePath).appendFieldDescriptorProto)
|
||||||
|
case 3:
|
||||||
|
b = p.appendRepeatedField(b, "nested_type", (*SourcePath).appendDescriptorProto)
|
||||||
|
case 4:
|
||||||
|
b = p.appendRepeatedField(b, "enum_type", (*SourcePath).appendEnumDescriptorProto)
|
||||||
|
case 5:
|
||||||
|
b = p.appendRepeatedField(b, "extension_range", (*SourcePath).appendDescriptorProto_ExtensionRange)
|
||||||
|
case 8:
|
||||||
|
b = p.appendRepeatedField(b, "oneof_decl", (*SourcePath).appendOneofDescriptorProto)
|
||||||
|
case 7:
|
||||||
|
b = p.appendSingularField(b, "options", (*SourcePath).appendMessageOptions)
|
||||||
|
case 9:
|
||||||
|
b = p.appendRepeatedField(b, "reserved_range", (*SourcePath).appendDescriptorProto_ReservedRange)
|
||||||
|
case 10:
|
||||||
|
b = p.appendRepeatedField(b, "reserved_name", nil)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendEnumDescriptorProto(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 1:
|
||||||
|
b = p.appendSingularField(b, "name", nil)
|
||||||
|
case 2:
|
||||||
|
b = p.appendRepeatedField(b, "value", (*SourcePath).appendEnumValueDescriptorProto)
|
||||||
|
case 3:
|
||||||
|
b = p.appendSingularField(b, "options", (*SourcePath).appendEnumOptions)
|
||||||
|
case 4:
|
||||||
|
b = p.appendRepeatedField(b, "reserved_range", (*SourcePath).appendEnumDescriptorProto_EnumReservedRange)
|
||||||
|
case 5:
|
||||||
|
b = p.appendRepeatedField(b, "reserved_name", nil)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendServiceDescriptorProto(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 1:
|
||||||
|
b = p.appendSingularField(b, "name", nil)
|
||||||
|
case 2:
|
||||||
|
b = p.appendRepeatedField(b, "method", (*SourcePath).appendMethodDescriptorProto)
|
||||||
|
case 3:
|
||||||
|
b = p.appendSingularField(b, "options", (*SourcePath).appendServiceOptions)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendFieldDescriptorProto(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 1:
|
||||||
|
b = p.appendSingularField(b, "name", nil)
|
||||||
|
case 3:
|
||||||
|
b = p.appendSingularField(b, "number", nil)
|
||||||
|
case 4:
|
||||||
|
b = p.appendSingularField(b, "label", nil)
|
||||||
|
case 5:
|
||||||
|
b = p.appendSingularField(b, "type", nil)
|
||||||
|
case 6:
|
||||||
|
b = p.appendSingularField(b, "type_name", nil)
|
||||||
|
case 2:
|
||||||
|
b = p.appendSingularField(b, "extendee", nil)
|
||||||
|
case 7:
|
||||||
|
b = p.appendSingularField(b, "default_value", nil)
|
||||||
|
case 9:
|
||||||
|
b = p.appendSingularField(b, "oneof_index", nil)
|
||||||
|
case 10:
|
||||||
|
b = p.appendSingularField(b, "json_name", nil)
|
||||||
|
case 8:
|
||||||
|
b = p.appendSingularField(b, "options", (*SourcePath).appendFieldOptions)
|
||||||
|
case 17:
|
||||||
|
b = p.appendSingularField(b, "proto3_optional", nil)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendFileOptions(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 1:
|
||||||
|
b = p.appendSingularField(b, "java_package", nil)
|
||||||
|
case 8:
|
||||||
|
b = p.appendSingularField(b, "java_outer_classname", nil)
|
||||||
|
case 10:
|
||||||
|
b = p.appendSingularField(b, "java_multiple_files", nil)
|
||||||
|
case 20:
|
||||||
|
b = p.appendSingularField(b, "java_generate_equals_and_hash", nil)
|
||||||
|
case 27:
|
||||||
|
b = p.appendSingularField(b, "java_string_check_utf8", nil)
|
||||||
|
case 9:
|
||||||
|
b = p.appendSingularField(b, "optimize_for", nil)
|
||||||
|
case 11:
|
||||||
|
b = p.appendSingularField(b, "go_package", nil)
|
||||||
|
case 16:
|
||||||
|
b = p.appendSingularField(b, "cc_generic_services", nil)
|
||||||
|
case 17:
|
||||||
|
b = p.appendSingularField(b, "java_generic_services", nil)
|
||||||
|
case 18:
|
||||||
|
b = p.appendSingularField(b, "py_generic_services", nil)
|
||||||
|
case 42:
|
||||||
|
b = p.appendSingularField(b, "php_generic_services", nil)
|
||||||
|
case 23:
|
||||||
|
b = p.appendSingularField(b, "deprecated", nil)
|
||||||
|
case 31:
|
||||||
|
b = p.appendSingularField(b, "cc_enable_arenas", nil)
|
||||||
|
case 36:
|
||||||
|
b = p.appendSingularField(b, "objc_class_prefix", nil)
|
||||||
|
case 37:
|
||||||
|
b = p.appendSingularField(b, "csharp_namespace", nil)
|
||||||
|
case 39:
|
||||||
|
b = p.appendSingularField(b, "swift_prefix", nil)
|
||||||
|
case 40:
|
||||||
|
b = p.appendSingularField(b, "php_class_prefix", nil)
|
||||||
|
case 41:
|
||||||
|
b = p.appendSingularField(b, "php_namespace", nil)
|
||||||
|
case 44:
|
||||||
|
b = p.appendSingularField(b, "php_metadata_namespace", nil)
|
||||||
|
case 45:
|
||||||
|
b = p.appendSingularField(b, "ruby_package", nil)
|
||||||
|
case 999:
|
||||||
|
b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendSourceCodeInfo(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 1:
|
||||||
|
b = p.appendRepeatedField(b, "location", (*SourcePath).appendSourceCodeInfo_Location)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendDescriptorProto_ExtensionRange(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 1:
|
||||||
|
b = p.appendSingularField(b, "start", nil)
|
||||||
|
case 2:
|
||||||
|
b = p.appendSingularField(b, "end", nil)
|
||||||
|
case 3:
|
||||||
|
b = p.appendSingularField(b, "options", (*SourcePath).appendExtensionRangeOptions)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendOneofDescriptorProto(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 1:
|
||||||
|
b = p.appendSingularField(b, "name", nil)
|
||||||
|
case 2:
|
||||||
|
b = p.appendSingularField(b, "options", (*SourcePath).appendOneofOptions)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendMessageOptions(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 1:
|
||||||
|
b = p.appendSingularField(b, "message_set_wire_format", nil)
|
||||||
|
case 2:
|
||||||
|
b = p.appendSingularField(b, "no_standard_descriptor_accessor", nil)
|
||||||
|
case 3:
|
||||||
|
b = p.appendSingularField(b, "deprecated", nil)
|
||||||
|
case 7:
|
||||||
|
b = p.appendSingularField(b, "map_entry", nil)
|
||||||
|
case 999:
|
||||||
|
b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendDescriptorProto_ReservedRange(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 1:
|
||||||
|
b = p.appendSingularField(b, "start", nil)
|
||||||
|
case 2:
|
||||||
|
b = p.appendSingularField(b, "end", nil)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendEnumValueDescriptorProto(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 1:
|
||||||
|
b = p.appendSingularField(b, "name", nil)
|
||||||
|
case 2:
|
||||||
|
b = p.appendSingularField(b, "number", nil)
|
||||||
|
case 3:
|
||||||
|
b = p.appendSingularField(b, "options", (*SourcePath).appendEnumValueOptions)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendEnumOptions(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 2:
|
||||||
|
b = p.appendSingularField(b, "allow_alias", nil)
|
||||||
|
case 3:
|
||||||
|
b = p.appendSingularField(b, "deprecated", nil)
|
||||||
|
case 999:
|
||||||
|
b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendEnumDescriptorProto_EnumReservedRange(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 1:
|
||||||
|
b = p.appendSingularField(b, "start", nil)
|
||||||
|
case 2:
|
||||||
|
b = p.appendSingularField(b, "end", nil)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendMethodDescriptorProto(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 1:
|
||||||
|
b = p.appendSingularField(b, "name", nil)
|
||||||
|
case 2:
|
||||||
|
b = p.appendSingularField(b, "input_type", nil)
|
||||||
|
case 3:
|
||||||
|
b = p.appendSingularField(b, "output_type", nil)
|
||||||
|
case 4:
|
||||||
|
b = p.appendSingularField(b, "options", (*SourcePath).appendMethodOptions)
|
||||||
|
case 5:
|
||||||
|
b = p.appendSingularField(b, "client_streaming", nil)
|
||||||
|
case 6:
|
||||||
|
b = p.appendSingularField(b, "server_streaming", nil)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendServiceOptions(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 33:
|
||||||
|
b = p.appendSingularField(b, "deprecated", nil)
|
||||||
|
case 999:
|
||||||
|
b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendFieldOptions(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 1:
|
||||||
|
b = p.appendSingularField(b, "ctype", nil)
|
||||||
|
case 2:
|
||||||
|
b = p.appendSingularField(b, "packed", nil)
|
||||||
|
case 6:
|
||||||
|
b = p.appendSingularField(b, "jstype", nil)
|
||||||
|
case 5:
|
||||||
|
b = p.appendSingularField(b, "lazy", nil)
|
||||||
|
case 3:
|
||||||
|
b = p.appendSingularField(b, "deprecated", nil)
|
||||||
|
case 10:
|
||||||
|
b = p.appendSingularField(b, "weak", nil)
|
||||||
|
case 999:
|
||||||
|
b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendUninterpretedOption(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 2:
|
||||||
|
b = p.appendRepeatedField(b, "name", (*SourcePath).appendUninterpretedOption_NamePart)
|
||||||
|
case 3:
|
||||||
|
b = p.appendSingularField(b, "identifier_value", nil)
|
||||||
|
case 4:
|
||||||
|
b = p.appendSingularField(b, "positive_int_value", nil)
|
||||||
|
case 5:
|
||||||
|
b = p.appendSingularField(b, "negative_int_value", nil)
|
||||||
|
case 6:
|
||||||
|
b = p.appendSingularField(b, "double_value", nil)
|
||||||
|
case 7:
|
||||||
|
b = p.appendSingularField(b, "string_value", nil)
|
||||||
|
case 8:
|
||||||
|
b = p.appendSingularField(b, "aggregate_value", nil)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendSourceCodeInfo_Location(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 1:
|
||||||
|
b = p.appendRepeatedField(b, "path", nil)
|
||||||
|
case 2:
|
||||||
|
b = p.appendRepeatedField(b, "span", nil)
|
||||||
|
case 3:
|
||||||
|
b = p.appendSingularField(b, "leading_comments", nil)
|
||||||
|
case 4:
|
||||||
|
b = p.appendSingularField(b, "trailing_comments", nil)
|
||||||
|
case 6:
|
||||||
|
b = p.appendRepeatedField(b, "leading_detached_comments", nil)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendExtensionRangeOptions(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 999:
|
||||||
|
b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendOneofOptions(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 999:
|
||||||
|
b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendEnumValueOptions(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 1:
|
||||||
|
b = p.appendSingularField(b, "deprecated", nil)
|
||||||
|
case 999:
|
||||||
|
b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendMethodOptions(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 33:
|
||||||
|
b = p.appendSingularField(b, "deprecated", nil)
|
||||||
|
case 34:
|
||||||
|
b = p.appendSingularField(b, "idempotency_level", nil)
|
||||||
|
case 999:
|
||||||
|
b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *SourcePath) appendUninterpretedOption_NamePart(b []byte) []byte {
|
||||||
|
if len(*p) == 0 {
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
switch (*p)[0] {
|
||||||
|
case 1:
|
||||||
|
b = p.appendSingularField(b, "name_part", nil)
|
||||||
|
case 2:
|
||||||
|
b = p.appendSingularField(b, "is_extension", nil)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
35
reflect/protoreflect/source_test.go
Normal file
35
reflect/protoreflect/source_test.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2020 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package protoreflect
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestSourcePathString(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
in SourcePath
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{nil, ""},
|
||||||
|
{SourcePath{}, ""},
|
||||||
|
{SourcePath{0}, ".0"},
|
||||||
|
{SourcePath{1}, ".name"},
|
||||||
|
{SourcePath{1, 1}, ".name.1"},
|
||||||
|
{SourcePath{1, 1, -2, 3}, ".name.1.-2.3"},
|
||||||
|
{SourcePath{3}, ".dependency"},
|
||||||
|
{SourcePath{3, 0}, ".dependency[0]"},
|
||||||
|
{SourcePath{3, -1}, ".dependency.-1"},
|
||||||
|
{SourcePath{3, 1, 2}, ".dependency[1].2"},
|
||||||
|
{SourcePath{4}, ".message_type"},
|
||||||
|
{SourcePath{4, 0}, ".message_type[0]"},
|
||||||
|
{SourcePath{4, -1}, ".message_type.-1"},
|
||||||
|
{SourcePath{4, 1, 0}, ".message_type[1].0"},
|
||||||
|
{SourcePath{4, 1, 1}, ".message_type[1].name"},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
if got := tt.in.String(); got != tt.want {
|
||||||
|
t.Errorf("SourcePath(%d).String() = %v, want %v", tt.in, got, tt.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user