github.com/hoveychen/protoreflect@v1.4.7-0.20221103114119-0b4b3385ec76/desc/protoparse/linker.go (about) 1 package protoparse 2 3 import ( 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/hoveychen/protoreflect/desc" 13 "github.com/hoveychen/protoreflect/desc/internal" 14 ) 15 16 type linker struct { 17 files map[string]*parseResult 18 filenames []string 19 errs *errorHandler 20 descriptorPool map[*dpb.FileDescriptorProto]map[string]proto.Message 21 extensions map[string]map[int32]string 22 } 23 24 func newLinker(files *parseResults, errs *errorHandler) *linker { 25 return &linker{files: files.resultsByFilename, filenames: files.filenames, errs: errs} 26 } 27 28 func (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 46 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 52 // 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 74 func (l *linker) createDescriptorPool() error { 75 l.descriptorPool = map[*dpb.FileDescriptorProto]map[string]proto.Message{} 76 for _, filename := range l.filenames { 77 r := l.files[filename] 78 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 { 86 if err := addMessageToPool(r, pool, l.errs, prefix, md); err != nil { 87 return err 88 } 89 } 90 for _, fld := range fd.Extension { 91 if err := addFieldToPool(r, pool, l.errs, prefix, fld); err != nil { 92 return err 93 } 94 } 95 for _, ed := range fd.EnumType { 96 if err := addEnumToPool(r, pool, l.errs, prefix, ed); err != nil { 97 return err 98 } 99 } 100 for _, sd := range fd.Service { 101 if err := addServiceToPool(r, pool, l.errs, prefix, sd); err != nil { 102 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{} 113 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] 123 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] 133 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 } 136 } 137 pool[k] = entry{file: f.GetName(), msg: v} 138 } 139 } 140 141 return nil 142 } 143 144 func addMessageToPool(r *parseResult, pool map[string]proto.Message, errs *errorHandler, prefix string, md *dpb.DescriptorProto) error { 145 fqn := prefix + md.GetName() 146 if err := addToPool(r, pool, errs, fqn, md); err != nil { 147 return err 148 } 149 prefix = fqn + "." 150 for _, fld := range md.Field { 151 if err := addFieldToPool(r, pool, errs, prefix, fld); err != nil { 152 return err 153 } 154 } 155 for _, fld := range md.Extension { 156 if err := addFieldToPool(r, pool, errs, prefix, fld); err != nil { 157 return err 158 } 159 } 160 for _, nmd := range md.NestedType { 161 if err := addMessageToPool(r, pool, errs, prefix, nmd); err != nil { 162 return err 163 } 164 } 165 for _, ed := range md.EnumType { 166 if err := addEnumToPool(r, pool, errs, prefix, ed); err != nil { 167 return err 168 } 169 } 170 return nil 171 } 172 173 func addFieldToPool(r *parseResult, pool map[string]proto.Message, errs *errorHandler, prefix string, fld *dpb.FieldDescriptorProto) error { 174 fqn := prefix + fld.GetName() 175 return addToPool(r, pool, errs, fqn, fld) 176 } 177 178 func addEnumToPool(r *parseResult, pool map[string]proto.Message, errs *errorHandler, prefix string, ed *dpb.EnumDescriptorProto) error { 179 fqn := prefix + ed.GetName() 180 if err := addToPool(r, pool, errs, fqn, ed); err != nil { 181 return err 182 } 183 for _, evd := range ed.Value { 184 vfqn := fqn + "." + evd.GetName() 185 if err := addToPool(r, pool, errs, vfqn, evd); err != nil { 186 return err 187 } 188 } 189 return nil 190 } 191 192 func addServiceToPool(r *parseResult, pool map[string]proto.Message, errs *errorHandler, prefix string, sd *dpb.ServiceDescriptorProto) error { 193 fqn := prefix + sd.GetName() 194 if err := addToPool(r, pool, errs, fqn, sd); err != nil { 195 return err 196 } 197 for _, mtd := range sd.Method { 198 mfqn := fqn + "." + mtd.GetName() 199 if err := addToPool(r, pool, errs, mfqn, mtd); err != nil { 200 return err 201 } 202 } 203 return nil 204 } 205 206 func addToPool(r *parseResult, pool map[string]proto.Message, errs *errorHandler, fqn string, dsc proto.Message) error { 207 if d, ok := pool[fqn]; ok { 208 node := r.nodes[dsc] 209 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 } 212 } 213 pool[fqn] = dsc 214 return nil 215 } 216 217 func 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 245 func (l *linker) resolveReferences() error { 246 l.extensions = map[string]map[int32]string{} 247 for _, filename := range l.filenames { 248 r := l.files[filename] 249 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 284 func (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 302 func (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 345 func (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() != "" { 351 elemType = "extension" 352 fqn, dsc, _ := l.resolve(fd, fld.GetExtendee(), isMessage, scopes) 353 if dsc == nil { 354 return l.errs.handleError(ErrorWithSourcePos{Pos: node.fieldExtendee().start(), Underlying: fmt.Errorf("unknown extendee type %s", fld.GetExtendee())}) 355 } 356 extd, ok := dsc.(*dpb.DescriptorProto) 357 if !ok { 358 otherType := descriptorType(dsc) 359 return l.errs.handleError(ErrorWithSourcePos{Pos: node.fieldExtendee().start(), Underlying: fmt.Errorf("extendee is invalid: %s is a %s, not a message", fqn, otherType)}) 360 } 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 { 372 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 } 389 } 390 } 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 { 405 return l.errs.handleError(ErrorWithSourcePos{Pos: node.fieldType().start(), Underlying: fmt.Errorf("%s: unknown type %s", scope, fld.GetTypeName())}) 406 } 407 switch dsc := dsc.(type) { 408 case *dpb.DescriptorProto: 409 fld.TypeName = proto.String("." + fqn) 410 // 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 } 414 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) 420 // the type was tentatively unset, but now we know it's actually an enum 421 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 429 func (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 { 447 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 { 451 otherType := descriptorType(dsc) 452 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) 457 } 458 459 fqn, dsc, _ = l.resolve(fd, mtd.GetOutputType(), isMessage, scopes) 460 if dsc == nil { 461 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 { 465 otherType := descriptorType(dsc) 466 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) 471 } 472 } 473 return nil 474 } 475 476 func (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 } 481 opts: 482 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 { 488 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 492 } 493 if ext, ok := dsc.(*dpb.FieldDescriptorProto); !ok { 494 otherType := descriptorType(dsc) 495 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 499 } else if ext.GetExtendee() == "" { 500 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 504 } 505 nm.NamePart = proto.String("." + fqn) 506 } 507 } 508 } 509 return nil 510 } 511 512 func (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 545 func isField(m proto.Message) bool { 546 _, ok := m.(*dpb.FieldDescriptorProto) 547 return ok 548 } 549 550 func isMessage(m proto.Message) bool { 551 _, ok := m.(*dpb.DescriptorProto) 552 return ok 553 } 554 555 func 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. 565 type scope func(symbol string) (fqn string, element proto.Message, proto3 bool) 566 567 func 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 589 func 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 599 func (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 640 func isProto3(fd *dpb.FileDescriptorProto) bool { 641 return fd.GetSyntax() == "proto3" 642 } 643 644 func (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 { 652 if _, err := l.linkFile(name, nil, nil, linked); err != nil { 653 return nil, err 654 } 655 } 656 return linked, nil 657 } 658 659 func (l *linker) linkFile(name string, rootImportLoc *SourcePos, seen []string, linked map[string]*desc.FileDescriptor) (*desc.FileDescriptor, error) { 660 // 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) 674 return nil, ErrorWithSourcePos{ 675 Underlying: fmt.Errorf("cycle found in imports: %s", msg.String()), 676 Pos: rootImportLoc, 677 } 678 } 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 692 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 } 713 } 714 } 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 } 724 } 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 }