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  }