// 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 (
	
	

	
	
	
	
	
	
	

	
)

func ( []filedesc.Enum,  []*descriptorpb.EnumDescriptorProto) error {
	for ,  := range  {
		 := &[]
		if  := .L2.ReservedNames.CheckValid();  != nil {
			return errors.New("enum %q reserved names has %v", .FullName(), )
		}
		if  := .L2.ReservedRanges.CheckValid();  != nil {
			return errors.New("enum %q reserved ranges has %v", .FullName(), )
		}
		if len(.GetValue()) == 0 {
			return errors.New("enum %q must contain at least one value declaration", .FullName())
		}
		 := .GetOptions().GetAllowAlias()
		 := false
		for  := 0;  < .Values().Len(); ++ {
			 := .Values().Get()
			if  := .Values().ByNumber(.Number());  !=  {
				 = true
				if ! {
					return errors.New("enum %q has conflicting non-aliased values on number %d: %q with %q", .FullName(), .Number(), .Name(), .Name())
				}
			}
		}
		if  && ! {
			return errors.New("enum %q allows aliases, but none were found", .FullName())
		}
		if .Syntax() == protoreflect.Proto3 {
			if  := .Values().Get(0); .Number() != 0 {
				return errors.New("enum %q using proto3 semantics must have zero number for the first value", .FullName())
			}
			// Verify that value names in proto3 do not conflict if the
			// case-insensitive prefix is removed.
			// See protoc v3.8.0: src/google/protobuf/descriptor.cc:4991-5055
			 := map[string]protoreflect.EnumValueDescriptor{}
			 := strings.Replace(strings.ToLower(string(.Name())), "_", "", -1)
			for  := 0;  < .Values().Len(); ++ {
				 := .Values().Get()
				 := strs.EnumValueName(strs.TrimEnumPrefix(string(.Name()), ))
				if ,  := [];  && .Number() != .Number() {
					return errors.New("enum %q using proto3 semantics has conflict: %q with %q", .FullName(), .Name(), .Name())
				}
				[] = 
			}
		}

		for ,  := range .GetValue() {
			 := &.L2.Values.List[]
			if .Number == nil {
				return errors.New("enum value %q must have a specified number", .FullName())
			}
			if .L2.ReservedNames.Has(.Name()) {
				return errors.New("enum value %q must not use reserved name", .FullName())
			}
			if .L2.ReservedRanges.Has(.Number()) {
				return errors.New("enum value %q must not use reserved number %d", .FullName(), .Number())
			}
		}
	}
	return nil
}

func ( []filedesc.Message,  []*descriptorpb.DescriptorProto) error {
	for ,  := range  {
		 := &[]

		// Handle the message descriptor itself.
		 := .GetOptions().GetMessageSetWireFormat()
		if  := .L2.ReservedNames.CheckValid();  != nil {
			return errors.New("message %q reserved names has %v", .FullName(), )
		}
		if  := .L2.ReservedRanges.CheckValid();  != nil {
			return errors.New("message %q reserved ranges has %v", .FullName(), )
		}
		if  := .L2.ExtensionRanges.CheckValid();  != nil {
			return errors.New("message %q extension ranges has %v", .FullName(), )
		}
		if  := (*filedesc.FieldRanges).CheckOverlap(&.L2.ReservedRanges, &.L2.ExtensionRanges);  != nil {
			return errors.New("message %q reserved and extension ranges has %v", .FullName(), )
		}
		for  := 0;  < .Fields().Len(); ++ {
			 := .Fields().Get()
			if  := .Fields().ByNumber(.Number());  !=  {
				return errors.New("message %q has conflicting fields: %q with %q", .FullName(), .Name(), .Name())
			}
		}
		if  && !flags.ProtoLegacy {
			return errors.New("message %q is a MessageSet, which is a legacy proto1 feature that is no longer supported", .FullName())
		}
		if  && (.Syntax() != protoreflect.Proto2 || .Fields().Len() > 0 || .ExtensionRanges().Len() == 0) {
			return errors.New("message %q is an invalid proto1 MessageSet", .FullName())
		}
		if .Syntax() == protoreflect.Proto3 {
			if .ExtensionRanges().Len() > 0 {
				return errors.New("message %q using proto3 semantics cannot have extension ranges", .FullName())
			}
			// Verify that field names in proto3 do not conflict if lowercased
			// with all underscores removed.
			// See protoc v3.8.0: src/google/protobuf/descriptor.cc:5830-5847
			 := map[string]protoreflect.FieldDescriptor{}
			for  := 0;  < .Fields().Len(); ++ {
				 := .Fields().Get()
				 := strings.Replace(strings.ToLower(string(.Name())), "_", "", -1)
				if ,  := [];  {
					return errors.New("message %q using proto3 semantics has conflict: %q with %q", .FullName(), .Name(), .Name())
				}
				[] = 
			}
		}

		for ,  := range .GetField() {
			 := &.L2.Fields.List[]
			if .L2.ReservedNames.Has(.Name()) {
				return errors.New("message field %q must not use reserved name", .FullName())
			}
			if !.Number().IsValid() {
				return errors.New("message field %q has an invalid number: %d", .FullName(), .Number())
			}
			if !.Cardinality().IsValid() {
				return errors.New("message field %q has an invalid cardinality: %d", .FullName(), .Cardinality())
			}
			if .L2.ReservedRanges.Has(.Number()) {
				return errors.New("message field %q must not use reserved number %d", .FullName(), .Number())
			}
			if .L2.ExtensionRanges.Has(.Number()) {
				return errors.New("message field %q with number %d in extension range", .FullName(), .Number())
			}
			if .Extendee != nil {
				return errors.New("message field %q may not have extendee: %q", .FullName(), .GetExtendee())
			}
			if .L1.IsProto3Optional {
				if .Syntax() != protoreflect.Proto3 {
					return errors.New("message field %q under proto3 optional semantics must be specified in the proto3 syntax", .FullName())
				}
				if .Cardinality() != protoreflect.Optional {
					return errors.New("message field %q under proto3 optional semantics must have optional cardinality", .FullName())
				}
				if .ContainingOneof() != nil && .ContainingOneof().Fields().Len() != 1 {
					return errors.New("message field %q under proto3 optional semantics must be within a single element oneof", .FullName())
				}
			}
			if .IsWeak() && !flags.ProtoLegacy {
				return errors.New("message field %q is a weak field, which is a legacy proto1 feature that is no longer supported", .FullName())
			}
			if .IsWeak() && (.Syntax() != protoreflect.Proto2 || !isOptionalMessage() || .ContainingOneof() != nil) {
				return errors.New("message field %q may only be weak for an optional message", .FullName())
			}
			if .IsPacked() && !isPackable() {
				return errors.New("message field %q is not packable", .FullName())
			}
			if  := checkValidGroup();  != nil {
				return errors.New("message field %q is an invalid group: %v", .FullName(), )
			}
			if  := checkValidMap();  != nil {
				return errors.New("message field %q is an invalid map: %v", .FullName(), )
			}
			if .Syntax() == protoreflect.Proto3 {
				if .Cardinality() == protoreflect.Required {
					return errors.New("message field %q using proto3 semantics cannot be required", .FullName())
				}
				if .Enum() != nil && !.Enum().IsPlaceholder() && .Enum().Syntax() != protoreflect.Proto3 {
					return errors.New("message field %q using proto3 semantics may only depend on a proto3 enum", .FullName())
				}
			}
		}
		 := false // synthetic oneofs for proto3 optional must come after real oneofs
		for  := range .GetOneofDecl() {
			 := &.L2.Oneofs.List[]
			if .Fields().Len() == 0 {
				return errors.New("message oneof %q must contain at least one field declaration", .FullName())
			}
			if  := .Fields().Len(); -1 != (.Fields().Get(-1).Index() - .Fields().Get(0).Index()) {
				return errors.New("message oneof %q must have consecutively declared fields", .FullName())
			}

			if .IsSynthetic() {
				 = true
				continue
			}
			if !.IsSynthetic() &&  {
				return errors.New("message oneof %q must be declared before synthetic oneofs", .FullName())
			}

			for  := 0;  < .Fields().Len(); ++ {
				 := .Fields().Get()
				if .Cardinality() != protoreflect.Optional {
					return errors.New("message field %q belongs in a oneof and must be optional", .FullName())
				}
				if .IsWeak() {
					return errors.New("message field %q belongs in a oneof and must not be a weak reference", .FullName())
				}
			}
		}

		if  := validateEnumDeclarations(.L1.Enums.List, .GetEnumType());  != nil {
			return 
		}
		if  := (.L1.Messages.List, .GetNestedType());  != nil {
			return 
		}
		if  := validateExtensionDeclarations(.L1.Extensions.List, .GetExtension());  != nil {
			return 
		}
	}
	return nil
}

func ( []filedesc.Extension,  []*descriptorpb.FieldDescriptorProto) error {
	for ,  := range  {
		 := &[]
		// NOTE: Avoid using the IsValid method since extensions to MessageSet
		// may have a field number higher than normal. This check only verifies
		// that the number is not negative or reserved. We check again later
		// if we know that the extendee is definitely not a MessageSet.
		if  := .Number();  < 0 || (protowire.FirstReservedNumber <=  &&  <= protowire.LastReservedNumber) {
			return errors.New("extension field %q has an invalid number: %d", .FullName(), .Number())
		}
		if !.Cardinality().IsValid() || .Cardinality() == protoreflect.Required {
			return errors.New("extension field %q has an invalid cardinality: %d", .FullName(), .Cardinality())
		}
		if .JsonName != nil {
			// A bug in older versions of protoc would always populate the
			// "json_name" option for extensions when it is meaningless.
			// When it did so, it would always use the camel-cased field name.
			if .GetJsonName() != strs.JSONCamelCase(string(.Name())) {
				return errors.New("extension field %q may not have an explicitly set JSON name: %q", .FullName(), .GetJsonName())
			}
		}
		if .OneofIndex != nil {
			return errors.New("extension field %q may not be part of a oneof", .FullName())
		}
		if  := .ContainingMessage(); !.IsPlaceholder() {
			if !.ExtensionRanges().Has(.Number()) {
				return errors.New("extension field %q extends %q with non-extension field number: %d", .FullName(), .FullName(), .Number())
			}
			 := .Options().(*descriptorpb.MessageOptions).GetMessageSetWireFormat()
			if  && !isOptionalMessage() {
				return errors.New("extension field %q extends MessageSet and must be an optional message", .FullName())
			}
			if ! && !.Number().IsValid() {
				return errors.New("extension field %q has an invalid number: %d", .FullName(), .Number())
			}
		}
		if .GetOptions().GetWeak() {
			return errors.New("extension field %q cannot be a weak reference", .FullName())
		}
		if .IsPacked() && !isPackable() {
			return errors.New("extension field %q is not packable", .FullName())
		}
		if  := checkValidGroup();  != nil {
			return errors.New("extension field %q is an invalid group: %v", .FullName(), )
		}
		if  := .Message();  != nil && .IsMapEntry() {
			return errors.New("extension field %q cannot be a map entry", .FullName())
		}
		if .Syntax() == protoreflect.Proto3 {
			switch .ContainingMessage().FullName() {
			case (*descriptorpb.FileOptions)(nil).ProtoReflect().Descriptor().FullName():
			case (*descriptorpb.EnumOptions)(nil).ProtoReflect().Descriptor().FullName():
			case (*descriptorpb.EnumValueOptions)(nil).ProtoReflect().Descriptor().FullName():
			case (*descriptorpb.MessageOptions)(nil).ProtoReflect().Descriptor().FullName():
			case (*descriptorpb.FieldOptions)(nil).ProtoReflect().Descriptor().FullName():
			case (*descriptorpb.OneofOptions)(nil).ProtoReflect().Descriptor().FullName():
			case (*descriptorpb.ExtensionRangeOptions)(nil).ProtoReflect().Descriptor().FullName():
			case (*descriptorpb.ServiceOptions)(nil).ProtoReflect().Descriptor().FullName():
			case (*descriptorpb.MethodOptions)(nil).ProtoReflect().Descriptor().FullName():
			default:
				return errors.New("extension field %q cannot be declared in proto3 unless extended descriptor options", .FullName())
			}
		}
	}
	return nil
}

// isOptionalMessage reports whether this is an optional message.
// If the kind is unknown, it is assumed to be a message.
func ( protoreflect.FieldDescriptor) bool {
	return (.Kind() == 0 || .Kind() == protoreflect.MessageKind) && .Cardinality() == protoreflect.Optional
}

// isPackable checks whether the pack option can be specified.
func ( protoreflect.FieldDescriptor) bool {
	switch .Kind() {
	case protoreflect.StringKind, protoreflect.BytesKind, protoreflect.MessageKind, protoreflect.GroupKind:
		return false
	}
	return .IsList()
}

// checkValidGroup reports whether fd is a valid group according to the same
// rules that protoc imposes.
func ( protoreflect.FieldDescriptor) error {
	 := .Message()
	switch {
	case .Kind() != protoreflect.GroupKind:
		return nil
	case .Syntax() != protoreflect.Proto2:
		return errors.New("invalid under proto2 semantics")
	case  == nil || .IsPlaceholder():
		return errors.New("message must be resolvable")
	case .FullName().Parent() != .FullName().Parent():
		return errors.New("message and field must be declared in the same scope")
	case !unicode.IsUpper(rune(.Name()[0])):
		return errors.New("message name must start with an uppercase")
	case .Name() != protoreflect.Name(strings.ToLower(string(.Name()))):
		return errors.New("field name must be lowercased form of the message name")
	}
	return nil
}

// checkValidMap checks whether the field is a valid map according to the same
// rules that protoc imposes.
// See protoc v3.8.0: src/google/protobuf/descriptor.cc:6045-6115
func ( protoreflect.FieldDescriptor) error {
	 := .Message()
	switch {
	case  == nil || !.IsMapEntry():
		return nil
	case .FullName().Parent() != .FullName().Parent():
		return errors.New("message and field must be declared in the same scope")
	case .Name() != protoreflect.Name(strs.MapEntryName(string(.Name()))):
		return errors.New("incorrect implicit map entry name")
	case .Cardinality() != protoreflect.Repeated:
		return errors.New("field must be repeated")
	case .Fields().Len() != 2:
		return errors.New("message must have exactly two fields")
	case .ExtensionRanges().Len() > 0:
		return errors.New("message must not have any extension ranges")
	case .Enums().Len()+.Messages().Len()+.Extensions().Len() > 0:
		return errors.New("message must not have any nested declarations")
	}
	 := .Fields().Get(0)
	 := .Fields().Get(1)
	switch {
	case .Name() != genid.MapEntry_Key_field_name || .Number() != genid.MapEntry_Key_field_number || .Cardinality() != protoreflect.Optional || .ContainingOneof() != nil || .HasDefault():
		return errors.New("invalid key field")
	case .Name() != genid.MapEntry_Value_field_name || .Number() != genid.MapEntry_Value_field_number || .Cardinality() != protoreflect.Optional || .ContainingOneof() != nil || .HasDefault():
		return errors.New("invalid value field")
	}
	switch .Kind() {
	case protoreflect.BoolKind: // bool
	case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: // int32
	case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: // int64
	case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: // uint32
	case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: // uint64
	case protoreflect.StringKind: // string
	default:
		return errors.New("invalid key kind: %v", .Kind())
	}
	if  := .Enum();  != nil && .Values().Len() > 0 && .Values().Get(0).Number() != 0 {
		return errors.New("map enum value must have zero number for the first value")
	}
	return nil
}