1*1c12ee1eSDan Willemsen// Copyright 2019 The Go Authors. All rights reserved. 2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style 3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file. 4*1c12ee1eSDan Willemsen 5*1c12ee1eSDan Willemsenpackage protodesc 6*1c12ee1eSDan Willemsen 7*1c12ee1eSDan Willemsenimport ( 8*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/encoding/defval" 9*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/errors" 10*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/filedesc" 11*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoreflect" 12*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoregistry" 13*1c12ee1eSDan Willemsen 14*1c12ee1eSDan Willemsen "google.golang.org/protobuf/types/descriptorpb" 15*1c12ee1eSDan Willemsen) 16*1c12ee1eSDan Willemsen 17*1c12ee1eSDan Willemsen// resolver is a wrapper around a local registry of declarations within the file 18*1c12ee1eSDan Willemsen// and the remote resolver. The remote resolver is restricted to only return 19*1c12ee1eSDan Willemsen// descriptors that have been imported. 20*1c12ee1eSDan Willemsentype resolver struct { 21*1c12ee1eSDan Willemsen local descsByName 22*1c12ee1eSDan Willemsen remote Resolver 23*1c12ee1eSDan Willemsen imports importSet 24*1c12ee1eSDan Willemsen 25*1c12ee1eSDan Willemsen allowUnresolvable bool 26*1c12ee1eSDan Willemsen} 27*1c12ee1eSDan Willemsen 28*1c12ee1eSDan Willemsenfunc (r *resolver) resolveMessageDependencies(ms []filedesc.Message, mds []*descriptorpb.DescriptorProto) (err error) { 29*1c12ee1eSDan Willemsen for i, md := range mds { 30*1c12ee1eSDan Willemsen m := &ms[i] 31*1c12ee1eSDan Willemsen for j, fd := range md.GetField() { 32*1c12ee1eSDan Willemsen f := &m.L2.Fields.List[j] 33*1c12ee1eSDan Willemsen if f.L1.Cardinality == protoreflect.Required { 34*1c12ee1eSDan Willemsen m.L2.RequiredNumbers.List = append(m.L2.RequiredNumbers.List, f.L1.Number) 35*1c12ee1eSDan Willemsen } 36*1c12ee1eSDan Willemsen if fd.OneofIndex != nil { 37*1c12ee1eSDan Willemsen k := int(fd.GetOneofIndex()) 38*1c12ee1eSDan Willemsen if !(0 <= k && k < len(md.GetOneofDecl())) { 39*1c12ee1eSDan Willemsen return errors.New("message field %q has an invalid oneof index: %d", f.FullName(), k) 40*1c12ee1eSDan Willemsen } 41*1c12ee1eSDan Willemsen o := &m.L2.Oneofs.List[k] 42*1c12ee1eSDan Willemsen f.L1.ContainingOneof = o 43*1c12ee1eSDan Willemsen o.L1.Fields.List = append(o.L1.Fields.List, f) 44*1c12ee1eSDan Willemsen } 45*1c12ee1eSDan Willemsen 46*1c12ee1eSDan Willemsen if f.L1.Kind, f.L1.Enum, f.L1.Message, err = r.findTarget(f.Kind(), f.Parent().FullName(), partialName(fd.GetTypeName()), f.IsWeak()); err != nil { 47*1c12ee1eSDan Willemsen return errors.New("message field %q cannot resolve type: %v", f.FullName(), err) 48*1c12ee1eSDan Willemsen } 49*1c12ee1eSDan Willemsen if fd.DefaultValue != nil { 50*1c12ee1eSDan Willemsen v, ev, err := unmarshalDefault(fd.GetDefaultValue(), f, r.allowUnresolvable) 51*1c12ee1eSDan Willemsen if err != nil { 52*1c12ee1eSDan Willemsen return errors.New("message field %q has invalid default: %v", f.FullName(), err) 53*1c12ee1eSDan Willemsen } 54*1c12ee1eSDan Willemsen f.L1.Default = filedesc.DefaultValue(v, ev) 55*1c12ee1eSDan Willemsen } 56*1c12ee1eSDan Willemsen } 57*1c12ee1eSDan Willemsen 58*1c12ee1eSDan Willemsen if err := r.resolveMessageDependencies(m.L1.Messages.List, md.GetNestedType()); err != nil { 59*1c12ee1eSDan Willemsen return err 60*1c12ee1eSDan Willemsen } 61*1c12ee1eSDan Willemsen if err := r.resolveExtensionDependencies(m.L1.Extensions.List, md.GetExtension()); err != nil { 62*1c12ee1eSDan Willemsen return err 63*1c12ee1eSDan Willemsen } 64*1c12ee1eSDan Willemsen } 65*1c12ee1eSDan Willemsen return nil 66*1c12ee1eSDan Willemsen} 67*1c12ee1eSDan Willemsen 68*1c12ee1eSDan Willemsenfunc (r *resolver) resolveExtensionDependencies(xs []filedesc.Extension, xds []*descriptorpb.FieldDescriptorProto) (err error) { 69*1c12ee1eSDan Willemsen for i, xd := range xds { 70*1c12ee1eSDan Willemsen x := &xs[i] 71*1c12ee1eSDan Willemsen if x.L1.Extendee, err = r.findMessageDescriptor(x.Parent().FullName(), partialName(xd.GetExtendee()), false); err != nil { 72*1c12ee1eSDan Willemsen return errors.New("extension field %q cannot resolve extendee: %v", x.FullName(), err) 73*1c12ee1eSDan Willemsen } 74*1c12ee1eSDan Willemsen if x.L1.Kind, x.L2.Enum, x.L2.Message, err = r.findTarget(x.Kind(), x.Parent().FullName(), partialName(xd.GetTypeName()), false); err != nil { 75*1c12ee1eSDan Willemsen return errors.New("extension field %q cannot resolve type: %v", x.FullName(), err) 76*1c12ee1eSDan Willemsen } 77*1c12ee1eSDan Willemsen if xd.DefaultValue != nil { 78*1c12ee1eSDan Willemsen v, ev, err := unmarshalDefault(xd.GetDefaultValue(), x, r.allowUnresolvable) 79*1c12ee1eSDan Willemsen if err != nil { 80*1c12ee1eSDan Willemsen return errors.New("extension field %q has invalid default: %v", x.FullName(), err) 81*1c12ee1eSDan Willemsen } 82*1c12ee1eSDan Willemsen x.L2.Default = filedesc.DefaultValue(v, ev) 83*1c12ee1eSDan Willemsen } 84*1c12ee1eSDan Willemsen } 85*1c12ee1eSDan Willemsen return nil 86*1c12ee1eSDan Willemsen} 87*1c12ee1eSDan Willemsen 88*1c12ee1eSDan Willemsenfunc (r *resolver) resolveServiceDependencies(ss []filedesc.Service, sds []*descriptorpb.ServiceDescriptorProto) (err error) { 89*1c12ee1eSDan Willemsen for i, sd := range sds { 90*1c12ee1eSDan Willemsen s := &ss[i] 91*1c12ee1eSDan Willemsen for j, md := range sd.GetMethod() { 92*1c12ee1eSDan Willemsen m := &s.L2.Methods.List[j] 93*1c12ee1eSDan Willemsen m.L1.Input, err = r.findMessageDescriptor(m.Parent().FullName(), partialName(md.GetInputType()), false) 94*1c12ee1eSDan Willemsen if err != nil { 95*1c12ee1eSDan Willemsen return errors.New("service method %q cannot resolve input: %v", m.FullName(), err) 96*1c12ee1eSDan Willemsen } 97*1c12ee1eSDan Willemsen m.L1.Output, err = r.findMessageDescriptor(s.FullName(), partialName(md.GetOutputType()), false) 98*1c12ee1eSDan Willemsen if err != nil { 99*1c12ee1eSDan Willemsen return errors.New("service method %q cannot resolve output: %v", m.FullName(), err) 100*1c12ee1eSDan Willemsen } 101*1c12ee1eSDan Willemsen } 102*1c12ee1eSDan Willemsen } 103*1c12ee1eSDan Willemsen return nil 104*1c12ee1eSDan Willemsen} 105*1c12ee1eSDan Willemsen 106*1c12ee1eSDan Willemsen// findTarget finds an enum or message descriptor if k is an enum, message, 107*1c12ee1eSDan Willemsen// group, or unknown. If unknown, and the name could be resolved, the kind 108*1c12ee1eSDan Willemsen// returned kind is set based on the type of the resolved descriptor. 109*1c12ee1eSDan Willemsenfunc (r *resolver) findTarget(k protoreflect.Kind, scope protoreflect.FullName, ref partialName, isWeak bool) (protoreflect.Kind, protoreflect.EnumDescriptor, protoreflect.MessageDescriptor, error) { 110*1c12ee1eSDan Willemsen switch k { 111*1c12ee1eSDan Willemsen case protoreflect.EnumKind: 112*1c12ee1eSDan Willemsen ed, err := r.findEnumDescriptor(scope, ref, isWeak) 113*1c12ee1eSDan Willemsen if err != nil { 114*1c12ee1eSDan Willemsen return 0, nil, nil, err 115*1c12ee1eSDan Willemsen } 116*1c12ee1eSDan Willemsen return k, ed, nil, nil 117*1c12ee1eSDan Willemsen case protoreflect.MessageKind, protoreflect.GroupKind: 118*1c12ee1eSDan Willemsen md, err := r.findMessageDescriptor(scope, ref, isWeak) 119*1c12ee1eSDan Willemsen if err != nil { 120*1c12ee1eSDan Willemsen return 0, nil, nil, err 121*1c12ee1eSDan Willemsen } 122*1c12ee1eSDan Willemsen return k, nil, md, nil 123*1c12ee1eSDan Willemsen case 0: 124*1c12ee1eSDan Willemsen // Handle unspecified kinds (possible with parsers that operate 125*1c12ee1eSDan Willemsen // on a per-file basis without knowledge of dependencies). 126*1c12ee1eSDan Willemsen d, err := r.findDescriptor(scope, ref) 127*1c12ee1eSDan Willemsen if err == protoregistry.NotFound && (r.allowUnresolvable || isWeak) { 128*1c12ee1eSDan Willemsen return k, filedesc.PlaceholderEnum(ref.FullName()), filedesc.PlaceholderMessage(ref.FullName()), nil 129*1c12ee1eSDan Willemsen } else if err == protoregistry.NotFound { 130*1c12ee1eSDan Willemsen return 0, nil, nil, errors.New("%q not found", ref.FullName()) 131*1c12ee1eSDan Willemsen } else if err != nil { 132*1c12ee1eSDan Willemsen return 0, nil, nil, err 133*1c12ee1eSDan Willemsen } 134*1c12ee1eSDan Willemsen switch d := d.(type) { 135*1c12ee1eSDan Willemsen case protoreflect.EnumDescriptor: 136*1c12ee1eSDan Willemsen return protoreflect.EnumKind, d, nil, nil 137*1c12ee1eSDan Willemsen case protoreflect.MessageDescriptor: 138*1c12ee1eSDan Willemsen return protoreflect.MessageKind, nil, d, nil 139*1c12ee1eSDan Willemsen default: 140*1c12ee1eSDan Willemsen return 0, nil, nil, errors.New("unknown kind") 141*1c12ee1eSDan Willemsen } 142*1c12ee1eSDan Willemsen default: 143*1c12ee1eSDan Willemsen if ref != "" { 144*1c12ee1eSDan Willemsen return 0, nil, nil, errors.New("target name cannot be specified for %v", k) 145*1c12ee1eSDan Willemsen } 146*1c12ee1eSDan Willemsen if !k.IsValid() { 147*1c12ee1eSDan Willemsen return 0, nil, nil, errors.New("invalid kind: %d", k) 148*1c12ee1eSDan Willemsen } 149*1c12ee1eSDan Willemsen return k, nil, nil, nil 150*1c12ee1eSDan Willemsen } 151*1c12ee1eSDan Willemsen} 152*1c12ee1eSDan Willemsen 153*1c12ee1eSDan Willemsen// findDescriptor finds the descriptor by name, 154*1c12ee1eSDan Willemsen// which may be a relative name within some scope. 155*1c12ee1eSDan Willemsen// 156*1c12ee1eSDan Willemsen// Suppose the scope was "fizz.buzz" and the reference was "Foo.Bar", 157*1c12ee1eSDan Willemsen// then the following full names are searched: 158*1c12ee1eSDan Willemsen// - fizz.buzz.Foo.Bar 159*1c12ee1eSDan Willemsen// - fizz.Foo.Bar 160*1c12ee1eSDan Willemsen// - Foo.Bar 161*1c12ee1eSDan Willemsenfunc (r *resolver) findDescriptor(scope protoreflect.FullName, ref partialName) (protoreflect.Descriptor, error) { 162*1c12ee1eSDan Willemsen if !ref.IsValid() { 163*1c12ee1eSDan Willemsen return nil, errors.New("invalid name reference: %q", ref) 164*1c12ee1eSDan Willemsen } 165*1c12ee1eSDan Willemsen if ref.IsFull() { 166*1c12ee1eSDan Willemsen scope, ref = "", ref[1:] 167*1c12ee1eSDan Willemsen } 168*1c12ee1eSDan Willemsen var foundButNotImported protoreflect.Descriptor 169*1c12ee1eSDan Willemsen for { 170*1c12ee1eSDan Willemsen // Derive the full name to search. 171*1c12ee1eSDan Willemsen s := protoreflect.FullName(ref) 172*1c12ee1eSDan Willemsen if scope != "" { 173*1c12ee1eSDan Willemsen s = scope + "." + s 174*1c12ee1eSDan Willemsen } 175*1c12ee1eSDan Willemsen 176*1c12ee1eSDan Willemsen // Check the current file for the descriptor. 177*1c12ee1eSDan Willemsen if d, ok := r.local[s]; ok { 178*1c12ee1eSDan Willemsen return d, nil 179*1c12ee1eSDan Willemsen } 180*1c12ee1eSDan Willemsen 181*1c12ee1eSDan Willemsen // Check the remote registry for the descriptor. 182*1c12ee1eSDan Willemsen d, err := r.remote.FindDescriptorByName(s) 183*1c12ee1eSDan Willemsen if err == nil { 184*1c12ee1eSDan Willemsen // Only allow descriptors covered by one of the imports. 185*1c12ee1eSDan Willemsen if r.imports[d.ParentFile().Path()] { 186*1c12ee1eSDan Willemsen return d, nil 187*1c12ee1eSDan Willemsen } 188*1c12ee1eSDan Willemsen foundButNotImported = d 189*1c12ee1eSDan Willemsen } else if err != protoregistry.NotFound { 190*1c12ee1eSDan Willemsen return nil, errors.Wrap(err, "%q", s) 191*1c12ee1eSDan Willemsen } 192*1c12ee1eSDan Willemsen 193*1c12ee1eSDan Willemsen // Continue on at a higher level of scoping. 194*1c12ee1eSDan Willemsen if scope == "" { 195*1c12ee1eSDan Willemsen if d := foundButNotImported; d != nil { 196*1c12ee1eSDan Willemsen return nil, errors.New("resolved %q, but %q is not imported", d.FullName(), d.ParentFile().Path()) 197*1c12ee1eSDan Willemsen } 198*1c12ee1eSDan Willemsen return nil, protoregistry.NotFound 199*1c12ee1eSDan Willemsen } 200*1c12ee1eSDan Willemsen scope = scope.Parent() 201*1c12ee1eSDan Willemsen } 202*1c12ee1eSDan Willemsen} 203*1c12ee1eSDan Willemsen 204*1c12ee1eSDan Willemsenfunc (r *resolver) findEnumDescriptor(scope protoreflect.FullName, ref partialName, isWeak bool) (protoreflect.EnumDescriptor, error) { 205*1c12ee1eSDan Willemsen d, err := r.findDescriptor(scope, ref) 206*1c12ee1eSDan Willemsen if err == protoregistry.NotFound && (r.allowUnresolvable || isWeak) { 207*1c12ee1eSDan Willemsen return filedesc.PlaceholderEnum(ref.FullName()), nil 208*1c12ee1eSDan Willemsen } else if err == protoregistry.NotFound { 209*1c12ee1eSDan Willemsen return nil, errors.New("%q not found", ref.FullName()) 210*1c12ee1eSDan Willemsen } else if err != nil { 211*1c12ee1eSDan Willemsen return nil, err 212*1c12ee1eSDan Willemsen } 213*1c12ee1eSDan Willemsen ed, ok := d.(protoreflect.EnumDescriptor) 214*1c12ee1eSDan Willemsen if !ok { 215*1c12ee1eSDan Willemsen return nil, errors.New("resolved %q, but it is not an enum", d.FullName()) 216*1c12ee1eSDan Willemsen } 217*1c12ee1eSDan Willemsen return ed, nil 218*1c12ee1eSDan Willemsen} 219*1c12ee1eSDan Willemsen 220*1c12ee1eSDan Willemsenfunc (r *resolver) findMessageDescriptor(scope protoreflect.FullName, ref partialName, isWeak bool) (protoreflect.MessageDescriptor, error) { 221*1c12ee1eSDan Willemsen d, err := r.findDescriptor(scope, ref) 222*1c12ee1eSDan Willemsen if err == protoregistry.NotFound && (r.allowUnresolvable || isWeak) { 223*1c12ee1eSDan Willemsen return filedesc.PlaceholderMessage(ref.FullName()), nil 224*1c12ee1eSDan Willemsen } else if err == protoregistry.NotFound { 225*1c12ee1eSDan Willemsen return nil, errors.New("%q not found", ref.FullName()) 226*1c12ee1eSDan Willemsen } else if err != nil { 227*1c12ee1eSDan Willemsen return nil, err 228*1c12ee1eSDan Willemsen } 229*1c12ee1eSDan Willemsen md, ok := d.(protoreflect.MessageDescriptor) 230*1c12ee1eSDan Willemsen if !ok { 231*1c12ee1eSDan Willemsen return nil, errors.New("resolved %q, but it is not an message", d.FullName()) 232*1c12ee1eSDan Willemsen } 233*1c12ee1eSDan Willemsen return md, nil 234*1c12ee1eSDan Willemsen} 235*1c12ee1eSDan Willemsen 236*1c12ee1eSDan Willemsen// partialName is the partial name. A leading dot means that the name is full, 237*1c12ee1eSDan Willemsen// otherwise the name is relative to some current scope. 238*1c12ee1eSDan Willemsen// See google.protobuf.FieldDescriptorProto.type_name. 239*1c12ee1eSDan Willemsentype partialName string 240*1c12ee1eSDan Willemsen 241*1c12ee1eSDan Willemsenfunc (s partialName) IsFull() bool { 242*1c12ee1eSDan Willemsen return len(s) > 0 && s[0] == '.' 243*1c12ee1eSDan Willemsen} 244*1c12ee1eSDan Willemsen 245*1c12ee1eSDan Willemsenfunc (s partialName) IsValid() bool { 246*1c12ee1eSDan Willemsen if s.IsFull() { 247*1c12ee1eSDan Willemsen return protoreflect.FullName(s[1:]).IsValid() 248*1c12ee1eSDan Willemsen } 249*1c12ee1eSDan Willemsen return protoreflect.FullName(s).IsValid() 250*1c12ee1eSDan Willemsen} 251*1c12ee1eSDan Willemsen 252*1c12ee1eSDan Willemsenconst unknownPrefix = "*." 253*1c12ee1eSDan Willemsen 254*1c12ee1eSDan Willemsen// FullName converts the partial name to a full name on a best-effort basis. 255*1c12ee1eSDan Willemsen// If relative, it creates an invalid full name, using a "*." prefix 256*1c12ee1eSDan Willemsen// to indicate that the start of the full name is unknown. 257*1c12ee1eSDan Willemsenfunc (s partialName) FullName() protoreflect.FullName { 258*1c12ee1eSDan Willemsen if s.IsFull() { 259*1c12ee1eSDan Willemsen return protoreflect.FullName(s[1:]) 260*1c12ee1eSDan Willemsen } 261*1c12ee1eSDan Willemsen return protoreflect.FullName(unknownPrefix + s) 262*1c12ee1eSDan Willemsen} 263*1c12ee1eSDan Willemsen 264*1c12ee1eSDan Willemsenfunc unmarshalDefault(s string, fd protoreflect.FieldDescriptor, allowUnresolvable bool) (protoreflect.Value, protoreflect.EnumValueDescriptor, error) { 265*1c12ee1eSDan Willemsen var evs protoreflect.EnumValueDescriptors 266*1c12ee1eSDan Willemsen if fd.Enum() != nil { 267*1c12ee1eSDan Willemsen evs = fd.Enum().Values() 268*1c12ee1eSDan Willemsen } 269*1c12ee1eSDan Willemsen v, ev, err := defval.Unmarshal(s, fd.Kind(), evs, defval.Descriptor) 270*1c12ee1eSDan Willemsen if err != nil && allowUnresolvable && evs != nil && protoreflect.Name(s).IsValid() { 271*1c12ee1eSDan Willemsen v = protoreflect.ValueOfEnum(0) 272*1c12ee1eSDan Willemsen if evs.Len() > 0 { 273*1c12ee1eSDan Willemsen v = protoreflect.ValueOfEnum(evs.Get(0).Number()) 274*1c12ee1eSDan Willemsen } 275*1c12ee1eSDan Willemsen ev = filedesc.PlaceholderEnumValue(fd.Enum().FullName().Parent().Append(protoreflect.Name(s))) 276*1c12ee1eSDan Willemsen } else if err != nil { 277*1c12ee1eSDan Willemsen return v, ev, err 278*1c12ee1eSDan Willemsen } 279*1c12ee1eSDan Willemsen if fd.Syntax() == protoreflect.Proto3 { 280*1c12ee1eSDan Willemsen return v, ev, errors.New("cannot be specified under proto3 semantics") 281*1c12ee1eSDan Willemsen } 282*1c12ee1eSDan Willemsen if fd.Kind() == protoreflect.MessageKind || fd.Kind() == protoreflect.GroupKind || fd.Cardinality() == protoreflect.Repeated { 283*1c12ee1eSDan Willemsen return v, ev, errors.New("cannot be specified on composite types") 284*1c12ee1eSDan Willemsen } 285*1c12ee1eSDan Willemsen return v, ev, nil 286*1c12ee1eSDan Willemsen} 287