mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-03-23 19:21:40 +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
|
||||
// location identified by the field number n.
|
||||
func genStandaloneComments(g *protogen.GeneratedFile, f *fileInfo, n int32) {
|
||||
for _, loc := range f.Proto.GetSourceCodeInfo().GetLocation() {
|
||||
if len(loc.Path) == 1 && loc.Path[0] == n {
|
||||
for _, s := range loc.GetLeadingDetachedComments() {
|
||||
g.P(protogen.Comments(s))
|
||||
g.P()
|
||||
}
|
||||
if s := loc.GetLeadingComments(); s != "" {
|
||||
g.P(protogen.Comments(s))
|
||||
g.P()
|
||||
}
|
||||
}
|
||||
loc := f.Desc.SourceLocations().ByPath(protoreflect.SourcePath{n})
|
||||
for _, s := range loc.LeadingDetachedComments {
|
||||
g.P(protogen.Comments(s))
|
||||
g.P()
|
||||
}
|
||||
if s := loc.LeadingComments; s != "" {
|
||||
g.P(protogen.Comments(s))
|
||||
g.P()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,6 @@ package protogen
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
@ -482,7 +481,7 @@ type File struct {
|
||||
// of "dir/foo". Appending ".pb.go" produces an output file of "dir/foo.pb.go".
|
||||
GeneratedFilenamePrefix string
|
||||
|
||||
comments map[pathKey]CommentSet
|
||||
location Location
|
||||
}
|
||||
|
||||
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,
|
||||
GoPackageName: packageName,
|
||||
GoImportPath: importPath,
|
||||
comments: make(map[pathKey]CommentSet),
|
||||
location: Location{SourceFile: desc.Path()},
|
||||
}
|
||||
|
||||
// Determine the prefix for generated Go files.
|
||||
@ -526,19 +525,6 @@ func newFile(gen *Plugin, p *descriptorpb.FileDescriptorProto, packageName GoPac
|
||||
}
|
||||
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++ {
|
||||
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
|
||||
}
|
||||
|
||||
func (f *File) location(idxPath ...int32) Location {
|
||||
return Location{
|
||||
SourceFile: f.Desc.Path(),
|
||||
Path: idxPath,
|
||||
}
|
||||
}
|
||||
|
||||
// goPackageOption interprets a file's go_package option.
|
||||
// If there is no go_package, it returns ("", "").
|
||||
// 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 {
|
||||
var loc Location
|
||||
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 {
|
||||
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{
|
||||
Desc: desc,
|
||||
GoIdent: newGoIdent(f, desc),
|
||||
Location: loc,
|
||||
Comments: f.comments[newPathKey(loc.Path)],
|
||||
Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)),
|
||||
}
|
||||
gen.enumsByName[desc.FullName()] = enum
|
||||
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
|
||||
}
|
||||
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{
|
||||
Desc: desc,
|
||||
GoIdent: f.GoImportPath.Ident(name),
|
||||
Parent: enum,
|
||||
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 {
|
||||
var loc Location
|
||||
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 {
|
||||
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{
|
||||
Desc: desc,
|
||||
GoIdent: newGoIdent(f, desc),
|
||||
Location: loc,
|
||||
Comments: f.comments[newPathKey(loc.Path)],
|
||||
Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)),
|
||||
}
|
||||
gen.messagesByName[desc.FullName()] = message
|
||||
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
|
||||
switch {
|
||||
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:
|
||||
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:
|
||||
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()))
|
||||
var parentPrefix string
|
||||
@ -872,7 +851,7 @@ func newField(gen *Plugin, f *File, message *Message, desc protoreflect.FieldDes
|
||||
},
|
||||
Parent: message,
|
||||
Location: loc,
|
||||
Comments: f.comments[newPathKey(loc.Path)],
|
||||
Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)),
|
||||
}
|
||||
return field
|
||||
}
|
||||
@ -927,7 +906,7 @@ type Oneof struct {
|
||||
}
|
||||
|
||||
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()))
|
||||
parentPrefix := message.GoIdent.GoName + "_"
|
||||
return &Oneof{
|
||||
@ -939,7 +918,7 @@ func newOneof(gen *Plugin, f *File, message *Message, desc protoreflect.OneofDes
|
||||
GoName: parentPrefix + camelCased,
|
||||
},
|
||||
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 {
|
||||
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{
|
||||
Desc: desc,
|
||||
GoName: strs.GoCamelCase(string(desc.Name())),
|
||||
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++ {
|
||||
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 {
|
||||
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{
|
||||
Desc: desc,
|
||||
GoName: strs.GoCamelCase(string(desc.Name())),
|
||||
Parent: service,
|
||||
Location: loc,
|
||||
Comments: f.comments[newPathKey(loc.Path)],
|
||||
Comments: makeCommentSet(f.Desc.SourceLocations().ByDescriptor(desc)),
|
||||
}
|
||||
return method
|
||||
}
|
||||
@ -1359,28 +1338,10 @@ type Location struct {
|
||||
}
|
||||
|
||||
// appendPath add elements to a Location's path, returning a new Location.
|
||||
func (loc Location) appendPath(a ...int32) Location {
|
||||
var n protoreflect.SourcePath
|
||||
n = append(n, loc.Path...)
|
||||
n = append(n, a...)
|
||||
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)}
|
||||
func (loc Location) appendPath(num protoreflect.FieldNumber, idx int) Location {
|
||||
loc.Path = append(protoreflect.SourcePath(nil), loc.Path...) // make copy
|
||||
loc.Path = append(loc.Path, int32(num), int32(idx))
|
||||
return loc
|
||||
}
|
||||
|
||||
// CommentSet is a set of leading and trailing comments associated
|
||||
@ -1391,6 +1352,18 @@ type CommentSet struct {
|
||||
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.
|
||||
type Comments string
|
||||
|
||||
|
@ -93,6 +93,7 @@ func init() {
|
||||
gengo.GenerateVersionMarkers = false
|
||||
gengo.GenerateFile(gen, file)
|
||||
generateIdentifiers(gen, file)
|
||||
generateSouceContextStringer(gen, file)
|
||||
}
|
||||
}
|
||||
gen.SupportedFeatures = gengo.SupportedFeatures
|
||||
@ -361,6 +362,66 @@ func generateIdentifiers(gen *protogen.Plugin, file *protogen.File) {
|
||||
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) {
|
||||
filepath.Walk(srcDir, func(srcPath string, _ os.FileInfo, _ error) error {
|
||||
if !strings.HasSuffix(srcPath, ".go") && !strings.HasSuffix(srcPath, ".meta") {
|
||||
|
@ -3,6 +3,9 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package filedesc provides functionality for constructing descriptors.
|
||||
//
|
||||
// The types in this package implement interfaces in the protoreflect package
|
||||
// related to protobuf descripriptors.
|
||||
package filedesc
|
||||
|
||||
import (
|
||||
|
@ -6,9 +6,12 @@ package filedesc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
"google.golang.org/protobuf/internal/genid"
|
||||
|
||||
"google.golang.org/protobuf/encoding/protowire"
|
||||
"google.golang.org/protobuf/internal/descfmt"
|
||||
"google.golang.org/protobuf/internal/errors"
|
||||
@ -278,9 +281,170 @@ func (p *OneofFields) lazyInit() *OneofFields {
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
// 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) Get(i int) pref.SourceLocation { return p.List[i] }
|
||||
func (p *SourceLocations) Len() int { return len(p.List) }
|
||||
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) {}
|
||||
|
||||
// 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.
|
||||
f.L2.Locations.File = f
|
||||
for _, loc := range fd.GetSourceCodeInfo().GetLocation() {
|
||||
var l protoreflect.SourceLocation
|
||||
// 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")
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// SourceLocations is a list of source locations.
|
||||
type SourceLocations interface {
|
||||
// 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(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
|
||||
@ -39,6 +54,10 @@ type SourceLocation struct {
|
||||
LeadingComments string
|
||||
// TrailingComments is the trailing attached comment for the declaration.
|
||||
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.
|
||||
@ -48,5 +67,62 @@ type SourceLocation struct {
|
||||
// See google.protobuf.SourceCodeInfo.Location.path.
|
||||
type SourcePath []int32
|
||||
|
||||
// TODO: Add SourcePath.String method to pretty-print the path. For example:
|
||||
// ".message_type[6].nested_type[15].field[3]"
|
||||
// Equal reports whether p1 equals p2.
|
||||
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