2018-08-26 22:48:17 -07:00
|
|
|
// Copyright 2018 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.
|
|
|
|
|
2018-11-26 18:55:29 -08:00
|
|
|
// Package protodesc provides for converting descriptorpb.FileDescriptorProto
|
|
|
|
// to/from the reflective protoreflect.FileDescriptor.
|
|
|
|
package protodesc
|
2018-08-26 22:48:17 -07:00
|
|
|
|
|
|
|
import (
|
|
|
|
"strings"
|
|
|
|
|
2019-05-13 23:55:40 -07:00
|
|
|
"google.golang.org/protobuf/internal/encoding/defval"
|
|
|
|
"google.golang.org/protobuf/internal/errors"
|
|
|
|
"google.golang.org/protobuf/internal/prototype"
|
|
|
|
"google.golang.org/protobuf/reflect/protoreflect"
|
|
|
|
"google.golang.org/protobuf/reflect/protoregistry"
|
2018-11-26 18:55:29 -08:00
|
|
|
|
2019-05-13 23:55:40 -07:00
|
|
|
descriptorpb "google.golang.org/protobuf/types/descriptor"
|
2018-08-26 22:48:17 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
// TODO: Should we be responsible for validating other parts of the descriptor
|
|
|
|
// that we don't directly use?
|
|
|
|
//
|
|
|
|
// For example:
|
|
|
|
// * That "json_name" is not set for an extension field. Maybe, maybe not.
|
|
|
|
// * That "weak" is not set for an extension field (double check this).
|
|
|
|
|
|
|
|
// TODO: Store the input file descriptor to implement:
|
|
|
|
// * protoreflect.Descriptor.DescriptorProto
|
|
|
|
// * protoreflect.Descriptor.DescriptorOptions
|
|
|
|
|
|
|
|
// TODO: Should we return a File instead of protoreflect.FileDescriptor?
|
|
|
|
// This would allow users to mutate the File before converting it.
|
|
|
|
// However, this will complicate future work for validation since File may now
|
|
|
|
// diverge from the stored descriptor proto (see above TODO).
|
|
|
|
|
2018-11-26 18:55:29 -08:00
|
|
|
// NewFile creates a new protoreflect.FileDescriptor from the provided
|
|
|
|
// file descriptor message. The file must represent a valid proto file according
|
|
|
|
// to protobuf semantics.
|
2018-08-26 22:48:17 -07:00
|
|
|
//
|
|
|
|
// Any import files, enum types, or message types referenced in the file are
|
|
|
|
// resolved using the provided registry. When looking up an import file path,
|
|
|
|
// the path must be unique. The newly created file descriptor is not registered
|
|
|
|
// back into the provided file registry.
|
|
|
|
//
|
|
|
|
// The caller must relinquish full ownership of the input fd and must not
|
|
|
|
// access or mutate any fields.
|
2018-11-26 18:55:29 -08:00
|
|
|
func NewFile(fd *descriptorpb.FileDescriptorProto, r *protoregistry.Files) (protoreflect.FileDescriptor, error) {
|
|
|
|
var f prototype.File
|
2018-08-26 22:48:17 -07:00
|
|
|
switch fd.GetSyntax() {
|
2018-12-06 09:39:03 -08:00
|
|
|
case "proto2", "":
|
2018-08-26 22:48:17 -07:00
|
|
|
f.Syntax = protoreflect.Proto2
|
|
|
|
case "proto3":
|
|
|
|
f.Syntax = protoreflect.Proto3
|
|
|
|
default:
|
|
|
|
return nil, errors.New("invalid syntax: %v", fd.GetSyntax())
|
|
|
|
}
|
|
|
|
f.Path = fd.GetName()
|
|
|
|
f.Package = protoreflect.FullName(fd.GetPackage())
|
2018-10-23 15:03:38 -07:00
|
|
|
f.Options = fd.GetOptions()
|
2018-08-26 22:48:17 -07:00
|
|
|
|
|
|
|
f.Imports = make([]protoreflect.FileImport, len(fd.GetDependency()))
|
|
|
|
for _, i := range fd.GetPublicDependency() {
|
|
|
|
if int(i) >= len(f.Imports) || f.Imports[i].IsPublic {
|
|
|
|
return nil, errors.New("invalid or duplicate public import index: %d", i)
|
|
|
|
}
|
|
|
|
f.Imports[i].IsPublic = true
|
|
|
|
}
|
|
|
|
for _, i := range fd.GetWeakDependency() {
|
|
|
|
if int(i) >= len(f.Imports) || f.Imports[i].IsWeak {
|
|
|
|
return nil, errors.New("invalid or duplicate weak import index: %d", i)
|
|
|
|
}
|
|
|
|
f.Imports[i].IsWeak = true
|
|
|
|
}
|
|
|
|
for i, path := range fd.GetDependency() {
|
|
|
|
var n int
|
|
|
|
imp := &f.Imports[i]
|
|
|
|
r.RangeFilesByPath(path, func(fd protoreflect.FileDescriptor) bool {
|
|
|
|
imp.FileDescriptor = fd
|
|
|
|
n++
|
|
|
|
return true
|
|
|
|
})
|
|
|
|
if n > 1 {
|
|
|
|
return nil, errors.New("duplicate files for import %q", path)
|
|
|
|
}
|
|
|
|
if imp.IsWeak || imp.FileDescriptor == nil {
|
2018-11-26 18:55:29 -08:00
|
|
|
imp.FileDescriptor = prototype.PlaceholderFile(path, "")
|
2018-08-26 22:48:17 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-03 14:05:20 -06:00
|
|
|
imps := importedFiles(f.Imports)
|
|
|
|
|
2018-08-26 22:48:17 -07:00
|
|
|
var err error
|
2019-05-03 14:05:20 -06:00
|
|
|
f.Messages, err = messagesFromDescriptorProto(fd.GetMessageType(), imps, r)
|
2018-08-26 22:48:17 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
f.Enums, err = enumsFromDescriptorProto(fd.GetEnumType(), r)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-05-03 14:05:20 -06:00
|
|
|
f.Extensions, err = extensionsFromDescriptorProto(fd.GetExtension(), imps, r)
|
2018-08-26 22:48:17 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-05-03 14:05:20 -06:00
|
|
|
f.Services, err = servicesFromDescriptorProto(fd.GetService(), imps, r)
|
2018-08-26 22:48:17 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-11-26 18:55:29 -08:00
|
|
|
return prototype.NewFile(&f)
|
2018-08-26 22:48:17 -07:00
|
|
|
}
|
|
|
|
|
2019-05-07 19:10:41 -06:00
|
|
|
type importSet map[string]bool
|
2019-05-03 14:05:20 -06:00
|
|
|
|
|
|
|
func importedFiles(imps []protoreflect.FileImport) importSet {
|
|
|
|
ret := make(importSet)
|
|
|
|
for _, imp := range imps {
|
2019-05-07 19:10:41 -06:00
|
|
|
ret[imp.Path()] = true
|
|
|
|
addPublicImports(imp, ret)
|
2019-05-03 14:05:20 -06:00
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
func addPublicImports(fd protoreflect.FileDescriptor, out importSet) {
|
|
|
|
imps := fd.Imports()
|
|
|
|
for i := 0; i < imps.Len(); i++ {
|
|
|
|
imp := imps.Get(i)
|
|
|
|
if imp.IsPublic {
|
2019-05-07 19:10:41 -06:00
|
|
|
out[imp.Path()] = true
|
|
|
|
addPublicImports(imp, out)
|
2019-05-03 14:05:20 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func messagesFromDescriptorProto(mds []*descriptorpb.DescriptorProto, imps importSet, r *protoregistry.Files) (ms []prototype.Message, err error) {
|
2018-08-26 22:48:17 -07:00
|
|
|
for _, md := range mds {
|
2018-11-26 18:55:29 -08:00
|
|
|
var m prototype.Message
|
2018-08-26 22:48:17 -07:00
|
|
|
m.Name = protoreflect.Name(md.GetName())
|
2018-10-23 15:03:38 -07:00
|
|
|
m.Options = md.GetOptions()
|
2018-12-10 15:14:36 -08:00
|
|
|
m.IsMapEntry = md.GetOptions().GetMapEntry()
|
2019-05-03 14:05:20 -06:00
|
|
|
|
|
|
|
for _, s := range md.GetReservedName() {
|
|
|
|
m.ReservedNames = append(m.ReservedNames, protoreflect.Name(s))
|
|
|
|
}
|
|
|
|
for _, rr := range md.GetReservedRange() {
|
|
|
|
m.ReservedRanges = append(m.ReservedRanges, [2]protoreflect.FieldNumber{
|
|
|
|
protoreflect.FieldNumber(rr.GetStart()),
|
|
|
|
protoreflect.FieldNumber(rr.GetEnd()),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
for _, xr := range md.GetExtensionRange() {
|
|
|
|
m.ExtensionRanges = append(m.ExtensionRanges, [2]protoreflect.FieldNumber{
|
|
|
|
protoreflect.FieldNumber(xr.GetStart()),
|
|
|
|
protoreflect.FieldNumber(xr.GetEnd()),
|
|
|
|
})
|
|
|
|
m.ExtensionRangeOptions = append(m.ExtensionRangeOptions, xr.GetOptions())
|
|
|
|
}
|
|
|
|
resNames := prototype.Names(m.ReservedNames)
|
|
|
|
resRanges := prototype.FieldRanges(m.ReservedRanges)
|
|
|
|
extRanges := prototype.FieldRanges(m.ExtensionRanges)
|
|
|
|
|
2018-08-26 22:48:17 -07:00
|
|
|
for _, fd := range md.GetField() {
|
2019-05-03 14:05:20 -06:00
|
|
|
if fd.GetExtendee() != "" {
|
|
|
|
return nil, errors.New("message field may not have extendee")
|
|
|
|
}
|
2018-11-26 18:55:29 -08:00
|
|
|
var f prototype.Field
|
2018-08-26 22:48:17 -07:00
|
|
|
f.Name = protoreflect.Name(fd.GetName())
|
2019-05-03 14:05:20 -06:00
|
|
|
if resNames.Has(f.Name) {
|
|
|
|
return nil, errors.New("%v contains field with reserved name %q", m.Name, f.Name)
|
|
|
|
}
|
2018-08-26 22:48:17 -07:00
|
|
|
f.Number = protoreflect.FieldNumber(fd.GetNumber())
|
2019-05-03 14:05:20 -06:00
|
|
|
if resRanges.Has(f.Number) {
|
|
|
|
return nil, errors.New("%v contains field with reserved number %d", m.Name, f.Number)
|
|
|
|
}
|
|
|
|
if extRanges.Has(f.Number) {
|
|
|
|
return nil, errors.New("%v contains field with number %d in extension range", m.Name, f.Number)
|
|
|
|
}
|
2018-08-26 22:48:17 -07:00
|
|
|
f.Cardinality = protoreflect.Cardinality(fd.GetLabel())
|
|
|
|
f.Kind = protoreflect.Kind(fd.GetType())
|
2018-12-10 15:14:36 -08:00
|
|
|
opts := fd.GetOptions()
|
|
|
|
f.Options = opts
|
|
|
|
if opts != nil && opts.Packed != nil {
|
|
|
|
if *opts.Packed {
|
|
|
|
f.IsPacked = prototype.True
|
|
|
|
} else {
|
|
|
|
f.IsPacked = prototype.False
|
|
|
|
}
|
|
|
|
}
|
|
|
|
f.IsWeak = opts.GetWeak()
|
2018-08-26 22:48:17 -07:00
|
|
|
f.JSONName = fd.GetJsonName()
|
|
|
|
if fd.DefaultValue != nil {
|
2018-12-06 18:34:53 -08:00
|
|
|
f.Default, err = defval.Unmarshal(fd.GetDefaultValue(), f.Kind, defval.Descriptor)
|
2018-08-26 22:48:17 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if fd.OneofIndex != nil {
|
|
|
|
i := int(fd.GetOneofIndex())
|
|
|
|
if i >= len(md.GetOneofDecl()) {
|
|
|
|
return nil, errors.New("invalid oneof index: %d", i)
|
|
|
|
}
|
|
|
|
f.OneofName = protoreflect.Name(md.GetOneofDecl()[i].GetName())
|
|
|
|
}
|
|
|
|
switch f.Kind {
|
|
|
|
case protoreflect.EnumKind:
|
2019-05-03 14:05:20 -06:00
|
|
|
f.EnumType, err = findEnumDescriptor(fd.GetTypeName(), imps, r)
|
2018-08-26 22:48:17 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-11-26 18:55:29 -08:00
|
|
|
if opts.GetWeak() && !f.EnumType.IsPlaceholder() {
|
|
|
|
f.EnumType = prototype.PlaceholderEnum(f.EnumType.FullName())
|
2018-08-26 22:48:17 -07:00
|
|
|
}
|
|
|
|
case protoreflect.MessageKind, protoreflect.GroupKind:
|
2019-05-03 14:05:20 -06:00
|
|
|
f.MessageType, err = findMessageDescriptor(fd.GetTypeName(), imps, r)
|
2018-08-26 22:48:17 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-11-26 18:55:29 -08:00
|
|
|
if opts.GetWeak() && !f.MessageType.IsPlaceholder() {
|
|
|
|
f.MessageType = prototype.PlaceholderMessage(f.MessageType.FullName())
|
2018-08-26 22:48:17 -07:00
|
|
|
}
|
2019-05-03 14:05:20 -06:00
|
|
|
default:
|
|
|
|
if fd.GetTypeName() != "" {
|
|
|
|
return nil, errors.New("field of kind %v has type_name set", f.Kind)
|
|
|
|
}
|
2018-08-26 22:48:17 -07:00
|
|
|
}
|
|
|
|
m.Fields = append(m.Fields, f)
|
|
|
|
}
|
|
|
|
for _, od := range md.GetOneofDecl() {
|
2018-11-26 18:55:29 -08:00
|
|
|
m.Oneofs = append(m.Oneofs, prototype.Oneof{
|
2018-10-23 15:03:38 -07:00
|
|
|
Name: protoreflect.Name(od.GetName()),
|
|
|
|
Options: od.Options,
|
|
|
|
})
|
2018-08-26 22:48:17 -07:00
|
|
|
}
|
|
|
|
|
2019-05-03 14:05:20 -06:00
|
|
|
m.Messages, err = messagesFromDescriptorProto(md.GetNestedType(), imps, r)
|
2018-08-26 22:48:17 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
m.Enums, err = enumsFromDescriptorProto(md.GetEnumType(), r)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-05-03 14:05:20 -06:00
|
|
|
m.Extensions, err = extensionsFromDescriptorProto(md.GetExtension(), imps, r)
|
2018-08-26 22:48:17 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
ms = append(ms, m)
|
|
|
|
}
|
|
|
|
return ms, nil
|
|
|
|
}
|
|
|
|
|
2018-11-26 18:55:29 -08:00
|
|
|
func enumsFromDescriptorProto(eds []*descriptorpb.EnumDescriptorProto, r *protoregistry.Files) (es []prototype.Enum, err error) {
|
2018-08-26 22:48:17 -07:00
|
|
|
for _, ed := range eds {
|
2018-11-26 18:55:29 -08:00
|
|
|
var e prototype.Enum
|
2018-08-26 22:48:17 -07:00
|
|
|
e.Name = protoreflect.Name(ed.GetName())
|
2018-10-23 15:03:38 -07:00
|
|
|
e.Options = ed.GetOptions()
|
2018-12-06 09:39:03 -08:00
|
|
|
for _, s := range ed.GetReservedName() {
|
|
|
|
e.ReservedNames = append(e.ReservedNames, protoreflect.Name(s))
|
|
|
|
}
|
|
|
|
for _, rr := range ed.GetReservedRange() {
|
|
|
|
e.ReservedRanges = append(e.ReservedRanges, [2]protoreflect.EnumNumber{
|
|
|
|
protoreflect.EnumNumber(rr.GetStart()),
|
|
|
|
protoreflect.EnumNumber(rr.GetEnd()),
|
|
|
|
})
|
|
|
|
}
|
2019-05-03 14:05:20 -06:00
|
|
|
resNames := prototype.Names(e.ReservedNames)
|
|
|
|
resRanges := prototype.EnumRanges(e.ReservedRanges)
|
|
|
|
|
|
|
|
for _, vd := range ed.GetValue() {
|
|
|
|
v := prototype.EnumValue{
|
|
|
|
Name: protoreflect.Name(vd.GetName()),
|
|
|
|
Number: protoreflect.EnumNumber(vd.GetNumber()),
|
|
|
|
Options: vd.Options,
|
|
|
|
}
|
|
|
|
if resNames.Has(v.Name) {
|
|
|
|
return nil, errors.New("enum %v contains value with reserved name %q", e.Name, v.Name)
|
|
|
|
}
|
|
|
|
if resRanges.Has(v.Number) {
|
|
|
|
return nil, errors.New("enum %v contains value with reserved number %d", e.Name, v.Number)
|
|
|
|
}
|
|
|
|
e.Values = append(e.Values, v)
|
|
|
|
}
|
2018-08-26 22:48:17 -07:00
|
|
|
es = append(es, e)
|
|
|
|
}
|
|
|
|
return es, nil
|
|
|
|
}
|
|
|
|
|
2019-05-03 14:05:20 -06:00
|
|
|
func extensionsFromDescriptorProto(xds []*descriptorpb.FieldDescriptorProto, imps importSet, r *protoregistry.Files) (xs []prototype.Extension, err error) {
|
2018-08-26 22:48:17 -07:00
|
|
|
for _, xd := range xds {
|
2019-05-03 14:05:20 -06:00
|
|
|
if xd.OneofIndex != nil {
|
|
|
|
return nil, errors.New("extension may not have oneof_index")
|
|
|
|
}
|
2018-11-26 18:55:29 -08:00
|
|
|
var x prototype.Extension
|
2018-08-26 22:48:17 -07:00
|
|
|
x.Name = protoreflect.Name(xd.GetName())
|
|
|
|
x.Number = protoreflect.FieldNumber(xd.GetNumber())
|
|
|
|
x.Cardinality = protoreflect.Cardinality(xd.GetLabel())
|
|
|
|
x.Kind = protoreflect.Kind(xd.GetType())
|
2018-10-23 15:03:38 -07:00
|
|
|
x.Options = xd.GetOptions()
|
2018-08-26 22:48:17 -07:00
|
|
|
if xd.DefaultValue != nil {
|
2018-12-06 18:34:53 -08:00
|
|
|
x.Default, err = defval.Unmarshal(xd.GetDefaultValue(), x.Kind, defval.Descriptor)
|
2018-08-26 22:48:17 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
switch x.Kind {
|
|
|
|
case protoreflect.EnumKind:
|
2019-05-03 14:05:20 -06:00
|
|
|
x.EnumType, err = findEnumDescriptor(xd.GetTypeName(), imps, r)
|
2018-08-26 22:48:17 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
case protoreflect.MessageKind, protoreflect.GroupKind:
|
2019-05-03 14:05:20 -06:00
|
|
|
x.MessageType, err = findMessageDescriptor(xd.GetTypeName(), imps, r)
|
2018-08-26 22:48:17 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-05-03 14:05:20 -06:00
|
|
|
default:
|
|
|
|
if xd.GetTypeName() != "" {
|
|
|
|
return nil, errors.New("extension of kind %v has type_name set", x.Kind)
|
|
|
|
}
|
2018-08-26 22:48:17 -07:00
|
|
|
}
|
2019-05-03 14:05:20 -06:00
|
|
|
x.ExtendedType, err = findMessageDescriptor(xd.GetExtendee(), imps, r)
|
2018-08-26 22:48:17 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
xs = append(xs, x)
|
|
|
|
}
|
|
|
|
return xs, nil
|
|
|
|
}
|
|
|
|
|
2019-05-03 14:05:20 -06:00
|
|
|
func servicesFromDescriptorProto(sds []*descriptorpb.ServiceDescriptorProto, imps importSet, r *protoregistry.Files) (ss []prototype.Service, err error) {
|
2018-08-26 22:48:17 -07:00
|
|
|
for _, sd := range sds {
|
2018-11-26 18:55:29 -08:00
|
|
|
var s prototype.Service
|
2018-08-26 22:48:17 -07:00
|
|
|
s.Name = protoreflect.Name(sd.GetName())
|
2018-10-23 15:03:38 -07:00
|
|
|
s.Options = sd.GetOptions()
|
2018-08-26 22:48:17 -07:00
|
|
|
for _, md := range sd.GetMethod() {
|
2018-11-26 18:55:29 -08:00
|
|
|
var m prototype.Method
|
2018-08-26 22:48:17 -07:00
|
|
|
m.Name = protoreflect.Name(md.GetName())
|
2018-10-23 15:03:38 -07:00
|
|
|
m.Options = md.GetOptions()
|
2019-05-03 14:05:20 -06:00
|
|
|
m.InputType, err = findMessageDescriptor(md.GetInputType(), imps, r)
|
2018-08-26 22:48:17 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-05-03 14:05:20 -06:00
|
|
|
m.OutputType, err = findMessageDescriptor(md.GetOutputType(), imps, r)
|
2018-08-26 22:48:17 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
m.IsStreamingClient = md.GetClientStreaming()
|
|
|
|
m.IsStreamingServer = md.GetServerStreaming()
|
|
|
|
s.Methods = append(s.Methods, m)
|
|
|
|
}
|
|
|
|
ss = append(ss, s)
|
|
|
|
}
|
|
|
|
return ss, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Should we allow relative names? The protoc compiler has emitted
|
|
|
|
// absolute names for some time now. Requiring absolute names as an input
|
|
|
|
// simplifies our implementation as we won't need to implement C++'s namespace
|
|
|
|
// scoping rules.
|
|
|
|
|
2019-05-03 14:05:20 -06:00
|
|
|
func findMessageDescriptor(s string, imps importSet, r *protoregistry.Files) (protoreflect.MessageDescriptor, error) {
|
2018-08-26 22:48:17 -07:00
|
|
|
if !strings.HasPrefix(s, ".") {
|
|
|
|
return nil, errors.New("identifier name must be fully qualified with a leading dot: %v", s)
|
|
|
|
}
|
|
|
|
name := protoreflect.FullName(strings.TrimPrefix(s, "."))
|
reflect/protoreflect, reflect/protoregistry: move descriptor lookup to registry
Drop the protoreflect.FileDescriptor.DescriptorByName method.
Descriptor lookup will always happen through a protoregistry.Files, which
is more generally useful (it's rare that you want to find a descriptor in a
specific file, as opposed to a package which may be composed of multiple files).
Split protoregistry.Files descriptor lookup into individual per-type functions
(enum, message, extension, service), matching the preg.Types API.
Drop the ability to look up enum values, message fields, and service methods
for now. This can be easily added later if needed, and is trivial to implement
in user code. (e.g., look up the service and then consult sd.Methods.ByName().)
Change-Id: I2b3d8ef888921a8464ba1434eddab20c7d3a458e
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/172118
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-04-15 13:05:13 -07:00
|
|
|
md, err := r.FindMessageByName(name)
|
|
|
|
if err != nil {
|
2018-11-26 18:55:29 -08:00
|
|
|
return prototype.PlaceholderMessage(name), nil
|
2018-08-26 22:48:17 -07:00
|
|
|
}
|
2019-05-03 14:05:20 -06:00
|
|
|
if err := validateFileInImports(md, imps); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
reflect/protoreflect, reflect/protoregistry: move descriptor lookup to registry
Drop the protoreflect.FileDescriptor.DescriptorByName method.
Descriptor lookup will always happen through a protoregistry.Files, which
is more generally useful (it's rare that you want to find a descriptor in a
specific file, as opposed to a package which may be composed of multiple files).
Split protoregistry.Files descriptor lookup into individual per-type functions
(enum, message, extension, service), matching the preg.Types API.
Drop the ability to look up enum values, message fields, and service methods
for now. This can be easily added later if needed, and is trivial to implement
in user code. (e.g., look up the service and then consult sd.Methods.ByName().)
Change-Id: I2b3d8ef888921a8464ba1434eddab20c7d3a458e
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/172118
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-04-15 13:05:13 -07:00
|
|
|
return md, nil
|
2018-08-26 22:48:17 -07:00
|
|
|
}
|
|
|
|
|
2019-05-03 14:05:20 -06:00
|
|
|
func findEnumDescriptor(s string, imps importSet, r *protoregistry.Files) (protoreflect.EnumDescriptor, error) {
|
2018-08-26 22:48:17 -07:00
|
|
|
if !strings.HasPrefix(s, ".") {
|
|
|
|
return nil, errors.New("identifier name must be fully qualified with a leading dot: %v", s)
|
|
|
|
}
|
|
|
|
name := protoreflect.FullName(strings.TrimPrefix(s, "."))
|
reflect/protoreflect, reflect/protoregistry: move descriptor lookup to registry
Drop the protoreflect.FileDescriptor.DescriptorByName method.
Descriptor lookup will always happen through a protoregistry.Files, which
is more generally useful (it's rare that you want to find a descriptor in a
specific file, as opposed to a package which may be composed of multiple files).
Split protoregistry.Files descriptor lookup into individual per-type functions
(enum, message, extension, service), matching the preg.Types API.
Drop the ability to look up enum values, message fields, and service methods
for now. This can be easily added later if needed, and is trivial to implement
in user code. (e.g., look up the service and then consult sd.Methods.ByName().)
Change-Id: I2b3d8ef888921a8464ba1434eddab20c7d3a458e
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/172118
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-04-15 13:05:13 -07:00
|
|
|
ed, err := r.FindEnumByName(name)
|
|
|
|
if err != nil {
|
2018-11-26 18:55:29 -08:00
|
|
|
return prototype.PlaceholderEnum(name), nil
|
2018-08-26 22:48:17 -07:00
|
|
|
}
|
2019-05-03 14:05:20 -06:00
|
|
|
if err := validateFileInImports(ed, imps); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
reflect/protoreflect, reflect/protoregistry: move descriptor lookup to registry
Drop the protoreflect.FileDescriptor.DescriptorByName method.
Descriptor lookup will always happen through a protoregistry.Files, which
is more generally useful (it's rare that you want to find a descriptor in a
specific file, as opposed to a package which may be composed of multiple files).
Split protoregistry.Files descriptor lookup into individual per-type functions
(enum, message, extension, service), matching the preg.Types API.
Drop the ability to look up enum values, message fields, and service methods
for now. This can be easily added later if needed, and is trivial to implement
in user code. (e.g., look up the service and then consult sd.Methods.ByName().)
Change-Id: I2b3d8ef888921a8464ba1434eddab20c7d3a458e
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/172118
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2019-04-15 13:05:13 -07:00
|
|
|
return ed, nil
|
2018-08-26 22:48:17 -07:00
|
|
|
}
|
2019-05-12 02:27:46 -07:00
|
|
|
|
|
|
|
func validateFileInImports(d protoreflect.Descriptor, imps importSet) error {
|
|
|
|
fd := d.ParentFile()
|
|
|
|
if fd == nil {
|
|
|
|
return errors.New("%v has no parent FileDescriptor", d.FullName())
|
|
|
|
}
|
|
|
|
if !imps[fd.Path()] {
|
|
|
|
return errors.New("reference to type %v without import of %v", d.FullName(), fd.Path())
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|