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/errors" 9*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/filedesc" 10*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/strs" 11*1c12ee1eSDan Willemsen "google.golang.org/protobuf/proto" 12*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoreflect" 13*1c12ee1eSDan Willemsen 14*1c12ee1eSDan Willemsen "google.golang.org/protobuf/types/descriptorpb" 15*1c12ee1eSDan Willemsen) 16*1c12ee1eSDan Willemsen 17*1c12ee1eSDan Willemsentype descsByName map[protoreflect.FullName]protoreflect.Descriptor 18*1c12ee1eSDan Willemsen 19*1c12ee1eSDan Willemsenfunc (r descsByName) initEnumDeclarations(eds []*descriptorpb.EnumDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (es []filedesc.Enum, err error) { 20*1c12ee1eSDan Willemsen es = make([]filedesc.Enum, len(eds)) // allocate up-front to ensure stable pointers 21*1c12ee1eSDan Willemsen for i, ed := range eds { 22*1c12ee1eSDan Willemsen e := &es[i] 23*1c12ee1eSDan Willemsen e.L2 = new(filedesc.EnumL2) 24*1c12ee1eSDan Willemsen if e.L0, err = r.makeBase(e, parent, ed.GetName(), i, sb); err != nil { 25*1c12ee1eSDan Willemsen return nil, err 26*1c12ee1eSDan Willemsen } 27*1c12ee1eSDan Willemsen if opts := ed.GetOptions(); opts != nil { 28*1c12ee1eSDan Willemsen opts = proto.Clone(opts).(*descriptorpb.EnumOptions) 29*1c12ee1eSDan Willemsen e.L2.Options = func() protoreflect.ProtoMessage { return opts } 30*1c12ee1eSDan Willemsen } 31*1c12ee1eSDan Willemsen for _, s := range ed.GetReservedName() { 32*1c12ee1eSDan Willemsen e.L2.ReservedNames.List = append(e.L2.ReservedNames.List, protoreflect.Name(s)) 33*1c12ee1eSDan Willemsen } 34*1c12ee1eSDan Willemsen for _, rr := range ed.GetReservedRange() { 35*1c12ee1eSDan Willemsen e.L2.ReservedRanges.List = append(e.L2.ReservedRanges.List, [2]protoreflect.EnumNumber{ 36*1c12ee1eSDan Willemsen protoreflect.EnumNumber(rr.GetStart()), 37*1c12ee1eSDan Willemsen protoreflect.EnumNumber(rr.GetEnd()), 38*1c12ee1eSDan Willemsen }) 39*1c12ee1eSDan Willemsen } 40*1c12ee1eSDan Willemsen if e.L2.Values.List, err = r.initEnumValuesFromDescriptorProto(ed.GetValue(), e, sb); err != nil { 41*1c12ee1eSDan Willemsen return nil, err 42*1c12ee1eSDan Willemsen } 43*1c12ee1eSDan Willemsen } 44*1c12ee1eSDan Willemsen return es, nil 45*1c12ee1eSDan Willemsen} 46*1c12ee1eSDan Willemsen 47*1c12ee1eSDan Willemsenfunc (r descsByName) initEnumValuesFromDescriptorProto(vds []*descriptorpb.EnumValueDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (vs []filedesc.EnumValue, err error) { 48*1c12ee1eSDan Willemsen vs = make([]filedesc.EnumValue, len(vds)) // allocate up-front to ensure stable pointers 49*1c12ee1eSDan Willemsen for i, vd := range vds { 50*1c12ee1eSDan Willemsen v := &vs[i] 51*1c12ee1eSDan Willemsen if v.L0, err = r.makeBase(v, parent, vd.GetName(), i, sb); err != nil { 52*1c12ee1eSDan Willemsen return nil, err 53*1c12ee1eSDan Willemsen } 54*1c12ee1eSDan Willemsen if opts := vd.GetOptions(); opts != nil { 55*1c12ee1eSDan Willemsen opts = proto.Clone(opts).(*descriptorpb.EnumValueOptions) 56*1c12ee1eSDan Willemsen v.L1.Options = func() protoreflect.ProtoMessage { return opts } 57*1c12ee1eSDan Willemsen } 58*1c12ee1eSDan Willemsen v.L1.Number = protoreflect.EnumNumber(vd.GetNumber()) 59*1c12ee1eSDan Willemsen } 60*1c12ee1eSDan Willemsen return vs, nil 61*1c12ee1eSDan Willemsen} 62*1c12ee1eSDan Willemsen 63*1c12ee1eSDan Willemsenfunc (r descsByName) initMessagesDeclarations(mds []*descriptorpb.DescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (ms []filedesc.Message, err error) { 64*1c12ee1eSDan Willemsen ms = make([]filedesc.Message, len(mds)) // allocate up-front to ensure stable pointers 65*1c12ee1eSDan Willemsen for i, md := range mds { 66*1c12ee1eSDan Willemsen m := &ms[i] 67*1c12ee1eSDan Willemsen m.L2 = new(filedesc.MessageL2) 68*1c12ee1eSDan Willemsen if m.L0, err = r.makeBase(m, parent, md.GetName(), i, sb); err != nil { 69*1c12ee1eSDan Willemsen return nil, err 70*1c12ee1eSDan Willemsen } 71*1c12ee1eSDan Willemsen if opts := md.GetOptions(); opts != nil { 72*1c12ee1eSDan Willemsen opts = proto.Clone(opts).(*descriptorpb.MessageOptions) 73*1c12ee1eSDan Willemsen m.L2.Options = func() protoreflect.ProtoMessage { return opts } 74*1c12ee1eSDan Willemsen m.L1.IsMapEntry = opts.GetMapEntry() 75*1c12ee1eSDan Willemsen m.L1.IsMessageSet = opts.GetMessageSetWireFormat() 76*1c12ee1eSDan Willemsen } 77*1c12ee1eSDan Willemsen for _, s := range md.GetReservedName() { 78*1c12ee1eSDan Willemsen m.L2.ReservedNames.List = append(m.L2.ReservedNames.List, protoreflect.Name(s)) 79*1c12ee1eSDan Willemsen } 80*1c12ee1eSDan Willemsen for _, rr := range md.GetReservedRange() { 81*1c12ee1eSDan Willemsen m.L2.ReservedRanges.List = append(m.L2.ReservedRanges.List, [2]protoreflect.FieldNumber{ 82*1c12ee1eSDan Willemsen protoreflect.FieldNumber(rr.GetStart()), 83*1c12ee1eSDan Willemsen protoreflect.FieldNumber(rr.GetEnd()), 84*1c12ee1eSDan Willemsen }) 85*1c12ee1eSDan Willemsen } 86*1c12ee1eSDan Willemsen for _, xr := range md.GetExtensionRange() { 87*1c12ee1eSDan Willemsen m.L2.ExtensionRanges.List = append(m.L2.ExtensionRanges.List, [2]protoreflect.FieldNumber{ 88*1c12ee1eSDan Willemsen protoreflect.FieldNumber(xr.GetStart()), 89*1c12ee1eSDan Willemsen protoreflect.FieldNumber(xr.GetEnd()), 90*1c12ee1eSDan Willemsen }) 91*1c12ee1eSDan Willemsen var optsFunc func() protoreflect.ProtoMessage 92*1c12ee1eSDan Willemsen if opts := xr.GetOptions(); opts != nil { 93*1c12ee1eSDan Willemsen opts = proto.Clone(opts).(*descriptorpb.ExtensionRangeOptions) 94*1c12ee1eSDan Willemsen optsFunc = func() protoreflect.ProtoMessage { return opts } 95*1c12ee1eSDan Willemsen } 96*1c12ee1eSDan Willemsen m.L2.ExtensionRangeOptions = append(m.L2.ExtensionRangeOptions, optsFunc) 97*1c12ee1eSDan Willemsen } 98*1c12ee1eSDan Willemsen if m.L2.Fields.List, err = r.initFieldsFromDescriptorProto(md.GetField(), m, sb); err != nil { 99*1c12ee1eSDan Willemsen return nil, err 100*1c12ee1eSDan Willemsen } 101*1c12ee1eSDan Willemsen if m.L2.Oneofs.List, err = r.initOneofsFromDescriptorProto(md.GetOneofDecl(), m, sb); err != nil { 102*1c12ee1eSDan Willemsen return nil, err 103*1c12ee1eSDan Willemsen } 104*1c12ee1eSDan Willemsen if m.L1.Enums.List, err = r.initEnumDeclarations(md.GetEnumType(), m, sb); err != nil { 105*1c12ee1eSDan Willemsen return nil, err 106*1c12ee1eSDan Willemsen } 107*1c12ee1eSDan Willemsen if m.L1.Messages.List, err = r.initMessagesDeclarations(md.GetNestedType(), m, sb); err != nil { 108*1c12ee1eSDan Willemsen return nil, err 109*1c12ee1eSDan Willemsen } 110*1c12ee1eSDan Willemsen if m.L1.Extensions.List, err = r.initExtensionDeclarations(md.GetExtension(), m, sb); err != nil { 111*1c12ee1eSDan Willemsen return nil, err 112*1c12ee1eSDan Willemsen } 113*1c12ee1eSDan Willemsen } 114*1c12ee1eSDan Willemsen return ms, nil 115*1c12ee1eSDan Willemsen} 116*1c12ee1eSDan Willemsen 117*1c12ee1eSDan Willemsenfunc (r descsByName) initFieldsFromDescriptorProto(fds []*descriptorpb.FieldDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (fs []filedesc.Field, err error) { 118*1c12ee1eSDan Willemsen fs = make([]filedesc.Field, len(fds)) // allocate up-front to ensure stable pointers 119*1c12ee1eSDan Willemsen for i, fd := range fds { 120*1c12ee1eSDan Willemsen f := &fs[i] 121*1c12ee1eSDan Willemsen if f.L0, err = r.makeBase(f, parent, fd.GetName(), i, sb); err != nil { 122*1c12ee1eSDan Willemsen return nil, err 123*1c12ee1eSDan Willemsen } 124*1c12ee1eSDan Willemsen f.L1.IsProto3Optional = fd.GetProto3Optional() 125*1c12ee1eSDan Willemsen if opts := fd.GetOptions(); opts != nil { 126*1c12ee1eSDan Willemsen opts = proto.Clone(opts).(*descriptorpb.FieldOptions) 127*1c12ee1eSDan Willemsen f.L1.Options = func() protoreflect.ProtoMessage { return opts } 128*1c12ee1eSDan Willemsen f.L1.IsWeak = opts.GetWeak() 129*1c12ee1eSDan Willemsen f.L1.HasPacked = opts.Packed != nil 130*1c12ee1eSDan Willemsen f.L1.IsPacked = opts.GetPacked() 131*1c12ee1eSDan Willemsen } 132*1c12ee1eSDan Willemsen f.L1.Number = protoreflect.FieldNumber(fd.GetNumber()) 133*1c12ee1eSDan Willemsen f.L1.Cardinality = protoreflect.Cardinality(fd.GetLabel()) 134*1c12ee1eSDan Willemsen if fd.Type != nil { 135*1c12ee1eSDan Willemsen f.L1.Kind = protoreflect.Kind(fd.GetType()) 136*1c12ee1eSDan Willemsen } 137*1c12ee1eSDan Willemsen if fd.JsonName != nil { 138*1c12ee1eSDan Willemsen f.L1.StringName.InitJSON(fd.GetJsonName()) 139*1c12ee1eSDan Willemsen } 140*1c12ee1eSDan Willemsen } 141*1c12ee1eSDan Willemsen return fs, nil 142*1c12ee1eSDan Willemsen} 143*1c12ee1eSDan Willemsen 144*1c12ee1eSDan Willemsenfunc (r descsByName) initOneofsFromDescriptorProto(ods []*descriptorpb.OneofDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (os []filedesc.Oneof, err error) { 145*1c12ee1eSDan Willemsen os = make([]filedesc.Oneof, len(ods)) // allocate up-front to ensure stable pointers 146*1c12ee1eSDan Willemsen for i, od := range ods { 147*1c12ee1eSDan Willemsen o := &os[i] 148*1c12ee1eSDan Willemsen if o.L0, err = r.makeBase(o, parent, od.GetName(), i, sb); err != nil { 149*1c12ee1eSDan Willemsen return nil, err 150*1c12ee1eSDan Willemsen } 151*1c12ee1eSDan Willemsen if opts := od.GetOptions(); opts != nil { 152*1c12ee1eSDan Willemsen opts = proto.Clone(opts).(*descriptorpb.OneofOptions) 153*1c12ee1eSDan Willemsen o.L1.Options = func() protoreflect.ProtoMessage { return opts } 154*1c12ee1eSDan Willemsen } 155*1c12ee1eSDan Willemsen } 156*1c12ee1eSDan Willemsen return os, nil 157*1c12ee1eSDan Willemsen} 158*1c12ee1eSDan Willemsen 159*1c12ee1eSDan Willemsenfunc (r descsByName) initExtensionDeclarations(xds []*descriptorpb.FieldDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (xs []filedesc.Extension, err error) { 160*1c12ee1eSDan Willemsen xs = make([]filedesc.Extension, len(xds)) // allocate up-front to ensure stable pointers 161*1c12ee1eSDan Willemsen for i, xd := range xds { 162*1c12ee1eSDan Willemsen x := &xs[i] 163*1c12ee1eSDan Willemsen x.L2 = new(filedesc.ExtensionL2) 164*1c12ee1eSDan Willemsen if x.L0, err = r.makeBase(x, parent, xd.GetName(), i, sb); err != nil { 165*1c12ee1eSDan Willemsen return nil, err 166*1c12ee1eSDan Willemsen } 167*1c12ee1eSDan Willemsen if opts := xd.GetOptions(); opts != nil { 168*1c12ee1eSDan Willemsen opts = proto.Clone(opts).(*descriptorpb.FieldOptions) 169*1c12ee1eSDan Willemsen x.L2.Options = func() protoreflect.ProtoMessage { return opts } 170*1c12ee1eSDan Willemsen x.L2.IsPacked = opts.GetPacked() 171*1c12ee1eSDan Willemsen } 172*1c12ee1eSDan Willemsen x.L1.Number = protoreflect.FieldNumber(xd.GetNumber()) 173*1c12ee1eSDan Willemsen x.L1.Cardinality = protoreflect.Cardinality(xd.GetLabel()) 174*1c12ee1eSDan Willemsen if xd.Type != nil { 175*1c12ee1eSDan Willemsen x.L1.Kind = protoreflect.Kind(xd.GetType()) 176*1c12ee1eSDan Willemsen } 177*1c12ee1eSDan Willemsen if xd.JsonName != nil { 178*1c12ee1eSDan Willemsen x.L2.StringName.InitJSON(xd.GetJsonName()) 179*1c12ee1eSDan Willemsen } 180*1c12ee1eSDan Willemsen } 181*1c12ee1eSDan Willemsen return xs, nil 182*1c12ee1eSDan Willemsen} 183*1c12ee1eSDan Willemsen 184*1c12ee1eSDan Willemsenfunc (r descsByName) initServiceDeclarations(sds []*descriptorpb.ServiceDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (ss []filedesc.Service, err error) { 185*1c12ee1eSDan Willemsen ss = make([]filedesc.Service, len(sds)) // allocate up-front to ensure stable pointers 186*1c12ee1eSDan Willemsen for i, sd := range sds { 187*1c12ee1eSDan Willemsen s := &ss[i] 188*1c12ee1eSDan Willemsen s.L2 = new(filedesc.ServiceL2) 189*1c12ee1eSDan Willemsen if s.L0, err = r.makeBase(s, parent, sd.GetName(), i, sb); err != nil { 190*1c12ee1eSDan Willemsen return nil, err 191*1c12ee1eSDan Willemsen } 192*1c12ee1eSDan Willemsen if opts := sd.GetOptions(); opts != nil { 193*1c12ee1eSDan Willemsen opts = proto.Clone(opts).(*descriptorpb.ServiceOptions) 194*1c12ee1eSDan Willemsen s.L2.Options = func() protoreflect.ProtoMessage { return opts } 195*1c12ee1eSDan Willemsen } 196*1c12ee1eSDan Willemsen if s.L2.Methods.List, err = r.initMethodsFromDescriptorProto(sd.GetMethod(), s, sb); err != nil { 197*1c12ee1eSDan Willemsen return nil, err 198*1c12ee1eSDan Willemsen } 199*1c12ee1eSDan Willemsen } 200*1c12ee1eSDan Willemsen return ss, nil 201*1c12ee1eSDan Willemsen} 202*1c12ee1eSDan Willemsen 203*1c12ee1eSDan Willemsenfunc (r descsByName) initMethodsFromDescriptorProto(mds []*descriptorpb.MethodDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (ms []filedesc.Method, err error) { 204*1c12ee1eSDan Willemsen ms = make([]filedesc.Method, len(mds)) // allocate up-front to ensure stable pointers 205*1c12ee1eSDan Willemsen for i, md := range mds { 206*1c12ee1eSDan Willemsen m := &ms[i] 207*1c12ee1eSDan Willemsen if m.L0, err = r.makeBase(m, parent, md.GetName(), i, sb); err != nil { 208*1c12ee1eSDan Willemsen return nil, err 209*1c12ee1eSDan Willemsen } 210*1c12ee1eSDan Willemsen if opts := md.GetOptions(); opts != nil { 211*1c12ee1eSDan Willemsen opts = proto.Clone(opts).(*descriptorpb.MethodOptions) 212*1c12ee1eSDan Willemsen m.L1.Options = func() protoreflect.ProtoMessage { return opts } 213*1c12ee1eSDan Willemsen } 214*1c12ee1eSDan Willemsen m.L1.IsStreamingClient = md.GetClientStreaming() 215*1c12ee1eSDan Willemsen m.L1.IsStreamingServer = md.GetServerStreaming() 216*1c12ee1eSDan Willemsen } 217*1c12ee1eSDan Willemsen return ms, nil 218*1c12ee1eSDan Willemsen} 219*1c12ee1eSDan Willemsen 220*1c12ee1eSDan Willemsenfunc (r descsByName) makeBase(child, parent protoreflect.Descriptor, name string, idx int, sb *strs.Builder) (filedesc.BaseL0, error) { 221*1c12ee1eSDan Willemsen if !protoreflect.Name(name).IsValid() { 222*1c12ee1eSDan Willemsen return filedesc.BaseL0{}, errors.New("descriptor %q has an invalid nested name: %q", parent.FullName(), name) 223*1c12ee1eSDan Willemsen } 224*1c12ee1eSDan Willemsen 225*1c12ee1eSDan Willemsen // Derive the full name of the child. 226*1c12ee1eSDan Willemsen // Note that enum values are a sibling to the enum parent in the namespace. 227*1c12ee1eSDan Willemsen var fullName protoreflect.FullName 228*1c12ee1eSDan Willemsen if _, ok := parent.(protoreflect.EnumDescriptor); ok { 229*1c12ee1eSDan Willemsen fullName = sb.AppendFullName(parent.FullName().Parent(), protoreflect.Name(name)) 230*1c12ee1eSDan Willemsen } else { 231*1c12ee1eSDan Willemsen fullName = sb.AppendFullName(parent.FullName(), protoreflect.Name(name)) 232*1c12ee1eSDan Willemsen } 233*1c12ee1eSDan Willemsen if _, ok := r[fullName]; ok { 234*1c12ee1eSDan Willemsen return filedesc.BaseL0{}, errors.New("descriptor %q already declared", fullName) 235*1c12ee1eSDan Willemsen } 236*1c12ee1eSDan Willemsen r[fullName] = child 237*1c12ee1eSDan Willemsen 238*1c12ee1eSDan Willemsen // TODO: Verify that the full name does not already exist in the resolver? 239*1c12ee1eSDan Willemsen // This is not as critical since most usages of NewFile will register 240*1c12ee1eSDan Willemsen // the created file back into the registry, which will perform this check. 241*1c12ee1eSDan Willemsen 242*1c12ee1eSDan Willemsen return filedesc.BaseL0{ 243*1c12ee1eSDan Willemsen FullName: fullName, 244*1c12ee1eSDan Willemsen ParentFile: parent.ParentFile().(*filedesc.File), 245*1c12ee1eSDan Willemsen Parent: parent, 246*1c12ee1eSDan Willemsen Index: idx, 247*1c12ee1eSDan Willemsen }, nil 248*1c12ee1eSDan Willemsen} 249