blob: a990f4fae956d08195a36c35cce22059a4ffb1ec [file] [log] [blame]
Zack Williamse940c7a2019-08-21 14:25:39 -07001package protoparse
2
3import (
4 "bytes"
5 "fmt"
6 "sort"
7 "strings"
8
9 "github.com/golang/protobuf/proto"
10 dpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
11
12 "github.com/jhump/protoreflect/desc"
13 "github.com/jhump/protoreflect/desc/internal"
14)
15
16type linker struct {
17 files map[string]*parseResult
Scott Baker4a35a702019-11-26 08:17:33 -080018 filenames []string
19 errs *errorHandler
Zack Williamse940c7a2019-08-21 14:25:39 -070020 descriptorPool map[*dpb.FileDescriptorProto]map[string]proto.Message
21 extensions map[string]map[int32]string
22}
23
Scott Baker4a35a702019-11-26 08:17:33 -080024func newLinker(files *parseResults, errs *errorHandler) *linker {
25 return &linker{files: files.resultsByFilename, filenames: files.filenames, errs: errs}
Zack Williamse940c7a2019-08-21 14:25:39 -070026}
27
28func (l *linker) linkFiles() (map[string]*desc.FileDescriptor, error) {
29 // First, we put all symbols into a single pool, which lets us ensure there
30 // are no duplicate symbols and will also let us resolve and revise all type
31 // references in next step.
32 if err := l.createDescriptorPool(); err != nil {
33 return nil, err
34 }
35
36 // After we've populated the pool, we can now try to resolve all type
37 // references. All references must be checked for correct type, any fields
38 // with enum types must be corrected (since we parse them as if they are
39 // message references since we don't actually know message or enum until
40 // link time), and references will be re-written to be fully-qualified
41 // references (e.g. start with a dot ".").
42 if err := l.resolveReferences(); err != nil {
43 return nil, err
44 }
45
Scott Baker4a35a702019-11-26 08:17:33 -080046 if err := l.errs.getError(); err != nil {
47 // we won't be able to create real descriptors if we've encountered
48 // errors up to this point, so bail at this point
49 return nil, err
50 }
51
Zack Williamse940c7a2019-08-21 14:25:39 -070052 // Now we've validated the descriptors, so we can link them into rich
53 // descriptors. This is a little redundant since that step does similar
54 // checking of symbols. But, without breaking encapsulation (e.g. exporting
55 // a lot of fields from desc package that are currently unexported) or
56 // merging this into the same package, we can't really prevent it.
57 linked, err := l.createdLinkedDescriptors()
58 if err != nil {
59 return nil, err
60 }
61
62 // Now that we have linked descriptors, we can interpret any uninterpreted
63 // options that remain.
64 for _, r := range l.files {
65 fd := linked[r.fd.GetName()]
66 if err := interpretFileOptions(r, richFileDescriptorish{FileDescriptor: fd}); err != nil {
67 return nil, err
68 }
69 }
70
71 return linked, nil
72}
73
74func (l *linker) createDescriptorPool() error {
75 l.descriptorPool = map[*dpb.FileDescriptorProto]map[string]proto.Message{}
Scott Baker4a35a702019-11-26 08:17:33 -080076 for _, filename := range l.filenames {
77 r := l.files[filename]
Zack Williamse940c7a2019-08-21 14:25:39 -070078 fd := r.fd
79 pool := map[string]proto.Message{}
80 l.descriptorPool[fd] = pool
81 prefix := fd.GetPackage()
82 if prefix != "" {
83 prefix += "."
84 }
85 for _, md := range fd.MessageType {
Scott Baker4a35a702019-11-26 08:17:33 -080086 if err := addMessageToPool(r, pool, l.errs, prefix, md); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -070087 return err
88 }
89 }
90 for _, fld := range fd.Extension {
Scott Baker4a35a702019-11-26 08:17:33 -080091 if err := addFieldToPool(r, pool, l.errs, prefix, fld); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -070092 return err
93 }
94 }
95 for _, ed := range fd.EnumType {
Scott Baker4a35a702019-11-26 08:17:33 -080096 if err := addEnumToPool(r, pool, l.errs, prefix, ed); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -070097 return err
98 }
99 }
100 for _, sd := range fd.Service {
Scott Baker4a35a702019-11-26 08:17:33 -0800101 if err := addServiceToPool(r, pool, l.errs, prefix, sd); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -0700102 return err
103 }
104 }
105 }
106 // try putting everything into a single pool, to ensure there are no duplicates
107 // across files (e.g. same symbol, but declared in two different files)
108 type entry struct {
109 file string
110 msg proto.Message
111 }
112 pool := map[string]entry{}
Scott Baker4a35a702019-11-26 08:17:33 -0800113 for _, filename := range l.filenames {
114 f := l.files[filename].fd
115 p := l.descriptorPool[f]
116 keys := make([]string, 0, len(p))
117 for k := range p {
118 keys = append(keys, k)
119 }
120 sort.Strings(keys) // for deterministic error reporting
121 for _, k := range keys {
122 v := p[k]
Zack Williamse940c7a2019-08-21 14:25:39 -0700123 if e, ok := pool[k]; ok {
124 desc1 := e.msg
125 file1 := e.file
126 desc2 := v
127 file2 := f.GetName()
128 if file2 < file1 {
129 file1, file2 = file2, file1
130 desc1, desc2 = desc2, desc1
131 }
132 node := l.files[file2].nodes[desc2]
Scott Baker4a35a702019-11-26 08:17:33 -0800133 if err := l.errs.handleError(ErrorWithSourcePos{Pos: node.start(), Underlying: fmt.Errorf("duplicate symbol %s: already defined as %s in %q", k, descriptorType(desc1), file1)}); err != nil {
134 return err
135 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700136 }
137 pool[k] = entry{file: f.GetName(), msg: v}
138 }
139 }
140
141 return nil
142}
143
Scott Baker4a35a702019-11-26 08:17:33 -0800144func addMessageToPool(r *parseResult, pool map[string]proto.Message, errs *errorHandler, prefix string, md *dpb.DescriptorProto) error {
Zack Williamse940c7a2019-08-21 14:25:39 -0700145 fqn := prefix + md.GetName()
Scott Baker4a35a702019-11-26 08:17:33 -0800146 if err := addToPool(r, pool, errs, fqn, md); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -0700147 return err
148 }
149 prefix = fqn + "."
150 for _, fld := range md.Field {
Scott Baker4a35a702019-11-26 08:17:33 -0800151 if err := addFieldToPool(r, pool, errs, prefix, fld); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -0700152 return err
153 }
154 }
155 for _, fld := range md.Extension {
Scott Baker4a35a702019-11-26 08:17:33 -0800156 if err := addFieldToPool(r, pool, errs, prefix, fld); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -0700157 return err
158 }
159 }
160 for _, nmd := range md.NestedType {
Scott Baker4a35a702019-11-26 08:17:33 -0800161 if err := addMessageToPool(r, pool, errs, prefix, nmd); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -0700162 return err
163 }
164 }
165 for _, ed := range md.EnumType {
Scott Baker4a35a702019-11-26 08:17:33 -0800166 if err := addEnumToPool(r, pool, errs, prefix, ed); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -0700167 return err
168 }
169 }
170 return nil
171}
172
Scott Baker4a35a702019-11-26 08:17:33 -0800173func addFieldToPool(r *parseResult, pool map[string]proto.Message, errs *errorHandler, prefix string, fld *dpb.FieldDescriptorProto) error {
Zack Williamse940c7a2019-08-21 14:25:39 -0700174 fqn := prefix + fld.GetName()
Scott Baker4a35a702019-11-26 08:17:33 -0800175 return addToPool(r, pool, errs, fqn, fld)
Zack Williamse940c7a2019-08-21 14:25:39 -0700176}
177
Scott Baker4a35a702019-11-26 08:17:33 -0800178func addEnumToPool(r *parseResult, pool map[string]proto.Message, errs *errorHandler, prefix string, ed *dpb.EnumDescriptorProto) error {
Zack Williamse940c7a2019-08-21 14:25:39 -0700179 fqn := prefix + ed.GetName()
Scott Baker4a35a702019-11-26 08:17:33 -0800180 if err := addToPool(r, pool, errs, fqn, ed); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -0700181 return err
182 }
183 for _, evd := range ed.Value {
184 vfqn := fqn + "." + evd.GetName()
Scott Baker4a35a702019-11-26 08:17:33 -0800185 if err := addToPool(r, pool, errs, vfqn, evd); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -0700186 return err
187 }
188 }
189 return nil
190}
191
Scott Baker4a35a702019-11-26 08:17:33 -0800192func addServiceToPool(r *parseResult, pool map[string]proto.Message, errs *errorHandler, prefix string, sd *dpb.ServiceDescriptorProto) error {
Zack Williamse940c7a2019-08-21 14:25:39 -0700193 fqn := prefix + sd.GetName()
Scott Baker4a35a702019-11-26 08:17:33 -0800194 if err := addToPool(r, pool, errs, fqn, sd); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -0700195 return err
196 }
197 for _, mtd := range sd.Method {
198 mfqn := fqn + "." + mtd.GetName()
Scott Baker4a35a702019-11-26 08:17:33 -0800199 if err := addToPool(r, pool, errs, mfqn, mtd); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -0700200 return err
201 }
202 }
203 return nil
204}
205
Scott Baker4a35a702019-11-26 08:17:33 -0800206func addToPool(r *parseResult, pool map[string]proto.Message, errs *errorHandler, fqn string, dsc proto.Message) error {
Zack Williamse940c7a2019-08-21 14:25:39 -0700207 if d, ok := pool[fqn]; ok {
208 node := r.nodes[dsc]
Scott Baker4a35a702019-11-26 08:17:33 -0800209 if err := errs.handleError(ErrorWithSourcePos{Pos: node.start(), Underlying: fmt.Errorf("duplicate symbol %s: already defined as %s", fqn, descriptorType(d))}); err != nil {
210 return err
211 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700212 }
213 pool[fqn] = dsc
214 return nil
215}
216
217func descriptorType(m proto.Message) string {
218 switch m := m.(type) {
219 case *dpb.DescriptorProto:
220 return "message"
221 case *dpb.DescriptorProto_ExtensionRange:
222 return "extension range"
223 case *dpb.FieldDescriptorProto:
224 if m.GetExtendee() == "" {
225 return "field"
226 } else {
227 return "extension"
228 }
229 case *dpb.EnumDescriptorProto:
230 return "enum"
231 case *dpb.EnumValueDescriptorProto:
232 return "enum value"
233 case *dpb.ServiceDescriptorProto:
234 return "service"
235 case *dpb.MethodDescriptorProto:
236 return "method"
237 case *dpb.FileDescriptorProto:
238 return "file"
239 default:
240 // shouldn't be possible
241 return fmt.Sprintf("%T", m)
242 }
243}
244
245func (l *linker) resolveReferences() error {
246 l.extensions = map[string]map[int32]string{}
Scott Baker4a35a702019-11-26 08:17:33 -0800247 for _, filename := range l.filenames {
248 r := l.files[filename]
Zack Williamse940c7a2019-08-21 14:25:39 -0700249 fd := r.fd
250 prefix := fd.GetPackage()
251 scopes := []scope{fileScope(fd, l)}
252 if prefix != "" {
253 prefix += "."
254 }
255 if fd.Options != nil {
256 if err := l.resolveOptions(r, fd, "file", fd.GetName(), proto.MessageName(fd.Options), fd.Options.UninterpretedOption, scopes); err != nil {
257 return err
258 }
259 }
260 for _, md := range fd.MessageType {
261 if err := l.resolveMessageTypes(r, fd, prefix, md, scopes); err != nil {
262 return err
263 }
264 }
265 for _, fld := range fd.Extension {
266 if err := l.resolveFieldTypes(r, fd, prefix, fld, scopes); err != nil {
267 return err
268 }
269 }
270 for _, ed := range fd.EnumType {
271 if err := l.resolveEnumTypes(r, fd, prefix, ed, scopes); err != nil {
272 return err
273 }
274 }
275 for _, sd := range fd.Service {
276 if err := l.resolveServiceTypes(r, fd, prefix, sd, scopes); err != nil {
277 return err
278 }
279 }
280 }
281 return nil
282}
283
284func (l *linker) resolveEnumTypes(r *parseResult, fd *dpb.FileDescriptorProto, prefix string, ed *dpb.EnumDescriptorProto, scopes []scope) error {
285 enumFqn := prefix + ed.GetName()
286 if ed.Options != nil {
287 if err := l.resolveOptions(r, fd, "enum", enumFqn, proto.MessageName(ed.Options), ed.Options.UninterpretedOption, scopes); err != nil {
288 return err
289 }
290 }
291 for _, evd := range ed.Value {
292 if evd.Options != nil {
293 evFqn := enumFqn + "." + evd.GetName()
294 if err := l.resolveOptions(r, fd, "enum value", evFqn, proto.MessageName(evd.Options), evd.Options.UninterpretedOption, scopes); err != nil {
295 return err
296 }
297 }
298 }
299 return nil
300}
301
302func (l *linker) resolveMessageTypes(r *parseResult, fd *dpb.FileDescriptorProto, prefix string, md *dpb.DescriptorProto, scopes []scope) error {
303 fqn := prefix + md.GetName()
304 scope := messageScope(fqn, isProto3(fd), l.descriptorPool[fd])
305 scopes = append(scopes, scope)
306 prefix = fqn + "."
307
308 if md.Options != nil {
309 if err := l.resolveOptions(r, fd, "message", fqn, proto.MessageName(md.Options), md.Options.UninterpretedOption, scopes); err != nil {
310 return err
311 }
312 }
313
314 for _, nmd := range md.NestedType {
315 if err := l.resolveMessageTypes(r, fd, prefix, nmd, scopes); err != nil {
316 return err
317 }
318 }
319 for _, ned := range md.EnumType {
320 if err := l.resolveEnumTypes(r, fd, prefix, ned, scopes); err != nil {
321 return err
322 }
323 }
324 for _, fld := range md.Field {
325 if err := l.resolveFieldTypes(r, fd, prefix, fld, scopes); err != nil {
326 return err
327 }
328 }
329 for _, fld := range md.Extension {
330 if err := l.resolveFieldTypes(r, fd, prefix, fld, scopes); err != nil {
331 return err
332 }
333 }
334 for _, er := range md.ExtensionRange {
335 if er.Options != nil {
336 erName := fmt.Sprintf("%s:%d-%d", fqn, er.GetStart(), er.GetEnd()-1)
337 if err := l.resolveOptions(r, fd, "extension range", erName, proto.MessageName(er.Options), er.Options.UninterpretedOption, scopes); err != nil {
338 return err
339 }
340 }
341 }
342 return nil
343}
344
345func (l *linker) resolveFieldTypes(r *parseResult, fd *dpb.FileDescriptorProto, prefix string, fld *dpb.FieldDescriptorProto, scopes []scope) error {
346 thisName := prefix + fld.GetName()
347 scope := fmt.Sprintf("field %s", thisName)
348 node := r.getFieldNode(fld)
349 elemType := "field"
350 if fld.GetExtendee() != "" {
Scott Baker4a35a702019-11-26 08:17:33 -0800351 elemType = "extension"
Zack Williamse940c7a2019-08-21 14:25:39 -0700352 fqn, dsc, _ := l.resolve(fd, fld.GetExtendee(), isMessage, scopes)
353 if dsc == nil {
Scott Baker4a35a702019-11-26 08:17:33 -0800354 return l.errs.handleError(ErrorWithSourcePos{Pos: node.fieldExtendee().start(), Underlying: fmt.Errorf("unknown extendee type %s", fld.GetExtendee())})
Zack Williamse940c7a2019-08-21 14:25:39 -0700355 }
356 extd, ok := dsc.(*dpb.DescriptorProto)
357 if !ok {
358 otherType := descriptorType(dsc)
Scott Baker4a35a702019-11-26 08:17:33 -0800359 return l.errs.handleError(ErrorWithSourcePos{Pos: node.fieldExtendee().start(), Underlying: fmt.Errorf("extendee is invalid: %s is a %s, not a message", fqn, otherType)})
Zack Williamse940c7a2019-08-21 14:25:39 -0700360 }
361 fld.Extendee = proto.String("." + fqn)
362 // make sure the tag number is in range
363 found := false
364 tag := fld.GetNumber()
365 for _, rng := range extd.ExtensionRange {
366 if tag >= rng.GetStart() && tag < rng.GetEnd() {
367 found = true
368 break
369 }
370 }
371 if !found {
Scott Baker4a35a702019-11-26 08:17:33 -0800372 if err := l.errs.handleError(ErrorWithSourcePos{Pos: node.fieldTag().start(), Underlying: fmt.Errorf("%s: tag %d is not in valid range for extended type %s", scope, tag, fqn)}); err != nil {
373 return err
374 }
375 } else {
376 // make sure tag is not a duplicate
377 usedExtTags := l.extensions[fqn]
378 if usedExtTags == nil {
379 usedExtTags = map[int32]string{}
380 l.extensions[fqn] = usedExtTags
381 }
382 if other := usedExtTags[fld.GetNumber()]; other != "" {
383 if err := l.errs.handleError(ErrorWithSourcePos{Pos: node.fieldTag().start(), Underlying: fmt.Errorf("%s: duplicate extension: %s and %s are both using tag %d", scope, other, thisName, fld.GetNumber())}); err != nil {
384 return err
385 }
386 } else {
387 usedExtTags[fld.GetNumber()] = thisName
388 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700389 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700390 }
391
392 if fld.Options != nil {
393 if err := l.resolveOptions(r, fd, elemType, thisName, proto.MessageName(fld.Options), fld.Options.UninterpretedOption, scopes); err != nil {
394 return err
395 }
396 }
397
398 if fld.GetTypeName() == "" {
399 // scalar type; no further resolution required
400 return nil
401 }
402
403 fqn, dsc, proto3 := l.resolve(fd, fld.GetTypeName(), isType, scopes)
404 if dsc == nil {
Scott Baker4a35a702019-11-26 08:17:33 -0800405 return l.errs.handleError(ErrorWithSourcePos{Pos: node.fieldType().start(), Underlying: fmt.Errorf("%s: unknown type %s", scope, fld.GetTypeName())})
Zack Williamse940c7a2019-08-21 14:25:39 -0700406 }
407 switch dsc := dsc.(type) {
408 case *dpb.DescriptorProto:
409 fld.TypeName = proto.String("." + fqn)
Scott Baker4a35a702019-11-26 08:17:33 -0800410 // if type was tentatively unset, we now know it's actually a message
411 if fld.Type == nil {
412 fld.Type = dpb.FieldDescriptorProto_TYPE_MESSAGE.Enum()
413 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700414 case *dpb.EnumDescriptorProto:
415 if fld.GetExtendee() == "" && isProto3(fd) && !proto3 {
416 // fields in a proto3 message cannot refer to proto2 enums
417 return ErrorWithSourcePos{Pos: node.fieldType().start(), Underlying: fmt.Errorf("%s: cannot use proto2 enum %s in a proto3 message", scope, fld.GetTypeName())}
418 }
419 fld.TypeName = proto.String("." + fqn)
Scott Baker4a35a702019-11-26 08:17:33 -0800420 // the type was tentatively unset, but now we know it's actually an enum
Zack Williamse940c7a2019-08-21 14:25:39 -0700421 fld.Type = dpb.FieldDescriptorProto_TYPE_ENUM.Enum()
422 default:
423 otherType := descriptorType(dsc)
424 return ErrorWithSourcePos{Pos: node.fieldType().start(), Underlying: fmt.Errorf("%s: invalid type: %s is a %s, not a message or enum", scope, fqn, otherType)}
425 }
426 return nil
427}
428
429func (l *linker) resolveServiceTypes(r *parseResult, fd *dpb.FileDescriptorProto, prefix string, sd *dpb.ServiceDescriptorProto, scopes []scope) error {
430 thisName := prefix + sd.GetName()
431 if sd.Options != nil {
432 if err := l.resolveOptions(r, fd, "service", thisName, proto.MessageName(sd.Options), sd.Options.UninterpretedOption, scopes); err != nil {
433 return err
434 }
435 }
436
437 for _, mtd := range sd.Method {
438 if mtd.Options != nil {
439 if err := l.resolveOptions(r, fd, "method", thisName+"."+mtd.GetName(), proto.MessageName(mtd.Options), mtd.Options.UninterpretedOption, scopes); err != nil {
440 return err
441 }
442 }
443 scope := fmt.Sprintf("method %s.%s", thisName, mtd.GetName())
444 node := r.getMethodNode(mtd)
445 fqn, dsc, _ := l.resolve(fd, mtd.GetInputType(), isMessage, scopes)
446 if dsc == nil {
Scott Baker4a35a702019-11-26 08:17:33 -0800447 if err := l.errs.handleError(ErrorWithSourcePos{Pos: node.getInputType().start(), Underlying: fmt.Errorf("%s: unknown request type %s", scope, mtd.GetInputType())}); err != nil {
448 return err
449 }
450 } else if _, ok := dsc.(*dpb.DescriptorProto); !ok {
Zack Williamse940c7a2019-08-21 14:25:39 -0700451 otherType := descriptorType(dsc)
Scott Baker4a35a702019-11-26 08:17:33 -0800452 if err := l.errs.handleError(ErrorWithSourcePos{Pos: node.getInputType().start(), Underlying: fmt.Errorf("%s: invalid request type: %s is a %s, not a message", scope, fqn, otherType)}); err != nil {
453 return err
454 }
455 } else {
456 mtd.InputType = proto.String("." + fqn)
Zack Williamse940c7a2019-08-21 14:25:39 -0700457 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700458
459 fqn, dsc, _ = l.resolve(fd, mtd.GetOutputType(), isMessage, scopes)
460 if dsc == nil {
Scott Baker4a35a702019-11-26 08:17:33 -0800461 if err := l.errs.handleError(ErrorWithSourcePos{Pos: node.getOutputType().start(), Underlying: fmt.Errorf("%s: unknown response type %s", scope, mtd.GetOutputType())}); err != nil {
462 return err
463 }
464 } else if _, ok := dsc.(*dpb.DescriptorProto); !ok {
Zack Williamse940c7a2019-08-21 14:25:39 -0700465 otherType := descriptorType(dsc)
Scott Baker4a35a702019-11-26 08:17:33 -0800466 if err := l.errs.handleError(ErrorWithSourcePos{Pos: node.getOutputType().start(), Underlying: fmt.Errorf("%s: invalid response type: %s is a %s, not a message", scope, fqn, otherType)}); err != nil {
467 return err
468 }
469 } else {
470 mtd.OutputType = proto.String("." + fqn)
Zack Williamse940c7a2019-08-21 14:25:39 -0700471 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700472 }
473 return nil
474}
475
476func (l *linker) resolveOptions(r *parseResult, fd *dpb.FileDescriptorProto, elemType, elemName, optType string, opts []*dpb.UninterpretedOption, scopes []scope) error {
477 var scope string
478 if elemType != "file" {
479 scope = fmt.Sprintf("%s %s: ", elemType, elemName)
480 }
Scott Baker4a35a702019-11-26 08:17:33 -0800481opts:
Zack Williamse940c7a2019-08-21 14:25:39 -0700482 for _, opt := range opts {
483 for _, nm := range opt.Name {
484 if nm.GetIsExtension() {
485 node := r.getOptionNamePartNode(nm)
486 fqn, dsc, _ := l.resolve(fd, nm.GetNamePart(), isField, scopes)
487 if dsc == nil {
Scott Baker4a35a702019-11-26 08:17:33 -0800488 if err := l.errs.handleError(ErrorWithSourcePos{Pos: node.start(), Underlying: fmt.Errorf("%sunknown extension %s", scope, nm.GetNamePart())}); err != nil {
489 return err
490 }
491 continue opts
Zack Williamse940c7a2019-08-21 14:25:39 -0700492 }
493 if ext, ok := dsc.(*dpb.FieldDescriptorProto); !ok {
494 otherType := descriptorType(dsc)
Scott Baker4a35a702019-11-26 08:17:33 -0800495 if err := l.errs.handleError(ErrorWithSourcePos{Pos: node.start(), Underlying: fmt.Errorf("%sinvalid extension: %s is a %s, not an extension", scope, nm.GetNamePart(), otherType)}); err != nil {
496 return err
497 }
498 continue opts
Zack Williamse940c7a2019-08-21 14:25:39 -0700499 } else if ext.GetExtendee() == "" {
Scott Baker4a35a702019-11-26 08:17:33 -0800500 if err := l.errs.handleError(ErrorWithSourcePos{Pos: node.start(), Underlying: fmt.Errorf("%sinvalid extension: %s is a field but not an extension", scope, nm.GetNamePart())}); err != nil {
501 return err
502 }
503 continue opts
Zack Williamse940c7a2019-08-21 14:25:39 -0700504 }
505 nm.NamePart = proto.String("." + fqn)
506 }
507 }
508 }
509 return nil
510}
511
512func (l *linker) resolve(fd *dpb.FileDescriptorProto, name string, allowed func(proto.Message) bool, scopes []scope) (fqn string, element proto.Message, proto3 bool) {
513 if strings.HasPrefix(name, ".") {
514 // already fully-qualified
515 d, proto3 := l.findSymbol(fd, name[1:], false, map[*dpb.FileDescriptorProto]struct{}{})
516 if d != nil {
517 return name[1:], d, proto3
518 }
519 } else {
520 // unqualified, so we look in the enclosing (last) scope first and move
521 // towards outermost (first) scope, trying to resolve the symbol
522 var bestGuess proto.Message
523 var bestGuessFqn string
524 var bestGuessProto3 bool
525 for i := len(scopes) - 1; i >= 0; i-- {
526 fqn, d, proto3 := scopes[i](name)
527 if d != nil {
528 if allowed(d) {
529 return fqn, d, proto3
530 } else if bestGuess == nil {
531 bestGuess = d
532 bestGuessFqn = fqn
533 bestGuessProto3 = proto3
534 }
535 }
536 }
537 // we return best guess, even though it was not an allowed kind of
538 // descriptor, so caller can print a better error message (e.g.
539 // indicating that the name was found but that it's the wrong type)
540 return bestGuessFqn, bestGuess, bestGuessProto3
541 }
542 return "", nil, false
543}
544
545func isField(m proto.Message) bool {
546 _, ok := m.(*dpb.FieldDescriptorProto)
547 return ok
548}
549
550func isMessage(m proto.Message) bool {
551 _, ok := m.(*dpb.DescriptorProto)
552 return ok
553}
554
555func isType(m proto.Message) bool {
556 switch m.(type) {
557 case *dpb.DescriptorProto, *dpb.EnumDescriptorProto:
558 return true
559 }
560 return false
561}
562
563// scope represents a lexical scope in a proto file in which messages and enums
564// can be declared.
565type scope func(symbol string) (fqn string, element proto.Message, proto3 bool)
566
567func fileScope(fd *dpb.FileDescriptorProto, l *linker) scope {
568 // we search symbols in this file, but also symbols in other files that have
569 // the same package as this file or a "parent" package (in protobuf,
570 // packages are a hierarchy like C++ namespaces)
571 prefixes := internal.CreatePrefixList(fd.GetPackage())
572 return func(name string) (string, proto.Message, bool) {
573 for _, prefix := range prefixes {
574 var n string
575 if prefix == "" {
576 n = name
577 } else {
578 n = prefix + "." + name
579 }
580 d, proto3 := l.findSymbol(fd, n, false, map[*dpb.FileDescriptorProto]struct{}{})
581 if d != nil {
582 return n, d, proto3
583 }
584 }
585 return "", nil, false
586 }
587}
588
589func messageScope(messageName string, proto3 bool, filePool map[string]proto.Message) scope {
590 return func(name string) (string, proto.Message, bool) {
591 n := messageName + "." + name
592 if d, ok := filePool[n]; ok {
593 return n, d, proto3
594 }
595 return "", nil, false
596 }
597}
598
599func (l *linker) findSymbol(fd *dpb.FileDescriptorProto, name string, public bool, checked map[*dpb.FileDescriptorProto]struct{}) (element proto.Message, proto3 bool) {
600 if _, ok := checked[fd]; ok {
601 // already checked this one
602 return nil, false
603 }
604 checked[fd] = struct{}{}
605 d := l.descriptorPool[fd][name]
606 if d != nil {
607 return d, isProto3(fd)
608 }
609
610 // When public = false, we are searching only directly imported symbols. But we
611 // also need to search transitive public imports due to semantics of public imports.
612 if public {
613 for _, depIndex := range fd.PublicDependency {
614 dep := fd.Dependency[depIndex]
615 depres := l.files[dep]
616 if depres == nil {
617 // we'll catch this error later
618 continue
619 }
620 if d, proto3 := l.findSymbol(depres.fd, name, true, checked); d != nil {
621 return d, proto3
622 }
623 }
624 } else {
625 for _, dep := range fd.Dependency {
626 depres := l.files[dep]
627 if depres == nil {
628 // we'll catch this error later
629 continue
630 }
631 if d, proto3 := l.findSymbol(depres.fd, name, true, checked); d != nil {
632 return d, proto3
633 }
634 }
635 }
636
637 return nil, false
638}
639
640func isProto3(fd *dpb.FileDescriptorProto) bool {
641 return fd.GetSyntax() == "proto3"
642}
643
644func (l *linker) createdLinkedDescriptors() (map[string]*desc.FileDescriptor, error) {
645 names := make([]string, 0, len(l.files))
646 for name := range l.files {
647 names = append(names, name)
648 }
649 sort.Strings(names)
650 linked := map[string]*desc.FileDescriptor{}
651 for _, name := range names {
Scott Baker4a35a702019-11-26 08:17:33 -0800652 if _, err := l.linkFile(name, nil, nil, linked); err != nil {
Zack Williamse940c7a2019-08-21 14:25:39 -0700653 return nil, err
654 }
655 }
656 return linked, nil
657}
658
Scott Baker4a35a702019-11-26 08:17:33 -0800659func (l *linker) linkFile(name string, rootImportLoc *SourcePos, seen []string, linked map[string]*desc.FileDescriptor) (*desc.FileDescriptor, error) {
Zack Williamse940c7a2019-08-21 14:25:39 -0700660 // check for import cycle
661 for _, s := range seen {
662 if name == s {
663 var msg bytes.Buffer
664 first := true
665 for _, s := range seen {
666 if first {
667 first = false
668 } else {
669 msg.WriteString(" -> ")
670 }
671 fmt.Fprintf(&msg, "%q", s)
672 }
673 fmt.Fprintf(&msg, " -> %q", name)
Scott Baker4a35a702019-11-26 08:17:33 -0800674 return nil, ErrorWithSourcePos{
675 Underlying: fmt.Errorf("cycle found in imports: %s", msg.String()),
676 Pos: rootImportLoc,
677 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700678 }
679 }
680 seen = append(seen, name)
681
682 if lfd, ok := linked[name]; ok {
683 // already linked
684 return lfd, nil
685 }
686 r := l.files[name]
687 if r == nil {
688 importer := seen[len(seen)-2] // len-1 is *this* file, before that is the one that imported it
689 return nil, fmt.Errorf("no descriptor found for %q, imported by %q", name, importer)
690 }
691 var deps []*desc.FileDescriptor
Scott Baker4a35a702019-11-26 08:17:33 -0800692 if rootImportLoc == nil {
693 // try to find a source location for this "root" import
694 decl := r.getFileNode(r.fd)
695 fnode, ok := decl.(*fileNode)
696 if ok {
697 for _, dep := range fnode.imports {
698 ldep, err := l.linkFile(dep.name.val, dep.name.start(), seen, linked)
699 if err != nil {
700 return nil, err
701 }
702 deps = append(deps, ldep)
703 }
704 } else {
705 // no AST? just use the descriptor
706 for _, dep := range r.fd.Dependency {
707 ldep, err := l.linkFile(dep, decl.start(), seen, linked)
708 if err != nil {
709 return nil, err
710 }
711 deps = append(deps, ldep)
712 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700713 }
Scott Baker4a35a702019-11-26 08:17:33 -0800714 } else {
715 // we can just use the descriptor since we don't need source location
716 // (we'll just attribute any import cycles found to the "root" import)
717 for _, dep := range r.fd.Dependency {
718 ldep, err := l.linkFile(dep, rootImportLoc, seen, linked)
719 if err != nil {
720 return nil, err
721 }
722 deps = append(deps, ldep)
723 }
Zack Williamse940c7a2019-08-21 14:25:39 -0700724 }
725 lfd, err := desc.CreateFileDescriptor(r.fd, deps...)
726 if err != nil {
727 return nil, fmt.Errorf("error linking %q: %s", name, err)
728 }
729 linked[name] = lfd
730 return lfd, nil
731}