blob: 43721543215a0f1046ba35932c9c8e0287a3f904 [file] [log] [blame]
Joe Tsai3274acc2019-06-29 00:05:22 -07001// Copyright 2019 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package protodesc
6
7import (
8 "strings"
9
10 "google.golang.org/protobuf/internal/encoding/defval"
11 "google.golang.org/protobuf/internal/errors"
12 "google.golang.org/protobuf/internal/filedesc"
13 "google.golang.org/protobuf/reflect/protoreflect"
14 "google.golang.org/protobuf/reflect/protoregistry"
15
16 "google.golang.org/protobuf/types/descriptorpb"
17)
18
19type resolver struct {
20 local descsByName
21 remote Resolver
22 imports importSet
23}
24
25func (r *resolver) resolveMessageDependencies(ms []filedesc.Message, mds []*descriptorpb.DescriptorProto) (err error) {
26 for i, md := range mds {
27 m := &ms[i]
28 for j, fd := range md.GetField() {
29 f := &m.L2.Fields.List[j]
30 if f.L1.Cardinality == protoreflect.Required {
31 m.L2.RequiredNumbers.List = append(m.L2.RequiredNumbers.List, f.L1.Number)
32 }
33 if fd.OneofIndex != nil {
34 k := int(fd.GetOneofIndex())
35 if k >= len(md.GetOneofDecl()) {
36 return errors.New("invalid oneof index: %d", k)
37 }
38 o := &m.L2.Oneofs.List[k]
39 f.L1.ContainingOneof = o
40 o.L1.Fields.List = append(o.L1.Fields.List, f)
41 }
42 switch f.L1.Kind {
43 case protoreflect.EnumKind:
44 ed, err := findEnumDescriptor(fd.GetTypeName(), f.L1.IsWeak, r)
45 if err != nil {
46 return err
47 }
48 f.L1.Enum = ed
49 case protoreflect.MessageKind, protoreflect.GroupKind:
50 md, err := findMessageDescriptor(fd.GetTypeName(), f.L1.IsWeak, r)
51 if err != nil {
52 return err
53 }
54 f.L1.Message = md
55 default:
56 if fd.GetTypeName() != "" {
57 return errors.New("field of kind %v has type_name set", f.L1.Kind)
58 }
59 }
60 if fd.DefaultValue != nil {
61 // Handle default value after resolving the enum since the
62 // list of enum values is needed to resolve enums by name.
63 var evs protoreflect.EnumValueDescriptors
64 if f.L1.Kind == protoreflect.EnumKind {
65 evs = f.L1.Enum.Values()
66 }
67 v, ev, err := defval.Unmarshal(fd.GetDefaultValue(), f.L1.Kind, evs, defval.Descriptor)
68 if err != nil {
69 return err
70 }
71 f.L1.Default = filedesc.DefaultValue(v, ev)
72 }
73 }
74
75 if err := r.resolveMessageDependencies(m.L1.Messages.List, md.GetNestedType()); err != nil {
76 return err
77 }
78 if err := r.resolveExtensionDependencies(m.L1.Extensions.List, md.GetExtension()); err != nil {
79 return err
80 }
81 }
82 return nil
83}
84
85func (r *resolver) resolveExtensionDependencies(xs []filedesc.Extension, xds []*descriptorpb.FieldDescriptorProto) error {
86 for i, xd := range xds {
87 x := &xs[i]
88 md, err := findMessageDescriptor(xd.GetExtendee(), false, r)
89 if err != nil {
90 return err
91 }
92 x.L1.Extendee = md
93 switch x.L1.Kind {
94 case protoreflect.EnumKind:
95 ed, err := findEnumDescriptor(xd.GetTypeName(), false, r)
96 if err != nil {
97 return err
98 }
99 x.L2.Enum = ed
100 case protoreflect.MessageKind, protoreflect.GroupKind:
101 md, err := findMessageDescriptor(xd.GetTypeName(), false, r)
102 if err != nil {
103 return err
104 }
105 x.L2.Message = md
106 default:
107 if xd.GetTypeName() != "" {
108 return errors.New("field of kind %v has type_name set", x.L1.Kind)
109 }
110 }
111 if xd.DefaultValue != nil {
112 // Handle default value after resolving the enum since the
113 // list of enum values is needed to resolve enums by name.
114 var evs protoreflect.EnumValueDescriptors
115 if x.L1.Kind == protoreflect.EnumKind {
116 evs = x.L2.Enum.Values()
117 }
118 v, ev, err := defval.Unmarshal(xd.GetDefaultValue(), x.L1.Kind, evs, defval.Descriptor)
119 if err != nil {
120 return err
121 }
122 x.L2.Default = filedesc.DefaultValue(v, ev)
123 }
124 }
125 return nil
126}
127
128func (r *resolver) resolveServiceDependencies(ss []filedesc.Service, sds []*descriptorpb.ServiceDescriptorProto) (err error) {
129 for i, sd := range sds {
130 s := &ss[i]
131 for j, md := range sd.GetMethod() {
132 m := &s.L2.Methods.List[j]
133 m.L1.Input, err = findMessageDescriptor(md.GetInputType(), false, r)
134 if err != nil {
135 return err
136 }
137 m.L1.Output, err = findMessageDescriptor(md.GetOutputType(), false, r)
138 if err != nil {
139 return err
140 }
141 }
142 }
143 return nil
144}
145
146// TODO: Should we allow relative names? The protoc compiler has emitted
147// absolute names for some time now. Requiring absolute names as an input
148// simplifies our implementation as we won't need to implement C++'s namespace
149// scoping rules.
150
151func (r resolver) FindFileByPath(s string) (protoreflect.FileDescriptor, error) {
152 return r.remote.FindFileByPath(s)
153}
154
155func (r resolver) FindDescriptorByName(s protoreflect.FullName) (protoreflect.Descriptor, error) {
156 if d, ok := r.local[s]; ok {
157 return d, nil
158 }
159 return r.remote.FindDescriptorByName(s)
160}
161
162func findEnumDescriptor(s string, isWeak bool, r *resolver) (protoreflect.EnumDescriptor, error) {
163 d, err := findDescriptor(s, isWeak, r)
164 if err != nil {
165 return nil, err
166 }
167 if ed, ok := d.(protoreflect.EnumDescriptor); ok {
168 if err == protoregistry.NotFound {
169 if isWeak {
170 return filedesc.PlaceholderEnum(protoreflect.FullName(s[1:])), nil
171 }
172 // TODO: This should be an error.
173 return filedesc.PlaceholderEnum(protoreflect.FullName(s[1:])), nil
174 // return nil, errors.New("could not resolve enum: %v", name)
175 }
176 return ed, nil
177 }
178 return nil, errors.New("invalid descriptor type")
179}
180
181func findMessageDescriptor(s string, isWeak bool, r *resolver) (protoreflect.MessageDescriptor, error) {
182 d, err := findDescriptor(s, isWeak, r)
183 if err != nil {
184 if err == protoregistry.NotFound {
185 if isWeak {
186 return filedesc.PlaceholderMessage(protoreflect.FullName(s[1:])), nil
187 }
188 // TODO: This should be an error.
189 return filedesc.PlaceholderMessage(protoreflect.FullName(s[1:])), nil
190 // return nil, errors.New("could not resolve enum: %v", name)
191 }
192 return nil, err
193 }
194 if md, ok := d.(protoreflect.MessageDescriptor); ok {
195 return md, nil
196 }
197 return nil, errors.New("invalid descriptor type")
198}
199
200func findDescriptor(s string, isWeak bool, r *resolver) (protoreflect.Descriptor, error) {
201 if !strings.HasPrefix(s, ".") {
202 return nil, errors.New("identifier name must be fully qualified with a leading dot: %v", s)
203 }
204 name := protoreflect.FullName(strings.TrimPrefix(s, "."))
205 d, err := r.FindDescriptorByName(name)
206 if err != nil {
207 return nil, err
208 }
209 if err := r.imports.check(d); err != nil {
210 return nil, err
211 }
212 return d, nil
213}