// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package protodesc

import (
	
	
	
	
	

	
)

// resolver is a wrapper around a local registry of declarations within the file
// and the remote resolver. The remote resolver is restricted to only return
// descriptors that have been imported.
type resolver struct {
	local   descsByName
	remote  Resolver
	imports importSet

	allowUnresolvable bool
}

func ( *resolver) ( []filedesc.Message,  []*descriptorpb.DescriptorProto) ( error) {
	for ,  := range  {
		 := &[]
		for ,  := range .GetField() {
			 := &.L2.Fields.List[]
			if .L1.Cardinality == protoreflect.Required {
				.L2.RequiredNumbers.List = append(.L2.RequiredNumbers.List, .L1.Number)
			}
			if .OneofIndex != nil {
				 := int(.GetOneofIndex())
				if !(0 <=  &&  < len(.GetOneofDecl())) {
					return errors.New("message field %q has an invalid oneof index: %d", .FullName(), )
				}
				 := &.L2.Oneofs.List[]
				.L1.ContainingOneof = 
				.L1.Fields.List = append(.L1.Fields.List, )
			}

			if .L1.Kind, .L1.Enum, .L1.Message,  = .findTarget(.Kind(), .Parent().FullName(), partialName(.GetTypeName()), .IsWeak());  != nil {
				return errors.New("message field %q cannot resolve type: %v", .FullName(), )
			}
			if .DefaultValue != nil {
				, ,  := unmarshalDefault(.GetDefaultValue(), , .allowUnresolvable)
				if  != nil {
					return errors.New("message field %q has invalid default: %v", .FullName(), )
				}
				.L1.Default = filedesc.DefaultValue(, )
			}
		}

		if  := .(.L1.Messages.List, .GetNestedType());  != nil {
			return 
		}
		if  := .resolveExtensionDependencies(.L1.Extensions.List, .GetExtension());  != nil {
			return 
		}
	}
	return nil
}

func ( *resolver) ( []filedesc.Extension,  []*descriptorpb.FieldDescriptorProto) ( error) {
	for ,  := range  {
		 := &[]
		if .L1.Extendee,  = .findMessageDescriptor(.Parent().FullName(), partialName(.GetExtendee()), false);  != nil {
			return errors.New("extension field %q cannot resolve extendee: %v", .FullName(), )
		}
		if .L1.Kind, .L2.Enum, .L2.Message,  = .findTarget(.Kind(), .Parent().FullName(), partialName(.GetTypeName()), false);  != nil {
			return errors.New("extension field %q cannot resolve type: %v", .FullName(), )
		}
		if .DefaultValue != nil {
			, ,  := unmarshalDefault(.GetDefaultValue(), , .allowUnresolvable)
			if  != nil {
				return errors.New("extension field %q has invalid default: %v", .FullName(), )
			}
			.L2.Default = filedesc.DefaultValue(, )
		}
	}
	return nil
}

func ( *resolver) ( []filedesc.Service,  []*descriptorpb.ServiceDescriptorProto) ( error) {
	for ,  := range  {
		 := &[]
		for ,  := range .GetMethod() {
			 := &.L2.Methods.List[]
			.L1.Input,  = .findMessageDescriptor(.Parent().FullName(), partialName(.GetInputType()), false)
			if  != nil {
				return errors.New("service method %q cannot resolve input: %v", .FullName(), )
			}
			.L1.Output,  = .findMessageDescriptor(.FullName(), partialName(.GetOutputType()), false)
			if  != nil {
				return errors.New("service method %q cannot resolve output: %v", .FullName(), )
			}
		}
	}
	return nil
}

// findTarget finds an enum or message descriptor if k is an enum, message,
// group, or unknown. If unknown, and the name could be resolved, the kind
// returned kind is set based on the type of the resolved descriptor.
func ( *resolver) ( protoreflect.Kind,  protoreflect.FullName,  partialName,  bool) (protoreflect.Kind, protoreflect.EnumDescriptor, protoreflect.MessageDescriptor, error) {
	switch  {
	case protoreflect.EnumKind:
		,  := .findEnumDescriptor(, , )
		if  != nil {
			return 0, nil, nil, 
		}
		return , , nil, nil
	case protoreflect.MessageKind, protoreflect.GroupKind:
		,  := .findMessageDescriptor(, , )
		if  != nil {
			return 0, nil, nil, 
		}
		return , nil, , nil
	case 0:
		// Handle unspecified kinds (possible with parsers that operate
		// on a per-file basis without knowledge of dependencies).
		,  := .findDescriptor(, )
		if  == protoregistry.NotFound && (.allowUnresolvable || ) {
			return , filedesc.PlaceholderEnum(.FullName()), filedesc.PlaceholderMessage(.FullName()), nil
		} else if  == protoregistry.NotFound {
			return 0, nil, nil, errors.New("%q not found", .FullName())
		} else if  != nil {
			return 0, nil, nil, 
		}
		switch d := .(type) {
		case protoreflect.EnumDescriptor:
			return protoreflect.EnumKind, , nil, nil
		case protoreflect.MessageDescriptor:
			return protoreflect.MessageKind, nil, , nil
		default:
			return 0, nil, nil, errors.New("unknown kind")
		}
	default:
		if  != "" {
			return 0, nil, nil, errors.New("target name cannot be specified for %v", )
		}
		if !.IsValid() {
			return 0, nil, nil, errors.New("invalid kind: %d", )
		}
		return , nil, nil, nil
	}
}

// findDescriptor finds the descriptor by name,
// which may be a relative name within some scope.
//
// Suppose the scope was "fizz.buzz" and the reference was "Foo.Bar",
// then the following full names are searched:
//   - fizz.buzz.Foo.Bar
//   - fizz.Foo.Bar
//   - Foo.Bar
func ( *resolver) ( protoreflect.FullName,  partialName) (protoreflect.Descriptor, error) {
	if !.IsValid() {
		return nil, errors.New("invalid name reference: %q", )
	}
	if .IsFull() {
		,  = "", [1:]
	}
	var  protoreflect.Descriptor
	for {
		// Derive the full name to search.
		 := protoreflect.FullName()
		if  != "" {
			 =  + "." + 
		}

		// Check the current file for the descriptor.
		if ,  := .local[];  {
			return , nil
		}

		// Check the remote registry for the descriptor.
		,  := .remote.FindDescriptorByName()
		if  == nil {
			// Only allow descriptors covered by one of the imports.
			if .imports[.ParentFile().Path()] {
				return , nil
			}
			 = 
		} else if  != protoregistry.NotFound {
			return nil, errors.Wrap(, "%q", )
		}

		// Continue on at a higher level of scoping.
		if  == "" {
			if  := ;  != nil {
				return nil, errors.New("resolved %q, but %q is not imported", .FullName(), .ParentFile().Path())
			}
			return nil, protoregistry.NotFound
		}
		 = .Parent()
	}
}

func ( *resolver) ( protoreflect.FullName,  partialName,  bool) (protoreflect.EnumDescriptor, error) {
	,  := .findDescriptor(, )
	if  == protoregistry.NotFound && (.allowUnresolvable || ) {
		return filedesc.PlaceholderEnum(.FullName()), nil
	} else if  == protoregistry.NotFound {
		return nil, errors.New("%q not found", .FullName())
	} else if  != nil {
		return nil, 
	}
	,  := .(protoreflect.EnumDescriptor)
	if ! {
		return nil, errors.New("resolved %q, but it is not an enum", .FullName())
	}
	return , nil
}

func ( *resolver) ( protoreflect.FullName,  partialName,  bool) (protoreflect.MessageDescriptor, error) {
	,  := .findDescriptor(, )
	if  == protoregistry.NotFound && (.allowUnresolvable || ) {
		return filedesc.PlaceholderMessage(.FullName()), nil
	} else if  == protoregistry.NotFound {
		return nil, errors.New("%q not found", .FullName())
	} else if  != nil {
		return nil, 
	}
	,  := .(protoreflect.MessageDescriptor)
	if ! {
		return nil, errors.New("resolved %q, but it is not an message", .FullName())
	}
	return , nil
}

// partialName is the partial name. A leading dot means that the name is full,
// otherwise the name is relative to some current scope.
// See google.protobuf.FieldDescriptorProto.type_name.
type partialName string

func ( partialName) () bool {
	return len() > 0 && [0] == '.'
}

func ( partialName) () bool {
	if .IsFull() {
		return protoreflect.FullName([1:]).IsValid()
	}
	return protoreflect.FullName().IsValid()
}

const unknownPrefix = "*."

// FullName converts the partial name to a full name on a best-effort basis.
// If relative, it creates an invalid full name, using a "*." prefix
// to indicate that the start of the full name is unknown.
func ( partialName) () protoreflect.FullName {
	if .IsFull() {
		return protoreflect.FullName([1:])
	}
	return protoreflect.FullName(unknownPrefix + )
}

func ( string,  protoreflect.FieldDescriptor,  bool) (protoreflect.Value, protoreflect.EnumValueDescriptor, error) {
	var  protoreflect.EnumValueDescriptors
	if .Enum() != nil {
		 = .Enum().Values()
	}
	, ,  := defval.Unmarshal(, .Kind(), , defval.Descriptor)
	if  != nil &&  &&  != nil && protoreflect.Name().IsValid() {
		 = protoreflect.ValueOfEnum(0)
		if .Len() > 0 {
			 = protoreflect.ValueOfEnum(.Get(0).Number())
		}
		 = filedesc.PlaceholderEnumValue(.Enum().FullName().Parent().Append(protoreflect.Name()))
	} else if  != nil {
		return , , 
	}
	if .Syntax() == protoreflect.Proto3 {
		return , , errors.New("cannot be specified under proto3 semantics")
	}
	if .Kind() == protoreflect.MessageKind || .Kind() == protoreflect.GroupKind || .Cardinality() == protoreflect.Repeated {
		return , , errors.New("cannot be specified on composite types")
	}
	return , , nil
}