gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

desc_validate.go (16546B)


      1 // Copyright 2019 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package protodesc
      6 
      7 import (
      8 	"strings"
      9 	"unicode"
     10 
     11 	"google.golang.org/protobuf/encoding/protowire"
     12 	"google.golang.org/protobuf/internal/errors"
     13 	"google.golang.org/protobuf/internal/filedesc"
     14 	"google.golang.org/protobuf/internal/flags"
     15 	"google.golang.org/protobuf/internal/genid"
     16 	"google.golang.org/protobuf/internal/strs"
     17 	"google.golang.org/protobuf/reflect/protoreflect"
     18 
     19 	"google.golang.org/protobuf/types/descriptorpb"
     20 )
     21 
     22 func validateEnumDeclarations(es []filedesc.Enum, eds []*descriptorpb.EnumDescriptorProto) error {
     23 	for i, ed := range eds {
     24 		e := &es[i]
     25 		if err := e.L2.ReservedNames.CheckValid(); err != nil {
     26 			return errors.New("enum %q reserved names has %v", e.FullName(), err)
     27 		}
     28 		if err := e.L2.ReservedRanges.CheckValid(); err != nil {
     29 			return errors.New("enum %q reserved ranges has %v", e.FullName(), err)
     30 		}
     31 		if len(ed.GetValue()) == 0 {
     32 			return errors.New("enum %q must contain at least one value declaration", e.FullName())
     33 		}
     34 		allowAlias := ed.GetOptions().GetAllowAlias()
     35 		foundAlias := false
     36 		for i := 0; i < e.Values().Len(); i++ {
     37 			v1 := e.Values().Get(i)
     38 			if v2 := e.Values().ByNumber(v1.Number()); v1 != v2 {
     39 				foundAlias = true
     40 				if !allowAlias {
     41 					return errors.New("enum %q has conflicting non-aliased values on number %d: %q with %q", e.FullName(), v1.Number(), v1.Name(), v2.Name())
     42 				}
     43 			}
     44 		}
     45 		if allowAlias && !foundAlias {
     46 			return errors.New("enum %q allows aliases, but none were found", e.FullName())
     47 		}
     48 		if e.Syntax() == protoreflect.Proto3 {
     49 			if v := e.Values().Get(0); v.Number() != 0 {
     50 				return errors.New("enum %q using proto3 semantics must have zero number for the first value", v.FullName())
     51 			}
     52 			// Verify that value names in proto3 do not conflict if the
     53 			// case-insensitive prefix is removed.
     54 			// See protoc v3.8.0: src/google/protobuf/descriptor.cc:4991-5055
     55 			names := map[string]protoreflect.EnumValueDescriptor{}
     56 			prefix := strings.Replace(strings.ToLower(string(e.Name())), "_", "", -1)
     57 			for i := 0; i < e.Values().Len(); i++ {
     58 				v1 := e.Values().Get(i)
     59 				s := strs.EnumValueName(strs.TrimEnumPrefix(string(v1.Name()), prefix))
     60 				if v2, ok := names[s]; ok && v1.Number() != v2.Number() {
     61 					return errors.New("enum %q using proto3 semantics has conflict: %q with %q", e.FullName(), v1.Name(), v2.Name())
     62 				}
     63 				names[s] = v1
     64 			}
     65 		}
     66 
     67 		for j, vd := range ed.GetValue() {
     68 			v := &e.L2.Values.List[j]
     69 			if vd.Number == nil {
     70 				return errors.New("enum value %q must have a specified number", v.FullName())
     71 			}
     72 			if e.L2.ReservedNames.Has(v.Name()) {
     73 				return errors.New("enum value %q must not use reserved name", v.FullName())
     74 			}
     75 			if e.L2.ReservedRanges.Has(v.Number()) {
     76 				return errors.New("enum value %q must not use reserved number %d", v.FullName(), v.Number())
     77 			}
     78 		}
     79 	}
     80 	return nil
     81 }
     82 
     83 func validateMessageDeclarations(ms []filedesc.Message, mds []*descriptorpb.DescriptorProto) error {
     84 	for i, md := range mds {
     85 		m := &ms[i]
     86 
     87 		// Handle the message descriptor itself.
     88 		isMessageSet := md.GetOptions().GetMessageSetWireFormat()
     89 		if err := m.L2.ReservedNames.CheckValid(); err != nil {
     90 			return errors.New("message %q reserved names has %v", m.FullName(), err)
     91 		}
     92 		if err := m.L2.ReservedRanges.CheckValid(isMessageSet); err != nil {
     93 			return errors.New("message %q reserved ranges has %v", m.FullName(), err)
     94 		}
     95 		if err := m.L2.ExtensionRanges.CheckValid(isMessageSet); err != nil {
     96 			return errors.New("message %q extension ranges has %v", m.FullName(), err)
     97 		}
     98 		if err := (*filedesc.FieldRanges).CheckOverlap(&m.L2.ReservedRanges, &m.L2.ExtensionRanges); err != nil {
     99 			return errors.New("message %q reserved and extension ranges has %v", m.FullName(), err)
    100 		}
    101 		for i := 0; i < m.Fields().Len(); i++ {
    102 			f1 := m.Fields().Get(i)
    103 			if f2 := m.Fields().ByNumber(f1.Number()); f1 != f2 {
    104 				return errors.New("message %q has conflicting fields: %q with %q", m.FullName(), f1.Name(), f2.Name())
    105 			}
    106 		}
    107 		if isMessageSet && !flags.ProtoLegacy {
    108 			return errors.New("message %q is a MessageSet, which is a legacy proto1 feature that is no longer supported", m.FullName())
    109 		}
    110 		if isMessageSet && (m.Syntax() != protoreflect.Proto2 || m.Fields().Len() > 0 || m.ExtensionRanges().Len() == 0) {
    111 			return errors.New("message %q is an invalid proto1 MessageSet", m.FullName())
    112 		}
    113 		if m.Syntax() == protoreflect.Proto3 {
    114 			if m.ExtensionRanges().Len() > 0 {
    115 				return errors.New("message %q using proto3 semantics cannot have extension ranges", m.FullName())
    116 			}
    117 			// Verify that field names in proto3 do not conflict if lowercased
    118 			// with all underscores removed.
    119 			// See protoc v3.8.0: src/google/protobuf/descriptor.cc:5830-5847
    120 			names := map[string]protoreflect.FieldDescriptor{}
    121 			for i := 0; i < m.Fields().Len(); i++ {
    122 				f1 := m.Fields().Get(i)
    123 				s := strings.Replace(strings.ToLower(string(f1.Name())), "_", "", -1)
    124 				if f2, ok := names[s]; ok {
    125 					return errors.New("message %q using proto3 semantics has conflict: %q with %q", m.FullName(), f1.Name(), f2.Name())
    126 				}
    127 				names[s] = f1
    128 			}
    129 		}
    130 
    131 		for j, fd := range md.GetField() {
    132 			f := &m.L2.Fields.List[j]
    133 			if m.L2.ReservedNames.Has(f.Name()) {
    134 				return errors.New("message field %q must not use reserved name", f.FullName())
    135 			}
    136 			if !f.Number().IsValid() {
    137 				return errors.New("message field %q has an invalid number: %d", f.FullName(), f.Number())
    138 			}
    139 			if !f.Cardinality().IsValid() {
    140 				return errors.New("message field %q has an invalid cardinality: %d", f.FullName(), f.Cardinality())
    141 			}
    142 			if m.L2.ReservedRanges.Has(f.Number()) {
    143 				return errors.New("message field %q must not use reserved number %d", f.FullName(), f.Number())
    144 			}
    145 			if m.L2.ExtensionRanges.Has(f.Number()) {
    146 				return errors.New("message field %q with number %d in extension range", f.FullName(), f.Number())
    147 			}
    148 			if fd.Extendee != nil {
    149 				return errors.New("message field %q may not have extendee: %q", f.FullName(), fd.GetExtendee())
    150 			}
    151 			if f.L1.IsProto3Optional {
    152 				if f.Syntax() != protoreflect.Proto3 {
    153 					return errors.New("message field %q under proto3 optional semantics must be specified in the proto3 syntax", f.FullName())
    154 				}
    155 				if f.Cardinality() != protoreflect.Optional {
    156 					return errors.New("message field %q under proto3 optional semantics must have optional cardinality", f.FullName())
    157 				}
    158 				if f.ContainingOneof() != nil && f.ContainingOneof().Fields().Len() != 1 {
    159 					return errors.New("message field %q under proto3 optional semantics must be within a single element oneof", f.FullName())
    160 				}
    161 			}
    162 			if f.IsWeak() && !flags.ProtoLegacy {
    163 				return errors.New("message field %q is a weak field, which is a legacy proto1 feature that is no longer supported", f.FullName())
    164 			}
    165 			if f.IsWeak() && (f.Syntax() != protoreflect.Proto2 || !isOptionalMessage(f) || f.ContainingOneof() != nil) {
    166 				return errors.New("message field %q may only be weak for an optional message", f.FullName())
    167 			}
    168 			if f.IsPacked() && !isPackable(f) {
    169 				return errors.New("message field %q is not packable", f.FullName())
    170 			}
    171 			if err := checkValidGroup(f); err != nil {
    172 				return errors.New("message field %q is an invalid group: %v", f.FullName(), err)
    173 			}
    174 			if err := checkValidMap(f); err != nil {
    175 				return errors.New("message field %q is an invalid map: %v", f.FullName(), err)
    176 			}
    177 			if f.Syntax() == protoreflect.Proto3 {
    178 				if f.Cardinality() == protoreflect.Required {
    179 					return errors.New("message field %q using proto3 semantics cannot be required", f.FullName())
    180 				}
    181 				if f.Enum() != nil && !f.Enum().IsPlaceholder() && f.Enum().Syntax() != protoreflect.Proto3 {
    182 					return errors.New("message field %q using proto3 semantics may only depend on a proto3 enum", f.FullName())
    183 				}
    184 			}
    185 		}
    186 		seenSynthetic := false // synthetic oneofs for proto3 optional must come after real oneofs
    187 		for j := range md.GetOneofDecl() {
    188 			o := &m.L2.Oneofs.List[j]
    189 			if o.Fields().Len() == 0 {
    190 				return errors.New("message oneof %q must contain at least one field declaration", o.FullName())
    191 			}
    192 			if n := o.Fields().Len(); n-1 != (o.Fields().Get(n-1).Index() - o.Fields().Get(0).Index()) {
    193 				return errors.New("message oneof %q must have consecutively declared fields", o.FullName())
    194 			}
    195 
    196 			if o.IsSynthetic() {
    197 				seenSynthetic = true
    198 				continue
    199 			}
    200 			if !o.IsSynthetic() && seenSynthetic {
    201 				return errors.New("message oneof %q must be declared before synthetic oneofs", o.FullName())
    202 			}
    203 
    204 			for i := 0; i < o.Fields().Len(); i++ {
    205 				f := o.Fields().Get(i)
    206 				if f.Cardinality() != protoreflect.Optional {
    207 					return errors.New("message field %q belongs in a oneof and must be optional", f.FullName())
    208 				}
    209 				if f.IsWeak() {
    210 					return errors.New("message field %q belongs in a oneof and must not be a weak reference", f.FullName())
    211 				}
    212 			}
    213 		}
    214 
    215 		if err := validateEnumDeclarations(m.L1.Enums.List, md.GetEnumType()); err != nil {
    216 			return err
    217 		}
    218 		if err := validateMessageDeclarations(m.L1.Messages.List, md.GetNestedType()); err != nil {
    219 			return err
    220 		}
    221 		if err := validateExtensionDeclarations(m.L1.Extensions.List, md.GetExtension()); err != nil {
    222 			return err
    223 		}
    224 	}
    225 	return nil
    226 }
    227 
    228 func validateExtensionDeclarations(xs []filedesc.Extension, xds []*descriptorpb.FieldDescriptorProto) error {
    229 	for i, xd := range xds {
    230 		x := &xs[i]
    231 		// NOTE: Avoid using the IsValid method since extensions to MessageSet
    232 		// may have a field number higher than normal. This check only verifies
    233 		// that the number is not negative or reserved. We check again later
    234 		// if we know that the extendee is definitely not a MessageSet.
    235 		if n := x.Number(); n < 0 || (protowire.FirstReservedNumber <= n && n <= protowire.LastReservedNumber) {
    236 			return errors.New("extension field %q has an invalid number: %d", x.FullName(), x.Number())
    237 		}
    238 		if !x.Cardinality().IsValid() || x.Cardinality() == protoreflect.Required {
    239 			return errors.New("extension field %q has an invalid cardinality: %d", x.FullName(), x.Cardinality())
    240 		}
    241 		if xd.JsonName != nil {
    242 			// A bug in older versions of protoc would always populate the
    243 			// "json_name" option for extensions when it is meaningless.
    244 			// When it did so, it would always use the camel-cased field name.
    245 			if xd.GetJsonName() != strs.JSONCamelCase(string(x.Name())) {
    246 				return errors.New("extension field %q may not have an explicitly set JSON name: %q", x.FullName(), xd.GetJsonName())
    247 			}
    248 		}
    249 		if xd.OneofIndex != nil {
    250 			return errors.New("extension field %q may not be part of a oneof", x.FullName())
    251 		}
    252 		if md := x.ContainingMessage(); !md.IsPlaceholder() {
    253 			if !md.ExtensionRanges().Has(x.Number()) {
    254 				return errors.New("extension field %q extends %q with non-extension field number: %d", x.FullName(), md.FullName(), x.Number())
    255 			}
    256 			isMessageSet := md.Options().(*descriptorpb.MessageOptions).GetMessageSetWireFormat()
    257 			if isMessageSet && !isOptionalMessage(x) {
    258 				return errors.New("extension field %q extends MessageSet and must be an optional message", x.FullName())
    259 			}
    260 			if !isMessageSet && !x.Number().IsValid() {
    261 				return errors.New("extension field %q has an invalid number: %d", x.FullName(), x.Number())
    262 			}
    263 		}
    264 		if xd.GetOptions().GetWeak() {
    265 			return errors.New("extension field %q cannot be a weak reference", x.FullName())
    266 		}
    267 		if x.IsPacked() && !isPackable(x) {
    268 			return errors.New("extension field %q is not packable", x.FullName())
    269 		}
    270 		if err := checkValidGroup(x); err != nil {
    271 			return errors.New("extension field %q is an invalid group: %v", x.FullName(), err)
    272 		}
    273 		if md := x.Message(); md != nil && md.IsMapEntry() {
    274 			return errors.New("extension field %q cannot be a map entry", x.FullName())
    275 		}
    276 		if x.Syntax() == protoreflect.Proto3 {
    277 			switch x.ContainingMessage().FullName() {
    278 			case (*descriptorpb.FileOptions)(nil).ProtoReflect().Descriptor().FullName():
    279 			case (*descriptorpb.EnumOptions)(nil).ProtoReflect().Descriptor().FullName():
    280 			case (*descriptorpb.EnumValueOptions)(nil).ProtoReflect().Descriptor().FullName():
    281 			case (*descriptorpb.MessageOptions)(nil).ProtoReflect().Descriptor().FullName():
    282 			case (*descriptorpb.FieldOptions)(nil).ProtoReflect().Descriptor().FullName():
    283 			case (*descriptorpb.OneofOptions)(nil).ProtoReflect().Descriptor().FullName():
    284 			case (*descriptorpb.ExtensionRangeOptions)(nil).ProtoReflect().Descriptor().FullName():
    285 			case (*descriptorpb.ServiceOptions)(nil).ProtoReflect().Descriptor().FullName():
    286 			case (*descriptorpb.MethodOptions)(nil).ProtoReflect().Descriptor().FullName():
    287 			default:
    288 				return errors.New("extension field %q cannot be declared in proto3 unless extended descriptor options", x.FullName())
    289 			}
    290 		}
    291 	}
    292 	return nil
    293 }
    294 
    295 // isOptionalMessage reports whether this is an optional message.
    296 // If the kind is unknown, it is assumed to be a message.
    297 func isOptionalMessage(fd protoreflect.FieldDescriptor) bool {
    298 	return (fd.Kind() == 0 || fd.Kind() == protoreflect.MessageKind) && fd.Cardinality() == protoreflect.Optional
    299 }
    300 
    301 // isPackable checks whether the pack option can be specified.
    302 func isPackable(fd protoreflect.FieldDescriptor) bool {
    303 	switch fd.Kind() {
    304 	case protoreflect.StringKind, protoreflect.BytesKind, protoreflect.MessageKind, protoreflect.GroupKind:
    305 		return false
    306 	}
    307 	return fd.IsList()
    308 }
    309 
    310 // checkValidGroup reports whether fd is a valid group according to the same
    311 // rules that protoc imposes.
    312 func checkValidGroup(fd protoreflect.FieldDescriptor) error {
    313 	md := fd.Message()
    314 	switch {
    315 	case fd.Kind() != protoreflect.GroupKind:
    316 		return nil
    317 	case fd.Syntax() != protoreflect.Proto2:
    318 		return errors.New("invalid under proto2 semantics")
    319 	case md == nil || md.IsPlaceholder():
    320 		return errors.New("message must be resolvable")
    321 	case fd.FullName().Parent() != md.FullName().Parent():
    322 		return errors.New("message and field must be declared in the same scope")
    323 	case !unicode.IsUpper(rune(md.Name()[0])):
    324 		return errors.New("message name must start with an uppercase")
    325 	case fd.Name() != protoreflect.Name(strings.ToLower(string(md.Name()))):
    326 		return errors.New("field name must be lowercased form of the message name")
    327 	}
    328 	return nil
    329 }
    330 
    331 // checkValidMap checks whether the field is a valid map according to the same
    332 // rules that protoc imposes.
    333 // See protoc v3.8.0: src/google/protobuf/descriptor.cc:6045-6115
    334 func checkValidMap(fd protoreflect.FieldDescriptor) error {
    335 	md := fd.Message()
    336 	switch {
    337 	case md == nil || !md.IsMapEntry():
    338 		return nil
    339 	case fd.FullName().Parent() != md.FullName().Parent():
    340 		return errors.New("message and field must be declared in the same scope")
    341 	case md.Name() != protoreflect.Name(strs.MapEntryName(string(fd.Name()))):
    342 		return errors.New("incorrect implicit map entry name")
    343 	case fd.Cardinality() != protoreflect.Repeated:
    344 		return errors.New("field must be repeated")
    345 	case md.Fields().Len() != 2:
    346 		return errors.New("message must have exactly two fields")
    347 	case md.ExtensionRanges().Len() > 0:
    348 		return errors.New("message must not have any extension ranges")
    349 	case md.Enums().Len()+md.Messages().Len()+md.Extensions().Len() > 0:
    350 		return errors.New("message must not have any nested declarations")
    351 	}
    352 	kf := md.Fields().Get(0)
    353 	vf := md.Fields().Get(1)
    354 	switch {
    355 	case kf.Name() != genid.MapEntry_Key_field_name || kf.Number() != genid.MapEntry_Key_field_number || kf.Cardinality() != protoreflect.Optional || kf.ContainingOneof() != nil || kf.HasDefault():
    356 		return errors.New("invalid key field")
    357 	case vf.Name() != genid.MapEntry_Value_field_name || vf.Number() != genid.MapEntry_Value_field_number || vf.Cardinality() != protoreflect.Optional || vf.ContainingOneof() != nil || vf.HasDefault():
    358 		return errors.New("invalid value field")
    359 	}
    360 	switch kf.Kind() {
    361 	case protoreflect.BoolKind: // bool
    362 	case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: // int32
    363 	case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: // int64
    364 	case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: // uint32
    365 	case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: // uint64
    366 	case protoreflect.StringKind: // string
    367 	default:
    368 		return errors.New("invalid key kind: %v", kf.Kind())
    369 	}
    370 	if e := vf.Enum(); e != nil && e.Values().Len() > 0 && e.Values().Get(0).Number() != 0 {
    371 		return errors.New("map enum value must have zero number for the first value")
    372 	}
    373 	return nil
    374 }