github.com/syumai/protoreflect@v1.7.1-0.20200810020253-2ac7e3b3a321/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/syumai/protoreflect/desc"
    13  	"github.com/syumai/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  		// we should now have any message_set_wire_format options parsed
    70  		// and can do further validation on tag ranges
    71  		if err := checkExtensionTagsInFile(fd, r); err != nil {
    72  			return nil, err
    73  		}
    74  	}
    75  
    76  	// When Parser calls linkFiles, it does not check errs again, and it expects that linkFiles
    77  	// will return all errors it should process. If the ErrorReporter handles all errors itself
    78  	// and always returns nil, we should get ErrInvalidSource here, and need to propagate this
    79  	if err := l.errs.getError(); err != nil {
    80  		return nil, err
    81  	}
    82  	return linked, nil
    83  }
    84  
    85  func (l *linker) createDescriptorPool() error {
    86  	l.descriptorPool = map[*dpb.FileDescriptorProto]map[string]proto.Message{}
    87  	for _, filename := range l.filenames {
    88  		r := l.files[filename]
    89  		fd := r.fd
    90  		pool := map[string]proto.Message{}
    91  		l.descriptorPool[fd] = pool
    92  		prefix := fd.GetPackage()
    93  		if prefix != "" {
    94  			prefix += "."
    95  		}
    96  		for _, md := range fd.MessageType {
    97  			if err := addMessageToPool(r, pool, l.errs, prefix, md); err != nil {
    98  				return err
    99  			}
   100  		}
   101  		for _, fld := range fd.Extension {
   102  			if err := addFieldToPool(r, pool, l.errs, prefix, fld); err != nil {
   103  				return err
   104  			}
   105  		}
   106  		for _, ed := range fd.EnumType {
   107  			if err := addEnumToPool(r, pool, l.errs, prefix, ed); err != nil {
   108  				return err
   109  			}
   110  		}
   111  		for _, sd := range fd.Service {
   112  			if err := addServiceToPool(r, pool, l.errs, prefix, sd); err != nil {
   113  				return err
   114  			}
   115  		}
   116  	}
   117  	// try putting everything into a single pool, to ensure there are no duplicates
   118  	// across files (e.g. same symbol, but declared in two different files)
   119  	type entry struct {
   120  		file string
   121  		msg  proto.Message
   122  	}
   123  	pool := map[string]entry{}
   124  	for _, filename := range l.filenames {
   125  		f := l.files[filename].fd
   126  		p := l.descriptorPool[f]
   127  		keys := make([]string, 0, len(p))
   128  		for k := range p {
   129  			keys = append(keys, k)
   130  		}
   131  		sort.Strings(keys) // for deterministic error reporting
   132  		for _, k := range keys {
   133  			v := p[k]
   134  			if e, ok := pool[k]; ok {
   135  				desc1 := e.msg
   136  				file1 := e.file
   137  				desc2 := v
   138  				file2 := f.GetName()
   139  				if file2 < file1 {
   140  					file1, file2 = file2, file1
   141  					desc1, desc2 = desc2, desc1
   142  				}
   143  				node := l.files[file2].nodes[desc2]
   144  				if err := l.errs.handleErrorWithPos(node.start(), "duplicate symbol %s: already defined as %s in %q", k, descriptorType(desc1), file1); err != nil {
   145  					return err
   146  				}
   147  			}
   148  			pool[k] = entry{file: f.GetName(), msg: v}
   149  		}
   150  	}
   151  
   152  	return nil
   153  }
   154  
   155  func addMessageToPool(r *parseResult, pool map[string]proto.Message, errs *errorHandler, prefix string, md *dpb.DescriptorProto) error {
   156  	fqn := prefix + md.GetName()
   157  	if err := addToPool(r, pool, errs, fqn, md); err != nil {
   158  		return err
   159  	}
   160  	prefix = fqn + "."
   161  	for _, fld := range md.Field {
   162  		if err := addFieldToPool(r, pool, errs, prefix, fld); err != nil {
   163  			return err
   164  		}
   165  	}
   166  	for _, fld := range md.Extension {
   167  		if err := addFieldToPool(r, pool, errs, prefix, fld); err != nil {
   168  			return err
   169  		}
   170  	}
   171  	for _, nmd := range md.NestedType {
   172  		if err := addMessageToPool(r, pool, errs, prefix, nmd); err != nil {
   173  			return err
   174  		}
   175  	}
   176  	for _, ed := range md.EnumType {
   177  		if err := addEnumToPool(r, pool, errs, prefix, ed); err != nil {
   178  			return err
   179  		}
   180  	}
   181  	return nil
   182  }
   183  
   184  func addFieldToPool(r *parseResult, pool map[string]proto.Message, errs *errorHandler, prefix string, fld *dpb.FieldDescriptorProto) error {
   185  	fqn := prefix + fld.GetName()
   186  	return addToPool(r, pool, errs, fqn, fld)
   187  }
   188  
   189  func addEnumToPool(r *parseResult, pool map[string]proto.Message, errs *errorHandler, prefix string, ed *dpb.EnumDescriptorProto) error {
   190  	fqn := prefix + ed.GetName()
   191  	if err := addToPool(r, pool, errs, fqn, ed); err != nil {
   192  		return err
   193  	}
   194  	for _, evd := range ed.Value {
   195  		vfqn := fqn + "." + evd.GetName()
   196  		if err := addToPool(r, pool, errs, vfqn, evd); err != nil {
   197  			return err
   198  		}
   199  	}
   200  	return nil
   201  }
   202  
   203  func addServiceToPool(r *parseResult, pool map[string]proto.Message, errs *errorHandler, prefix string, sd *dpb.ServiceDescriptorProto) error {
   204  	fqn := prefix + sd.GetName()
   205  	if err := addToPool(r, pool, errs, fqn, sd); err != nil {
   206  		return err
   207  	}
   208  	for _, mtd := range sd.Method {
   209  		mfqn := fqn + "." + mtd.GetName()
   210  		if err := addToPool(r, pool, errs, mfqn, mtd); err != nil {
   211  			return err
   212  		}
   213  	}
   214  	return nil
   215  }
   216  
   217  func addToPool(r *parseResult, pool map[string]proto.Message, errs *errorHandler, fqn string, dsc proto.Message) error {
   218  	if d, ok := pool[fqn]; ok {
   219  		node := r.nodes[dsc]
   220  		if err := errs.handleErrorWithPos(node.start(), "duplicate symbol %s: already defined as %s", fqn, descriptorType(d)); err != nil {
   221  			return err
   222  		}
   223  	}
   224  	pool[fqn] = dsc
   225  	return nil
   226  }
   227  
   228  func descriptorType(m proto.Message) string {
   229  	switch m := m.(type) {
   230  	case *dpb.DescriptorProto:
   231  		return "message"
   232  	case *dpb.DescriptorProto_ExtensionRange:
   233  		return "extension range"
   234  	case *dpb.FieldDescriptorProto:
   235  		if m.GetExtendee() == "" {
   236  			return "field"
   237  		} else {
   238  			return "extension"
   239  		}
   240  	case *dpb.EnumDescriptorProto:
   241  		return "enum"
   242  	case *dpb.EnumValueDescriptorProto:
   243  		return "enum value"
   244  	case *dpb.ServiceDescriptorProto:
   245  		return "service"
   246  	case *dpb.MethodDescriptorProto:
   247  		return "method"
   248  	case *dpb.FileDescriptorProto:
   249  		return "file"
   250  	default:
   251  		// shouldn't be possible
   252  		return fmt.Sprintf("%T", m)
   253  	}
   254  }
   255  
   256  func (l *linker) resolveReferences() error {
   257  	l.extensions = map[string]map[int32]string{}
   258  	for _, filename := range l.filenames {
   259  		r := l.files[filename]
   260  		fd := r.fd
   261  		prefix := fd.GetPackage()
   262  		scopes := []scope{fileScope(fd, l)}
   263  		if prefix != "" {
   264  			prefix += "."
   265  		}
   266  		if fd.Options != nil {
   267  			if err := l.resolveOptions(r, fd, "file", fd.GetName(), proto.MessageName(fd.Options), fd.Options.UninterpretedOption, scopes); err != nil {
   268  				return err
   269  			}
   270  		}
   271  		for _, md := range fd.MessageType {
   272  			if err := l.resolveMessageTypes(r, fd, prefix, md, scopes); err != nil {
   273  				return err
   274  			}
   275  		}
   276  		for _, fld := range fd.Extension {
   277  			if err := l.resolveFieldTypes(r, fd, prefix, fld, scopes); err != nil {
   278  				return err
   279  			}
   280  		}
   281  		for _, ed := range fd.EnumType {
   282  			if err := l.resolveEnumTypes(r, fd, prefix, ed, scopes); err != nil {
   283  				return err
   284  			}
   285  		}
   286  		for _, sd := range fd.Service {
   287  			if err := l.resolveServiceTypes(r, fd, prefix, sd, scopes); err != nil {
   288  				return err
   289  			}
   290  		}
   291  	}
   292  	return nil
   293  }
   294  
   295  func (l *linker) resolveEnumTypes(r *parseResult, fd *dpb.FileDescriptorProto, prefix string, ed *dpb.EnumDescriptorProto, scopes []scope) error {
   296  	enumFqn := prefix + ed.GetName()
   297  	if ed.Options != nil {
   298  		if err := l.resolveOptions(r, fd, "enum", enumFqn, proto.MessageName(ed.Options), ed.Options.UninterpretedOption, scopes); err != nil {
   299  			return err
   300  		}
   301  	}
   302  	for _, evd := range ed.Value {
   303  		if evd.Options != nil {
   304  			evFqn := enumFqn + "." + evd.GetName()
   305  			if err := l.resolveOptions(r, fd, "enum value", evFqn, proto.MessageName(evd.Options), evd.Options.UninterpretedOption, scopes); err != nil {
   306  				return err
   307  			}
   308  		}
   309  	}
   310  	return nil
   311  }
   312  
   313  func (l *linker) resolveMessageTypes(r *parseResult, fd *dpb.FileDescriptorProto, prefix string, md *dpb.DescriptorProto, scopes []scope) error {
   314  	fqn := prefix + md.GetName()
   315  	scope := messageScope(fqn, isProto3(fd), l.descriptorPool[fd])
   316  	scopes = append(scopes, scope)
   317  	prefix = fqn + "."
   318  
   319  	if md.Options != nil {
   320  		if err := l.resolveOptions(r, fd, "message", fqn, proto.MessageName(md.Options), md.Options.UninterpretedOption, scopes); err != nil {
   321  			return err
   322  		}
   323  	}
   324  
   325  	for _, nmd := range md.NestedType {
   326  		if err := l.resolveMessageTypes(r, fd, prefix, nmd, scopes); err != nil {
   327  			return err
   328  		}
   329  	}
   330  	for _, ned := range md.EnumType {
   331  		if err := l.resolveEnumTypes(r, fd, prefix, ned, scopes); err != nil {
   332  			return err
   333  		}
   334  	}
   335  	for _, fld := range md.Field {
   336  		if err := l.resolveFieldTypes(r, fd, prefix, fld, scopes); err != nil {
   337  			return err
   338  		}
   339  	}
   340  	for _, fld := range md.Extension {
   341  		if err := l.resolveFieldTypes(r, fd, prefix, fld, scopes); err != nil {
   342  			return err
   343  		}
   344  	}
   345  	for _, er := range md.ExtensionRange {
   346  		if er.Options != nil {
   347  			erName := fmt.Sprintf("%s:%d-%d", fqn, er.GetStart(), er.GetEnd()-1)
   348  			if err := l.resolveOptions(r, fd, "extension range", erName, proto.MessageName(er.Options), er.Options.UninterpretedOption, scopes); err != nil {
   349  				return err
   350  			}
   351  		}
   352  	}
   353  	return nil
   354  }
   355  
   356  func (l *linker) resolveFieldTypes(r *parseResult, fd *dpb.FileDescriptorProto, prefix string, fld *dpb.FieldDescriptorProto, scopes []scope) error {
   357  	thisName := prefix + fld.GetName()
   358  	scope := fmt.Sprintf("field %s", thisName)
   359  	node := r.getFieldNode(fld)
   360  	elemType := "field"
   361  	if fld.GetExtendee() != "" {
   362  		elemType = "extension"
   363  		fqn, dsc, _ := l.resolve(fd, fld.GetExtendee(), isMessage, scopes)
   364  		if dsc == nil {
   365  			return l.errs.handleErrorWithPos(node.fieldExtendee().start(), "unknown extendee type %s", fld.GetExtendee())
   366  		}
   367  		extd, ok := dsc.(*dpb.DescriptorProto)
   368  		if !ok {
   369  			otherType := descriptorType(dsc)
   370  			return l.errs.handleErrorWithPos(node.fieldExtendee().start(), "extendee is invalid: %s is a %s, not a message", fqn, otherType)
   371  		}
   372  		fld.Extendee = proto.String("." + fqn)
   373  		// make sure the tag number is in range
   374  		found := false
   375  		tag := fld.GetNumber()
   376  		for _, rng := range extd.ExtensionRange {
   377  			if tag >= rng.GetStart() && tag < rng.GetEnd() {
   378  				found = true
   379  				break
   380  			}
   381  		}
   382  		if !found {
   383  			if err := l.errs.handleErrorWithPos(node.fieldTag().start(), "%s: tag %d is not in valid range for extended type %s", scope, tag, fqn); err != nil {
   384  				return err
   385  			}
   386  		} else {
   387  			// make sure tag is not a duplicate
   388  			usedExtTags := l.extensions[fqn]
   389  			if usedExtTags == nil {
   390  				usedExtTags = map[int32]string{}
   391  				l.extensions[fqn] = usedExtTags
   392  			}
   393  			if other := usedExtTags[fld.GetNumber()]; other != "" {
   394  				if err := l.errs.handleErrorWithPos(node.fieldTag().start(), "%s: duplicate extension: %s and %s are both using tag %d", scope, other, thisName, fld.GetNumber()); err != nil {
   395  					return err
   396  				}
   397  			} else {
   398  				usedExtTags[fld.GetNumber()] = thisName
   399  			}
   400  		}
   401  	}
   402  
   403  	if fld.Options != nil {
   404  		if err := l.resolveOptions(r, fd, elemType, thisName, proto.MessageName(fld.Options), fld.Options.UninterpretedOption, scopes); err != nil {
   405  			return err
   406  		}
   407  	}
   408  
   409  	if fld.GetTypeName() == "" {
   410  		// scalar type; no further resolution required
   411  		return nil
   412  	}
   413  
   414  	fqn, dsc, proto3 := l.resolve(fd, fld.GetTypeName(), isType, scopes)
   415  	if dsc == nil {
   416  		return l.errs.handleErrorWithPos(node.fieldType().start(), "%s: unknown type %s", scope, fld.GetTypeName())
   417  	}
   418  	switch dsc := dsc.(type) {
   419  	case *dpb.DescriptorProto:
   420  		fld.TypeName = proto.String("." + fqn)
   421  		// if type was tentatively unset, we now know it's actually a message
   422  		if fld.Type == nil {
   423  			fld.Type = dpb.FieldDescriptorProto_TYPE_MESSAGE.Enum()
   424  		}
   425  	case *dpb.EnumDescriptorProto:
   426  		if fld.GetExtendee() == "" && isProto3(fd) && !proto3 {
   427  			// fields in a proto3 message cannot refer to proto2 enums
   428  			return l.errs.handleErrorWithPos(node.fieldType().start(), "%s: cannot use proto2 enum %s in a proto3 message", scope, fld.GetTypeName())
   429  		}
   430  		fld.TypeName = proto.String("." + fqn)
   431  		// the type was tentatively unset, but now we know it's actually an enum
   432  		fld.Type = dpb.FieldDescriptorProto_TYPE_ENUM.Enum()
   433  	default:
   434  		otherType := descriptorType(dsc)
   435  		return l.errs.handleErrorWithPos(node.fieldType().start(), "%s: invalid type: %s is a %s, not a message or enum", scope, fqn, otherType)
   436  	}
   437  	return nil
   438  }
   439  
   440  func (l *linker) resolveServiceTypes(r *parseResult, fd *dpb.FileDescriptorProto, prefix string, sd *dpb.ServiceDescriptorProto, scopes []scope) error {
   441  	thisName := prefix + sd.GetName()
   442  	if sd.Options != nil {
   443  		if err := l.resolveOptions(r, fd, "service", thisName, proto.MessageName(sd.Options), sd.Options.UninterpretedOption, scopes); err != nil {
   444  			return err
   445  		}
   446  	}
   447  
   448  	for _, mtd := range sd.Method {
   449  		if mtd.Options != nil {
   450  			if err := l.resolveOptions(r, fd, "method", thisName+"."+mtd.GetName(), proto.MessageName(mtd.Options), mtd.Options.UninterpretedOption, scopes); err != nil {
   451  				return err
   452  			}
   453  		}
   454  		scope := fmt.Sprintf("method %s.%s", thisName, mtd.GetName())
   455  		node := r.getMethodNode(mtd)
   456  		fqn, dsc, _ := l.resolve(fd, mtd.GetInputType(), isMessage, scopes)
   457  		if dsc == nil {
   458  			if err := l.errs.handleErrorWithPos(node.getInputType().start(), "%s: unknown request type %s", scope, mtd.GetInputType()); err != nil {
   459  				return err
   460  			}
   461  		} else if _, ok := dsc.(*dpb.DescriptorProto); !ok {
   462  			otherType := descriptorType(dsc)
   463  			if err := l.errs.handleErrorWithPos(node.getInputType().start(), "%s: invalid request type: %s is a %s, not a message", scope, fqn, otherType); err != nil {
   464  				return err
   465  			}
   466  		} else {
   467  			mtd.InputType = proto.String("." + fqn)
   468  		}
   469  
   470  		fqn, dsc, _ = l.resolve(fd, mtd.GetOutputType(), isMessage, scopes)
   471  		if dsc == nil {
   472  			if err := l.errs.handleErrorWithPos(node.getOutputType().start(), "%s: unknown response type %s", scope, mtd.GetOutputType()); err != nil {
   473  				return err
   474  			}
   475  		} else if _, ok := dsc.(*dpb.DescriptorProto); !ok {
   476  			otherType := descriptorType(dsc)
   477  			if err := l.errs.handleErrorWithPos(node.getOutputType().start(), "%s: invalid response type: %s is a %s, not a message", scope, fqn, otherType); err != nil {
   478  				return err
   479  			}
   480  		} else {
   481  			mtd.OutputType = proto.String("." + fqn)
   482  		}
   483  	}
   484  	return nil
   485  }
   486  
   487  func (l *linker) resolveOptions(r *parseResult, fd *dpb.FileDescriptorProto, elemType, elemName, optType string, opts []*dpb.UninterpretedOption, scopes []scope) error {
   488  	var scope string
   489  	if elemType != "file" {
   490  		scope = fmt.Sprintf("%s %s: ", elemType, elemName)
   491  	}
   492  opts:
   493  	for _, opt := range opts {
   494  		for _, nm := range opt.Name {
   495  			if nm.GetIsExtension() {
   496  				node := r.getOptionNamePartNode(nm)
   497  				fqn, dsc, _ := l.resolve(fd, nm.GetNamePart(), isField, scopes)
   498  				if dsc == nil {
   499  					if err := l.errs.handleErrorWithPos(node.start(), "%sunknown extension %s", scope, nm.GetNamePart()); err != nil {
   500  						return err
   501  					}
   502  					continue opts
   503  				}
   504  				if ext, ok := dsc.(*dpb.FieldDescriptorProto); !ok {
   505  					otherType := descriptorType(dsc)
   506  					if err := l.errs.handleErrorWithPos(node.start(), "%sinvalid extension: %s is a %s, not an extension", scope, nm.GetNamePart(), otherType); err != nil {
   507  						return err
   508  					}
   509  					continue opts
   510  				} else if ext.GetExtendee() == "" {
   511  					if err := l.errs.handleErrorWithPos(node.start(), "%sinvalid extension: %s is a field but not an extension", scope, nm.GetNamePart()); err != nil {
   512  						return err
   513  					}
   514  					continue opts
   515  				}
   516  				nm.NamePart = proto.String("." + fqn)
   517  			}
   518  		}
   519  	}
   520  	return nil
   521  }
   522  
   523  func (l *linker) resolve(fd *dpb.FileDescriptorProto, name string, allowed func(proto.Message) bool, scopes []scope) (fqn string, element proto.Message, proto3 bool) {
   524  	if strings.HasPrefix(name, ".") {
   525  		// already fully-qualified
   526  		d, proto3 := l.findSymbol(fd, name[1:], false, map[*dpb.FileDescriptorProto]struct{}{})
   527  		if d != nil {
   528  			return name[1:], d, proto3
   529  		}
   530  	} else {
   531  		// unqualified, so we look in the enclosing (last) scope first and move
   532  		// towards outermost (first) scope, trying to resolve the symbol
   533  		var bestGuess proto.Message
   534  		var bestGuessFqn string
   535  		var bestGuessProto3 bool
   536  		for i := len(scopes) - 1; i >= 0; i-- {
   537  			fqn, d, proto3 := scopes[i](name)
   538  			if d != nil {
   539  				if allowed(d) {
   540  					return fqn, d, proto3
   541  				} else if bestGuess == nil {
   542  					bestGuess = d
   543  					bestGuessFqn = fqn
   544  					bestGuessProto3 = proto3
   545  				}
   546  			}
   547  		}
   548  		// we return best guess, even though it was not an allowed kind of
   549  		// descriptor, so caller can print a better error message (e.g.
   550  		// indicating that the name was found but that it's the wrong type)
   551  		return bestGuessFqn, bestGuess, bestGuessProto3
   552  	}
   553  	return "", nil, false
   554  }
   555  
   556  func isField(m proto.Message) bool {
   557  	_, ok := m.(*dpb.FieldDescriptorProto)
   558  	return ok
   559  }
   560  
   561  func isMessage(m proto.Message) bool {
   562  	_, ok := m.(*dpb.DescriptorProto)
   563  	return ok
   564  }
   565  
   566  func isType(m proto.Message) bool {
   567  	switch m.(type) {
   568  	case *dpb.DescriptorProto, *dpb.EnumDescriptorProto:
   569  		return true
   570  	}
   571  	return false
   572  }
   573  
   574  // scope represents a lexical scope in a proto file in which messages and enums
   575  // can be declared.
   576  type scope func(symbol string) (fqn string, element proto.Message, proto3 bool)
   577  
   578  func fileScope(fd *dpb.FileDescriptorProto, l *linker) scope {
   579  	// we search symbols in this file, but also symbols in other files that have
   580  	// the same package as this file or a "parent" package (in protobuf,
   581  	// packages are a hierarchy like C++ namespaces)
   582  	prefixes := internal.CreatePrefixList(fd.GetPackage())
   583  	return func(name string) (string, proto.Message, bool) {
   584  		for _, prefix := range prefixes {
   585  			var n string
   586  			if prefix == "" {
   587  				n = name
   588  			} else {
   589  				n = prefix + "." + name
   590  			}
   591  			d, proto3 := l.findSymbol(fd, n, false, map[*dpb.FileDescriptorProto]struct{}{})
   592  			if d != nil {
   593  				return n, d, proto3
   594  			}
   595  		}
   596  		return "", nil, false
   597  	}
   598  }
   599  
   600  func messageScope(messageName string, proto3 bool, filePool map[string]proto.Message) scope {
   601  	return func(name string) (string, proto.Message, bool) {
   602  		n := messageName + "." + name
   603  		if d, ok := filePool[n]; ok {
   604  			return n, d, proto3
   605  		}
   606  		return "", nil, false
   607  	}
   608  }
   609  
   610  func (l *linker) findSymbol(fd *dpb.FileDescriptorProto, name string, public bool, checked map[*dpb.FileDescriptorProto]struct{}) (element proto.Message, proto3 bool) {
   611  	if _, ok := checked[fd]; ok {
   612  		// already checked this one
   613  		return nil, false
   614  	}
   615  	checked[fd] = struct{}{}
   616  	d := l.descriptorPool[fd][name]
   617  	if d != nil {
   618  		return d, isProto3(fd)
   619  	}
   620  
   621  	// When public = false, we are searching only directly imported symbols. But we
   622  	// also need to search transitive public imports due to semantics of public imports.
   623  	if public {
   624  		for _, depIndex := range fd.PublicDependency {
   625  			dep := fd.Dependency[depIndex]
   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  	} else {
   636  		for _, dep := range fd.Dependency {
   637  			depres := l.files[dep]
   638  			if depres == nil {
   639  				// we'll catch this error later
   640  				continue
   641  			}
   642  			if d, proto3 := l.findSymbol(depres.fd, name, true, checked); d != nil {
   643  				return d, proto3
   644  			}
   645  		}
   646  	}
   647  
   648  	return nil, false
   649  }
   650  
   651  func isProto3(fd *dpb.FileDescriptorProto) bool {
   652  	return fd.GetSyntax() == "proto3"
   653  }
   654  
   655  func (l *linker) createdLinkedDescriptors() (map[string]*desc.FileDescriptor, error) {
   656  	names := make([]string, 0, len(l.files))
   657  	for name := range l.files {
   658  		names = append(names, name)
   659  	}
   660  	sort.Strings(names)
   661  	linked := map[string]*desc.FileDescriptor{}
   662  	for _, name := range names {
   663  		if _, err := l.linkFile(name, nil, nil, linked); err != nil {
   664  			return nil, err
   665  		}
   666  	}
   667  	return linked, nil
   668  }
   669  
   670  func (l *linker) linkFile(name string, rootImportLoc *SourcePos, seen []string, linked map[string]*desc.FileDescriptor) (*desc.FileDescriptor, error) {
   671  	// check for import cycle
   672  	for _, s := range seen {
   673  		if name == s {
   674  			var msg bytes.Buffer
   675  			first := true
   676  			for _, s := range seen {
   677  				if first {
   678  					first = false
   679  				} else {
   680  					msg.WriteString(" -> ")
   681  				}
   682  				_, _ = fmt.Fprintf(&msg, "%q", s)
   683  			}
   684  			_, _ = fmt.Fprintf(&msg, " -> %q", name)
   685  			return nil, ErrorWithSourcePos{
   686  				Underlying: fmt.Errorf("cycle found in imports: %s", msg.String()),
   687  				Pos:        rootImportLoc,
   688  			}
   689  		}
   690  	}
   691  	seen = append(seen, name)
   692  
   693  	if lfd, ok := linked[name]; ok {
   694  		// already linked
   695  		return lfd, nil
   696  	}
   697  	r := l.files[name]
   698  	if r == nil {
   699  		importer := seen[len(seen)-2] // len-1 is *this* file, before that is the one that imported it
   700  		return nil, fmt.Errorf("no descriptor found for %q, imported by %q", name, importer)
   701  	}
   702  	var deps []*desc.FileDescriptor
   703  	if rootImportLoc == nil {
   704  		// try to find a source location for this "root" import
   705  		decl := r.getFileNode(r.fd)
   706  		fnode, ok := decl.(*fileNode)
   707  		if ok {
   708  			for _, dep := range fnode.imports {
   709  				ldep, err := l.linkFile(dep.name.val, dep.name.start(), seen, linked)
   710  				if err != nil {
   711  					return nil, err
   712  				}
   713  				deps = append(deps, ldep)
   714  			}
   715  		} else {
   716  			// no AST? just use the descriptor
   717  			for _, dep := range r.fd.Dependency {
   718  				ldep, err := l.linkFile(dep, decl.start(), seen, linked)
   719  				if err != nil {
   720  					return nil, err
   721  				}
   722  				deps = append(deps, ldep)
   723  			}
   724  		}
   725  	} else {
   726  		// we can just use the descriptor since we don't need source location
   727  		// (we'll just attribute any import cycles found to the "root" import)
   728  		for _, dep := range r.fd.Dependency {
   729  			ldep, err := l.linkFile(dep, rootImportLoc, seen, linked)
   730  			if err != nil {
   731  				return nil, err
   732  			}
   733  			deps = append(deps, ldep)
   734  		}
   735  	}
   736  	lfd, err := desc.CreateFileDescriptor(r.fd, deps...)
   737  	if err != nil {
   738  		return nil, fmt.Errorf("error linking %q: %s", name, err)
   739  	}
   740  	linked[name] = lfd
   741  	return lfd, nil
   742  }