github.com/Khushbukela/protoreflect@v1.0.1/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/jhump/protoreflect/desc"
    13  	"github.com/jhump/protoreflect/desc/internal"
    14  	"github.com/jhump/protoreflect/desc/protoparse/ast"
    15  )
    16  
    17  type linker struct {
    18  	files             map[string]*parseResult
    19  	filenames         []string
    20  	errs              *errorHandler
    21  	descriptorPool    map[*dpb.FileDescriptorProto]map[string]proto.Message
    22  	packageNamespaces map[*dpb.FileDescriptorProto]map[string]struct{}
    23  	extensions        map[string]map[int32]string
    24  	usedImports       map[*dpb.FileDescriptorProto]map[string]struct{}
    25  }
    26  
    27  func newLinker(files *parseResults, errs *errorHandler) *linker {
    28  	return &linker{files: files.resultsByFilename, filenames: files.filenames, errs: errs}
    29  }
    30  
    31  func (l *linker) linkFiles() (map[string]*desc.FileDescriptor, error) {
    32  	// First, we put all symbols into a single pool, which lets us ensure there
    33  	// are no duplicate symbols and will also let us resolve and revise all type
    34  	// references in next step.
    35  	if err := l.createDescriptorPool(); err != nil {
    36  		return nil, err
    37  	}
    38  
    39  	// After we've populated the pool, we can now try to resolve all type
    40  	// references. All references must be checked for correct type, any fields
    41  	// with enum types must be corrected (since we parse them as if they are
    42  	// message references since we don't actually know message or enum until
    43  	// link time), and references will be re-written to be fully-qualified
    44  	// references (e.g. start with a dot ".").
    45  	if err := l.resolveReferences(); err != nil {
    46  		return nil, err
    47  	}
    48  
    49  	if err := l.errs.getError(); err != nil {
    50  		// we won't be able to create real descriptors if we've encountered
    51  		// errors up to this point, so bail at this point
    52  		return nil, err
    53  	}
    54  
    55  	// Now we've validated the descriptors, so we can link them into rich
    56  	// descriptors. This is a little redundant since that step does similar
    57  	// checking of symbols. But, without breaking encapsulation (e.g. exporting
    58  	// a lot of fields from desc package that are currently unexported) or
    59  	// merging this into the same package, we can't really prevent it.
    60  	linked, err := l.createdLinkedDescriptors()
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  
    65  	// Now that we have linked descriptors, we can interpret any uninterpreted
    66  	// options that remain.
    67  	for _, r := range l.files {
    68  		fd := linked[r.fd.GetName()]
    69  		if err := interpretFileOptions(l, r, richFileDescriptorish{FileDescriptor: fd}); err != nil {
    70  			return nil, err
    71  		}
    72  		// we should now have any message_set_wire_format options parsed
    73  		// and can do further validation on tag ranges
    74  		if err := checkExtensionsInFile(fd, r); err != nil {
    75  			return nil, err
    76  		}
    77  	}
    78  
    79  	// When Parser calls linkFiles, it does not check errs again, and it expects that linkFiles
    80  	// will return all errors it should process. If the ErrorReporter handles all errors itself
    81  	// and always returns nil, we should get ErrInvalidSource here, and need to propagate this
    82  	if err := l.errs.getError(); err != nil {
    83  		return nil, err
    84  	}
    85  	return linked, nil
    86  }
    87  
    88  func (l *linker) createDescriptorPool() error {
    89  	l.descriptorPool = map[*dpb.FileDescriptorProto]map[string]proto.Message{}
    90  	l.packageNamespaces = map[*dpb.FileDescriptorProto]map[string]struct{}{}
    91  	for _, filename := range l.filenames {
    92  		r := l.files[filename]
    93  		fd := r.fd
    94  		pool := map[string]proto.Message{}
    95  		l.descriptorPool[fd] = pool
    96  		prefix := fd.GetPackage()
    97  		l.packageNamespaces[fd] = namespacesFromPackage(prefix)
    98  		if prefix != "" {
    99  			prefix += "."
   100  		}
   101  		for _, md := range fd.MessageType {
   102  			if err := addMessageToPool(r, pool, l.errs, prefix, md); err != nil {
   103  				return err
   104  			}
   105  		}
   106  		for _, fld := range fd.Extension {
   107  			if err := addFieldToPool(r, pool, l.errs, prefix, fld); err != nil {
   108  				return err
   109  			}
   110  		}
   111  		for _, ed := range fd.EnumType {
   112  			if err := addEnumToPool(r, pool, l.errs, prefix, ed); err != nil {
   113  				return err
   114  			}
   115  		}
   116  		for _, sd := range fd.Service {
   117  			if err := addServiceToPool(r, pool, l.errs, prefix, sd); err != nil {
   118  				return err
   119  			}
   120  		}
   121  	}
   122  	// try putting everything into a single pool, to ensure there are no duplicates
   123  	// across files (e.g. same symbol, but declared in two different files)
   124  	type entry struct {
   125  		file string
   126  		msg  proto.Message
   127  	}
   128  	pool := map[string]entry{}
   129  	for _, filename := range l.filenames {
   130  		f := l.files[filename].fd
   131  		p := l.descriptorPool[f]
   132  		keys := make([]string, 0, len(p))
   133  		for k := range p {
   134  			keys = append(keys, k)
   135  		}
   136  		sort.Strings(keys) // for deterministic error reporting
   137  		for _, k := range keys {
   138  			v := p[k]
   139  			if e, ok := pool[k]; ok {
   140  				desc1 := e.msg
   141  				file1 := e.file
   142  				desc2 := v
   143  				file2 := f.GetName()
   144  				if file2 < file1 {
   145  					file1, file2 = file2, file1
   146  					desc1, desc2 = desc2, desc1
   147  				}
   148  				node := l.files[file2].nodes[desc2]
   149  				if err := l.errs.handleErrorWithPos(node.Start(), "duplicate symbol %s: already defined as %s in %q", k, descriptorType(desc1), file1); err != nil {
   150  					return err
   151  				}
   152  			}
   153  			pool[k] = entry{file: f.GetName(), msg: v}
   154  		}
   155  	}
   156  
   157  	return nil
   158  }
   159  
   160  func namespacesFromPackage(pkg string) map[string]struct{} {
   161  	if pkg == "" {
   162  		return nil
   163  	}
   164  	offs := 0
   165  	pkgs := map[string]struct{}{}
   166  	pkgs[pkg] = struct{}{}
   167  	for {
   168  		pos := strings.IndexByte(pkg[offs:], '.')
   169  		if pos == -1 {
   170  			return pkgs
   171  		}
   172  		pkgs[pkg[:offs+pos]] = struct{}{}
   173  		offs = offs + pos + 1
   174  	}
   175  }
   176  
   177  func addMessageToPool(r *parseResult, pool map[string]proto.Message, errs *errorHandler, prefix string, md *dpb.DescriptorProto) error {
   178  	fqn := prefix + md.GetName()
   179  	if err := addToPool(r, pool, errs, fqn, md); err != nil {
   180  		return err
   181  	}
   182  	prefix = fqn + "."
   183  	for _, ood := range md.OneofDecl {
   184  		if err := addOneofToPool(r, pool, errs, prefix, ood); err != nil {
   185  			return err
   186  		}
   187  	}
   188  	for _, fld := range md.Field {
   189  		if err := addFieldToPool(r, pool, errs, prefix, fld); err != nil {
   190  			return err
   191  		}
   192  	}
   193  	for _, fld := range md.Extension {
   194  		if err := addFieldToPool(r, pool, errs, prefix, fld); err != nil {
   195  			return err
   196  		}
   197  	}
   198  	for _, nmd := range md.NestedType {
   199  		if err := addMessageToPool(r, pool, errs, prefix, nmd); err != nil {
   200  			return err
   201  		}
   202  	}
   203  	for _, ed := range md.EnumType {
   204  		if err := addEnumToPool(r, pool, errs, prefix, ed); err != nil {
   205  			return err
   206  		}
   207  	}
   208  	return nil
   209  }
   210  
   211  func addFieldToPool(r *parseResult, pool map[string]proto.Message, errs *errorHandler, prefix string, fld *dpb.FieldDescriptorProto) error {
   212  	fqn := prefix + fld.GetName()
   213  	return addToPool(r, pool, errs, fqn, fld)
   214  }
   215  
   216  func addOneofToPool(r *parseResult, pool map[string]proto.Message, errs *errorHandler, prefix string, ood *dpb.OneofDescriptorProto) error {
   217  	fqn := prefix + ood.GetName()
   218  	return addToPool(r, pool, errs, fqn, ood)
   219  }
   220  
   221  func addEnumToPool(r *parseResult, pool map[string]proto.Message, errs *errorHandler, prefix string, ed *dpb.EnumDescriptorProto) error {
   222  	fqn := prefix + ed.GetName()
   223  	if err := addToPool(r, pool, errs, fqn, ed); err != nil {
   224  		return err
   225  	}
   226  	for _, evd := range ed.Value {
   227  		// protobuf name-scoping rules for enum values follow C++ scoping rules:
   228  		// the enum value name is a symbol in the *parent* scope (the one
   229  		// enclosing the enum).
   230  		vfqn := prefix + evd.GetName()
   231  		if err := addToPool(r, pool, errs, vfqn, evd); err != nil {
   232  			return err
   233  		}
   234  	}
   235  	return nil
   236  }
   237  
   238  func addServiceToPool(r *parseResult, pool map[string]proto.Message, errs *errorHandler, prefix string, sd *dpb.ServiceDescriptorProto) error {
   239  	fqn := prefix + sd.GetName()
   240  	if err := addToPool(r, pool, errs, fqn, sd); err != nil {
   241  		return err
   242  	}
   243  	for _, mtd := range sd.Method {
   244  		mfqn := fqn + "." + mtd.GetName()
   245  		if err := addToPool(r, pool, errs, mfqn, mtd); err != nil {
   246  			return err
   247  		}
   248  	}
   249  	return nil
   250  }
   251  
   252  func addToPool(r *parseResult, pool map[string]proto.Message, errs *errorHandler, fqn string, dsc proto.Message) error {
   253  	if d, ok := pool[fqn]; ok {
   254  		node := r.nodes[dsc]
   255  		_, additionIsEnumVal := dsc.(*dpb.EnumValueDescriptorProto)
   256  		_, existingIsEnumVal := d.(*dpb.EnumValueDescriptorProto)
   257  		// because of weird scoping for enum values, provide more context in error message
   258  		// if this conflict is with an enum value
   259  		var suffix string
   260  		if additionIsEnumVal || existingIsEnumVal {
   261  			suffix = "; protobuf uses C++ scoping rules for enum values, so they exist in the scope enclosing the enum"
   262  		}
   263  		// TODO: also include the source location for the conflicting symbol
   264  		if err := errs.handleErrorWithPos(node.Start(), "duplicate symbol %s: already defined as %s%s", fqn, descriptorType(d), suffix); err != nil {
   265  			return err
   266  		}
   267  	}
   268  	pool[fqn] = dsc
   269  	return nil
   270  }
   271  
   272  func descriptorType(m proto.Message) string {
   273  	switch m := m.(type) {
   274  	case *dpb.DescriptorProto:
   275  		return "message"
   276  	case *dpb.DescriptorProto_ExtensionRange:
   277  		return "extension range"
   278  	case *dpb.FieldDescriptorProto:
   279  		if m.GetExtendee() == "" {
   280  			return "field"
   281  		} else {
   282  			return "extension"
   283  		}
   284  	case *dpb.EnumDescriptorProto:
   285  		return "enum"
   286  	case *dpb.EnumValueDescriptorProto:
   287  		return "enum value"
   288  	case *dpb.ServiceDescriptorProto:
   289  		return "service"
   290  	case *dpb.MethodDescriptorProto:
   291  		return "method"
   292  	case *dpb.FileDescriptorProto:
   293  		return "file"
   294  	case *dpb.OneofDescriptorProto:
   295  		return "oneof"
   296  	default:
   297  		// shouldn't be possible
   298  		return fmt.Sprintf("%T", m)
   299  	}
   300  }
   301  
   302  func (l *linker) resolveReferences() error {
   303  	l.extensions = map[string]map[int32]string{}
   304  	l.usedImports = map[*dpb.FileDescriptorProto]map[string]struct{}{}
   305  	for _, filename := range l.filenames {
   306  		r := l.files[filename]
   307  		fd := r.fd
   308  		prefix := fd.GetPackage()
   309  		scopes := []scope{fileScope(fd, l)}
   310  		if prefix != "" {
   311  			prefix += "."
   312  		}
   313  		if fd.Options != nil {
   314  			if err := l.resolveOptions(r, fd, "file", fd.GetName(), proto.MessageName(fd.Options), fd.Options.UninterpretedOption, scopes); err != nil {
   315  				return err
   316  			}
   317  		}
   318  		for _, md := range fd.MessageType {
   319  			if err := l.resolveMessageTypes(r, fd, prefix, md, scopes); err != nil {
   320  				return err
   321  			}
   322  		}
   323  		for _, fld := range fd.Extension {
   324  			if err := l.resolveFieldTypes(r, fd, prefix, fld, scopes); err != nil {
   325  				return err
   326  			}
   327  		}
   328  		for _, ed := range fd.EnumType {
   329  			if err := l.resolveEnumTypes(r, fd, prefix, ed, scopes); err != nil {
   330  				return err
   331  			}
   332  		}
   333  		for _, sd := range fd.Service {
   334  			if err := l.resolveServiceTypes(r, fd, prefix, sd, scopes); err != nil {
   335  				return err
   336  			}
   337  		}
   338  	}
   339  	return nil
   340  }
   341  
   342  func (l *linker) resolveEnumTypes(r *parseResult, fd *dpb.FileDescriptorProto, prefix string, ed *dpb.EnumDescriptorProto, scopes []scope) error {
   343  	enumFqn := prefix + ed.GetName()
   344  	if ed.Options != nil {
   345  		if err := l.resolveOptions(r, fd, "enum", enumFqn, proto.MessageName(ed.Options), ed.Options.UninterpretedOption, scopes); err != nil {
   346  			return err
   347  		}
   348  	}
   349  	for _, evd := range ed.Value {
   350  		if evd.Options != nil {
   351  			evFqn := enumFqn + "." + evd.GetName()
   352  			if err := l.resolveOptions(r, fd, "enum value", evFqn, proto.MessageName(evd.Options), evd.Options.UninterpretedOption, scopes); err != nil {
   353  				return err
   354  			}
   355  		}
   356  	}
   357  	return nil
   358  }
   359  
   360  func (l *linker) resolveMessageTypes(r *parseResult, fd *dpb.FileDescriptorProto, prefix string, md *dpb.DescriptorProto, scopes []scope) error {
   361  	fqn := prefix + md.GetName()
   362  	scope := messageScope(fqn, isProto3(fd), l, fd)
   363  	scopes = append(scopes, scope)
   364  	prefix = fqn + "."
   365  
   366  	if md.Options != nil {
   367  		if err := l.resolveOptions(r, fd, "message", fqn, proto.MessageName(md.Options), md.Options.UninterpretedOption, scopes); err != nil {
   368  			return err
   369  		}
   370  	}
   371  
   372  	for _, nmd := range md.NestedType {
   373  		if err := l.resolveMessageTypes(r, fd, prefix, nmd, scopes); err != nil {
   374  			return err
   375  		}
   376  	}
   377  	for _, ned := range md.EnumType {
   378  		if err := l.resolveEnumTypes(r, fd, prefix, ned, scopes); err != nil {
   379  			return err
   380  		}
   381  	}
   382  	for _, fld := range md.Field {
   383  		if err := l.resolveFieldTypes(r, fd, prefix, fld, scopes); err != nil {
   384  			return err
   385  		}
   386  	}
   387  	for _, ood := range md.OneofDecl {
   388  		if ood.Options != nil {
   389  			ooName := fmt.Sprintf("%s.%s", fqn, ood.GetName())
   390  			if err := l.resolveOptions(r, fd, "oneof", ooName, proto.MessageName(ood.Options), ood.Options.UninterpretedOption, scopes); err != nil {
   391  				return err
   392  			}
   393  		}
   394  	}
   395  	for _, fld := range md.Extension {
   396  		if err := l.resolveFieldTypes(r, fd, prefix, fld, scopes); err != nil {
   397  			return err
   398  		}
   399  	}
   400  	for _, er := range md.ExtensionRange {
   401  		if er.Options != nil {
   402  			erName := fmt.Sprintf("%s:%d-%d", fqn, er.GetStart(), er.GetEnd()-1)
   403  			if err := l.resolveOptions(r, fd, "extension range", erName, proto.MessageName(er.Options), er.Options.UninterpretedOption, scopes); err != nil {
   404  				return err
   405  			}
   406  		}
   407  	}
   408  	return nil
   409  }
   410  
   411  func (l *linker) resolveFieldTypes(r *parseResult, fd *dpb.FileDescriptorProto, prefix string, fld *dpb.FieldDescriptorProto, scopes []scope) error {
   412  	thisName := prefix + fld.GetName()
   413  	scope := fmt.Sprintf("field %s", thisName)
   414  	node := r.getFieldNode(fld)
   415  	elemType := "field"
   416  	if fld.GetExtendee() != "" {
   417  		elemType = "extension"
   418  		fqn, dsc, _ := l.resolve(fd, fld.GetExtendee(), true, scopes)
   419  		if dsc == nil {
   420  			return l.errs.handleErrorWithPos(node.FieldExtendee().Start(), "unknown extendee type %s", fld.GetExtendee())
   421  		}
   422  		if dsc == sentinelMissingSymbol {
   423  			return l.errs.handleErrorWithPos(node.FieldExtendee().Start(), "unknown extendee type %s; resolved to %s which is not defined; consider using a leading dot", fld.GetExtendee(), fqn)
   424  		}
   425  		extd, ok := dsc.(*dpb.DescriptorProto)
   426  		if !ok {
   427  			otherType := descriptorType(dsc)
   428  			return l.errs.handleErrorWithPos(node.FieldExtendee().Start(), "extendee is invalid: %s is a %s, not a message", fqn, otherType)
   429  		}
   430  		fld.Extendee = proto.String("." + fqn)
   431  		// make sure the tag number is in range
   432  		found := false
   433  		tag := fld.GetNumber()
   434  		for _, rng := range extd.ExtensionRange {
   435  			if tag >= rng.GetStart() && tag < rng.GetEnd() {
   436  				found = true
   437  				break
   438  			}
   439  		}
   440  		if !found {
   441  			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 {
   442  				return err
   443  			}
   444  		} else {
   445  			// make sure tag is not a duplicate
   446  			usedExtTags := l.extensions[fqn]
   447  			if usedExtTags == nil {
   448  				usedExtTags = map[int32]string{}
   449  				l.extensions[fqn] = usedExtTags
   450  			}
   451  			if other := usedExtTags[fld.GetNumber()]; other != "" {
   452  				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 {
   453  					return err
   454  				}
   455  			} else {
   456  				usedExtTags[fld.GetNumber()] = thisName
   457  			}
   458  		}
   459  	}
   460  
   461  	if fld.Options != nil {
   462  		if err := l.resolveOptions(r, fd, elemType, thisName, proto.MessageName(fld.Options), fld.Options.UninterpretedOption, scopes); err != nil {
   463  			return err
   464  		}
   465  	}
   466  
   467  	if fld.GetTypeName() == "" {
   468  		// scalar type; no further resolution required
   469  		return nil
   470  	}
   471  
   472  	fqn, dsc, proto3 := l.resolve(fd, fld.GetTypeName(), true, scopes)
   473  	if dsc == nil {
   474  		return l.errs.handleErrorWithPos(node.FieldType().Start(), "%s: unknown type %s", scope, fld.GetTypeName())
   475  	}
   476  	if dsc == sentinelMissingSymbol {
   477  		return l.errs.handleErrorWithPos(node.FieldType().Start(), "%s: unknown type %s; resolved to %s which is not defined; consider using a leading dot", scope, fld.GetTypeName(), fqn)
   478  	}
   479  	switch dsc := dsc.(type) {
   480  	case *dpb.DescriptorProto:
   481  		fld.TypeName = proto.String("." + fqn)
   482  		// if type was tentatively unset, we now know it's actually a message
   483  		if fld.Type == nil {
   484  			fld.Type = dpb.FieldDescriptorProto_TYPE_MESSAGE.Enum()
   485  		}
   486  	case *dpb.EnumDescriptorProto:
   487  		if fld.GetExtendee() == "" && isProto3(fd) && !proto3 {
   488  			// fields in a proto3 message cannot refer to proto2 enums
   489  			return l.errs.handleErrorWithPos(node.FieldType().Start(), "%s: cannot use proto2 enum %s in a proto3 message", scope, fld.GetTypeName())
   490  		}
   491  		fld.TypeName = proto.String("." + fqn)
   492  		// the type was tentatively unset, but now we know it's actually an enum
   493  		fld.Type = dpb.FieldDescriptorProto_TYPE_ENUM.Enum()
   494  	default:
   495  		otherType := descriptorType(dsc)
   496  		return l.errs.handleErrorWithPos(node.FieldType().Start(), "%s: invalid type: %s is a %s, not a message or enum", scope, fqn, otherType)
   497  	}
   498  	return nil
   499  }
   500  
   501  func (l *linker) resolveServiceTypes(r *parseResult, fd *dpb.FileDescriptorProto, prefix string, sd *dpb.ServiceDescriptorProto, scopes []scope) error {
   502  	svcFqn := prefix + sd.GetName()
   503  	if sd.Options != nil {
   504  		if err := l.resolveOptions(r, fd, "service", svcFqn, proto.MessageName(sd.Options), sd.Options.UninterpretedOption, scopes); err != nil {
   505  			return err
   506  		}
   507  	}
   508  
   509  	// not a message, but same scoping rules for nested elements as if it were
   510  	scope := messageScope(svcFqn, isProto3(fd), l, fd)
   511  	scopes = append(scopes, scope)
   512  
   513  	for _, mtd := range sd.Method {
   514  		if mtd.Options != nil {
   515  			if err := l.resolveOptions(r, fd, "method", svcFqn+"."+mtd.GetName(), proto.MessageName(mtd.Options), mtd.Options.UninterpretedOption, scopes); err != nil {
   516  				return err
   517  			}
   518  		}
   519  		scope := fmt.Sprintf("method %s.%s", svcFqn, mtd.GetName())
   520  		node := r.getMethodNode(mtd)
   521  		fqn, dsc, _ := l.resolve(fd, mtd.GetInputType(), false, scopes)
   522  		if dsc == nil {
   523  			if err := l.errs.handleErrorWithPos(node.GetInputType().Start(), "%s: unknown request type %s", scope, mtd.GetInputType()); err != nil {
   524  				return err
   525  			}
   526  		} else if dsc == sentinelMissingSymbol {
   527  			if err := l.errs.handleErrorWithPos(node.GetInputType().Start(), "%s: unknown request type %s; resolved to %s which is not defined; consider using a leading dot", scope, mtd.GetInputType(), fqn); err != nil {
   528  				return err
   529  			}
   530  		} else if _, ok := dsc.(*dpb.DescriptorProto); !ok {
   531  			otherType := descriptorType(dsc)
   532  			if err := l.errs.handleErrorWithPos(node.GetInputType().Start(), "%s: invalid request type: %s is a %s, not a message", scope, fqn, otherType); err != nil {
   533  				return err
   534  			}
   535  		} else {
   536  			mtd.InputType = proto.String("." + fqn)
   537  		}
   538  
   539  		// TODO: make input and output type resolution more DRY
   540  		fqn, dsc, _ = l.resolve(fd, mtd.GetOutputType(), false, scopes)
   541  		if dsc == nil {
   542  			if err := l.errs.handleErrorWithPos(node.GetOutputType().Start(), "%s: unknown response type %s", scope, mtd.GetOutputType()); err != nil {
   543  				return err
   544  			}
   545  		} else if dsc == sentinelMissingSymbol {
   546  			if err := l.errs.handleErrorWithPos(node.GetOutputType().Start(), "%s: unknown response type %s; resolved to %s which is not defined; consider using a leading dot", scope, mtd.GetOutputType(), fqn); err != nil {
   547  				return err
   548  			}
   549  		} else if _, ok := dsc.(*dpb.DescriptorProto); !ok {
   550  			otherType := descriptorType(dsc)
   551  			if err := l.errs.handleErrorWithPos(node.GetOutputType().Start(), "%s: invalid response type: %s is a %s, not a message", scope, fqn, otherType); err != nil {
   552  				return err
   553  			}
   554  		} else {
   555  			mtd.OutputType = proto.String("." + fqn)
   556  		}
   557  	}
   558  	return nil
   559  }
   560  
   561  func (l *linker) resolveOptions(r *parseResult, fd *dpb.FileDescriptorProto, elemType, elemName, optType string, opts []*dpb.UninterpretedOption, scopes []scope) error {
   562  	var scope string
   563  	if elemType != "file" {
   564  		scope = fmt.Sprintf("%s %s: ", elemType, elemName)
   565  	}
   566  opts:
   567  	for _, opt := range opts {
   568  		for _, nm := range opt.Name {
   569  			if nm.GetIsExtension() {
   570  				node := r.getOptionNamePartNode(nm)
   571  				fqn, dsc, _ := l.resolve(fd, nm.GetNamePart(), false, scopes)
   572  				if dsc == nil {
   573  					if err := l.errs.handleErrorWithPos(node.Start(), "%sunknown extension %s", scope, nm.GetNamePart()); err != nil {
   574  						return err
   575  					}
   576  					continue opts
   577  				}
   578  				if dsc == sentinelMissingSymbol {
   579  					if err := l.errs.handleErrorWithPos(node.Start(), "%sunknown extension %s; resolved to %s which is not defined; consider using a leading dot", scope, nm.GetNamePart(), fqn); err != nil {
   580  						return err
   581  					}
   582  					continue opts
   583  				}
   584  				if ext, ok := dsc.(*dpb.FieldDescriptorProto); !ok {
   585  					otherType := descriptorType(dsc)
   586  					if err := l.errs.handleErrorWithPos(node.Start(), "%sinvalid extension: %s is a %s, not an extension", scope, nm.GetNamePart(), otherType); err != nil {
   587  						return err
   588  					}
   589  					continue opts
   590  				} else if ext.GetExtendee() == "" {
   591  					if err := l.errs.handleErrorWithPos(node.Start(), "%sinvalid extension: %s is a field but not an extension", scope, nm.GetNamePart()); err != nil {
   592  						return err
   593  					}
   594  					continue opts
   595  				}
   596  				nm.NamePart = proto.String("." + fqn)
   597  			}
   598  		}
   599  	}
   600  	return nil
   601  }
   602  
   603  func (l *linker) resolve(fd *dpb.FileDescriptorProto, name string, onlyTypes bool, scopes []scope) (fqn string, element proto.Message, proto3 bool) {
   604  	if strings.HasPrefix(name, ".") {
   605  		// already fully-qualified
   606  		d, proto3 := l.findSymbol(fd, name[1:])
   607  		if d != nil {
   608  			return name[1:], d, proto3
   609  		}
   610  		return "", nil, false
   611  	}
   612  	// unqualified, so we look in the enclosing (last) scope first and move
   613  	// towards outermost (first) scope, trying to resolve the symbol
   614  	pos := strings.IndexByte(name, '.')
   615  	firstName := name
   616  	if pos > 0 {
   617  		firstName = name[:pos]
   618  	}
   619  	var bestGuess proto.Message
   620  	var bestGuessFqn string
   621  	var bestGuessProto3 bool
   622  	for i := len(scopes) - 1; i >= 0; i-- {
   623  		fqn, d, proto3 := scopes[i](firstName, name)
   624  		if d != nil {
   625  			if !onlyTypes || isType(d) {
   626  				return fqn, d, proto3
   627  			} else if bestGuess == nil {
   628  				bestGuess = d
   629  				bestGuessFqn = fqn
   630  				bestGuessProto3 = proto3
   631  			}
   632  		}
   633  	}
   634  	// we return best guess, even though it was not an allowed kind of
   635  	// descriptor, so caller can print a better error message (e.g.
   636  	// indicating that the name was found but that it's the wrong type)
   637  	return bestGuessFqn, bestGuess, bestGuessProto3
   638  }
   639  
   640  func isType(m proto.Message) bool {
   641  	switch m.(type) {
   642  	case *dpb.DescriptorProto, *dpb.EnumDescriptorProto:
   643  		return true
   644  	}
   645  	return false
   646  }
   647  
   648  // scope represents a lexical scope in a proto file in which messages and enums
   649  // can be declared.
   650  type scope func(firstName, fullName string) (fqn string, element proto.Message, proto3 bool)
   651  
   652  func fileScope(fd *dpb.FileDescriptorProto, l *linker) scope {
   653  	// we search symbols in this file, but also symbols in other files that have
   654  	// the same package as this file or a "parent" package (in protobuf,
   655  	// packages are a hierarchy like C++ namespaces)
   656  	prefixes := internal.CreatePrefixList(fd.GetPackage())
   657  	querySymbol := func(n string) (d proto.Message, isProto3 bool) {
   658  		return l.findSymbol(fd, n)
   659  	}
   660  	return func(firstName, fullName string) (string, proto.Message, bool) {
   661  		for _, prefix := range prefixes {
   662  			var n1, n string
   663  			if prefix == "" {
   664  				// exhausted all prefixes, so it must be in this one
   665  				n1, n = fullName, fullName
   666  			} else {
   667  				n = prefix + "." + fullName
   668  				n1 = prefix + "." + firstName
   669  			}
   670  			d, proto3 := findSymbolRelative(n1, n, querySymbol)
   671  			if d != nil {
   672  				return n, d, proto3
   673  			}
   674  		}
   675  		return "", nil, false
   676  	}
   677  }
   678  
   679  func messageScope(messageName string, proto3 bool, l *linker, fd *dpb.FileDescriptorProto) scope {
   680  	querySymbol := func(n string) (d proto.Message, isProto3 bool) {
   681  		return l.findSymbolInFile(n, fd), false
   682  	}
   683  	return func(firstName, fullName string) (string, proto.Message, bool) {
   684  		n1 := messageName + "." + firstName
   685  		n := messageName + "." + fullName
   686  		d, _ := findSymbolRelative(n1, n, querySymbol)
   687  		if d != nil {
   688  			return n, d, proto3
   689  		}
   690  		return "", nil, false
   691  	}
   692  }
   693  
   694  func findSymbolRelative(firstName, fullName string, query func(name string) (d proto.Message, isProto3 bool)) (d proto.Message, isProto3 bool) {
   695  	d, proto3 := query(firstName)
   696  	if d == nil {
   697  		return nil, false
   698  	}
   699  	if firstName == fullName {
   700  		return d, proto3
   701  	}
   702  	if !isAggregateDescriptor(d) {
   703  		// can't possibly find the rest of full name if
   704  		// the first name indicated a leaf descriptor
   705  		return nil, false
   706  	}
   707  	d, proto3 = query(fullName)
   708  	if d == nil {
   709  		return sentinelMissingSymbol, false
   710  	}
   711  	return d, proto3
   712  }
   713  
   714  func (l *linker) findSymbolInFile(name string, fd *dpb.FileDescriptorProto) proto.Message {
   715  	d, ok := l.descriptorPool[fd][name]
   716  	if ok {
   717  		return d
   718  	}
   719  	_, ok = l.packageNamespaces[fd][name]
   720  	if ok {
   721  		// this sentinel means the name is a valid namespace but
   722  		// does not refer to a descriptor
   723  		return sentinelMissingSymbol
   724  	}
   725  	return nil
   726  }
   727  
   728  func (l *linker) markUsed(entryPoint, used *dpb.FileDescriptorProto) {
   729  	importsForFile := l.usedImports[entryPoint]
   730  	if importsForFile == nil {
   731  		importsForFile = map[string]struct{}{}
   732  		l.usedImports[entryPoint] = importsForFile
   733  	}
   734  	importsForFile[used.GetName()] = struct{}{}
   735  }
   736  
   737  func isAggregateDescriptor(m proto.Message) bool {
   738  	if m == sentinelMissingSymbol {
   739  		// this indicates the name matched a package, not a
   740  		// descriptor, but a package is an aggregate so
   741  		// we return true
   742  		return true
   743  	}
   744  	switch m.(type) {
   745  	case *dpb.DescriptorProto, *dpb.EnumDescriptorProto, *dpb.ServiceDescriptorProto:
   746  		return true
   747  	default:
   748  		return false
   749  	}
   750  }
   751  
   752  // This value is a bogus/nil value, but results in a non-nil
   753  // proto.Message interface value. So we use it as a sentinel
   754  // to indicate "stop searching for symbol... because it
   755  // definitively does not exist".
   756  var sentinelMissingSymbol = (*dpb.DescriptorProto)(nil)
   757  
   758  func (l *linker) findSymbol(fd *dpb.FileDescriptorProto, name string) (element proto.Message, proto3 bool) {
   759  	return l.findSymbolRecursive(fd, fd, name, false, map[*dpb.FileDescriptorProto]struct{}{})
   760  }
   761  
   762  func (l *linker) findSymbolRecursive(entryPoint, fd *dpb.FileDescriptorProto, name string, public bool, checked map[*dpb.FileDescriptorProto]struct{}) (element proto.Message, proto3 bool) {
   763  	if _, ok := checked[fd]; ok {
   764  		// already checked this one
   765  		return nil, false
   766  	}
   767  	checked[fd] = struct{}{}
   768  	d := l.findSymbolInFile(name, fd)
   769  	if d != nil {
   770  		return d, isProto3(fd)
   771  	}
   772  
   773  	// When public = false, we are searching only directly imported symbols. But we
   774  	// also need to search transitive public imports due to semantics of public imports.
   775  	if public {
   776  		for _, depIndex := range fd.PublicDependency {
   777  			dep := fd.Dependency[depIndex]
   778  			depres := l.files[dep]
   779  			if depres == nil {
   780  				// we'll catch this error later
   781  				continue
   782  			}
   783  			if d, proto3 := l.findSymbolRecursive(entryPoint, depres.fd, name, true, checked); d != nil {
   784  				l.markUsed(entryPoint, depres.fd)
   785  				return d, proto3
   786  			}
   787  		}
   788  	} else {
   789  		for _, dep := range fd.Dependency {
   790  			depres := l.files[dep]
   791  			if depres == nil {
   792  				// we'll catch this error later
   793  				continue
   794  			}
   795  			if d, proto3 := l.findSymbolRecursive(entryPoint, depres.fd, name, true, checked); d != nil {
   796  				l.markUsed(entryPoint, depres.fd)
   797  				return d, proto3
   798  			}
   799  		}
   800  	}
   801  
   802  	return nil, false
   803  }
   804  
   805  func isProto3(fd *dpb.FileDescriptorProto) bool {
   806  	return fd.GetSyntax() == "proto3"
   807  }
   808  
   809  func (l *linker) createdLinkedDescriptors() (map[string]*desc.FileDescriptor, error) {
   810  	names := make([]string, 0, len(l.files))
   811  	for name := range l.files {
   812  		names = append(names, name)
   813  	}
   814  	sort.Strings(names)
   815  	linked := map[string]*desc.FileDescriptor{}
   816  	for _, name := range names {
   817  		if _, err := l.linkFile(name, nil, nil, linked); err != nil {
   818  			return nil, err
   819  		}
   820  	}
   821  	return linked, nil
   822  }
   823  
   824  func (l *linker) linkFile(name string, rootImportLoc *SourcePos, seen []string, linked map[string]*desc.FileDescriptor) (*desc.FileDescriptor, error) {
   825  	// check for import cycle
   826  	for _, s := range seen {
   827  		if name == s {
   828  			var msg bytes.Buffer
   829  			first := true
   830  			for _, s := range seen {
   831  				if first {
   832  					first = false
   833  				} else {
   834  					msg.WriteString(" -> ")
   835  				}
   836  				_, _ = fmt.Fprintf(&msg, "%q", s)
   837  			}
   838  			_, _ = fmt.Fprintf(&msg, " -> %q", name)
   839  			return nil, ErrorWithSourcePos{
   840  				Underlying: fmt.Errorf("cycle found in imports: %s", msg.String()),
   841  				Pos:        rootImportLoc,
   842  			}
   843  		}
   844  	}
   845  	seen = append(seen, name)
   846  
   847  	if lfd, ok := linked[name]; ok {
   848  		// already linked
   849  		return lfd, nil
   850  	}
   851  	r := l.files[name]
   852  	if r == nil {
   853  		importer := seen[len(seen)-2] // len-1 is *this* file, before that is the one that imported it
   854  		return nil, fmt.Errorf("no descriptor found for %q, imported by %q", name, importer)
   855  	}
   856  	var deps []*desc.FileDescriptor
   857  	if rootImportLoc == nil {
   858  		// try to find a source location for this "root" import
   859  		decl := r.getFileNode(r.fd)
   860  		fnode, ok := decl.(*ast.FileNode)
   861  		if ok {
   862  			for _, decl := range fnode.Decls {
   863  				if dep, ok := decl.(*ast.ImportNode); ok {
   864  					ldep, err := l.linkFile(dep.Name.AsString(), dep.Name.Start(), seen, linked)
   865  					if err != nil {
   866  						return nil, err
   867  					}
   868  					deps = append(deps, ldep)
   869  				}
   870  			}
   871  		} else {
   872  			// no AST? just use the descriptor
   873  			for _, dep := range r.fd.Dependency {
   874  				ldep, err := l.linkFile(dep, decl.Start(), seen, linked)
   875  				if err != nil {
   876  					return nil, err
   877  				}
   878  				deps = append(deps, ldep)
   879  			}
   880  		}
   881  	} else {
   882  		// we can just use the descriptor since we don't need source location
   883  		// (we'll just attribute any import cycles found to the "root" import)
   884  		for _, dep := range r.fd.Dependency {
   885  			ldep, err := l.linkFile(dep, rootImportLoc, seen, linked)
   886  			if err != nil {
   887  				return nil, err
   888  			}
   889  			deps = append(deps, ldep)
   890  		}
   891  	}
   892  	lfd, err := desc.CreateFileDescriptor(r.fd, deps...)
   893  	if err != nil {
   894  		return nil, fmt.Errorf("error linking %q: %s", name, err)
   895  	}
   896  	linked[name] = lfd
   897  	return lfd, nil
   898  }
   899  
   900  func (l *linker) checkForUnusedImports(filename string) {
   901  	r := l.files[filename]
   902  	usedImports := l.usedImports[r.fd]
   903  	node := r.nodes[r.fd]
   904  	fileNode, _ := node.(*ast.FileNode)
   905  	for i, dep := range r.fd.Dependency {
   906  		if _, ok := usedImports[dep]; !ok {
   907  			isPublic := false
   908  			// it's fine if it's a public import
   909  			for _, j := range r.fd.PublicDependency {
   910  				if i == int(j) {
   911  					isPublic = true
   912  					break
   913  				}
   914  			}
   915  			if isPublic {
   916  				break
   917  			}
   918  			var pos *SourcePos
   919  			if fileNode != nil {
   920  				for _, decl := range fileNode.Decls {
   921  					imp, ok := decl.(*ast.ImportNode)
   922  					if !ok {
   923  						continue
   924  					}
   925  					if imp.Name.AsString() == dep {
   926  						pos = imp.Start()
   927  					}
   928  				}
   929  			}
   930  			if pos == nil {
   931  				pos = ast.UnknownPos(r.fd.GetName())
   932  			}
   933  			r.errs.warn(pos, errUnusedImport(dep))
   934  		}
   935  	}
   936  }