1
2
3
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.IsClosed() {
49 if v := e.Values().Get(0); v.Number() != 0 {
50 return errors.New("enum %q using open semantics must have zero number for the first value", v.FullName())
51 }
52
53
54
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 open 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(file *filedesc.File, ms []filedesc.Message, mds []*descriptorpb.DescriptorProto) error {
84
85 isProto3 := file.L1.Edition == fromEditionProto(descriptorpb.Edition_EDITION_PROTO3)
86 for i, md := range mds {
87 m := &ms[i]
88
89
90 isMessageSet := md.GetOptions().GetMessageSetWireFormat()
91 if err := m.L2.ReservedNames.CheckValid(); err != nil {
92 return errors.New("message %q reserved names has %v", m.FullName(), err)
93 }
94 if err := m.L2.ReservedRanges.CheckValid(isMessageSet); err != nil {
95 return errors.New("message %q reserved ranges has %v", m.FullName(), err)
96 }
97 if err := m.L2.ExtensionRanges.CheckValid(isMessageSet); err != nil {
98 return errors.New("message %q extension ranges has %v", m.FullName(), err)
99 }
100 if err := (*filedesc.FieldRanges).CheckOverlap(&m.L2.ReservedRanges, &m.L2.ExtensionRanges); err != nil {
101 return errors.New("message %q reserved and extension ranges has %v", m.FullName(), err)
102 }
103 for i := 0; i < m.Fields().Len(); i++ {
104 f1 := m.Fields().Get(i)
105 if f2 := m.Fields().ByNumber(f1.Number()); f1 != f2 {
106 return errors.New("message %q has conflicting fields: %q with %q", m.FullName(), f1.Name(), f2.Name())
107 }
108 }
109 if isMessageSet && !flags.ProtoLegacy {
110 return errors.New("message %q is a MessageSet, which is a legacy proto1 feature that is no longer supported", m.FullName())
111 }
112 if isMessageSet && (isProto3 || m.Fields().Len() > 0 || m.ExtensionRanges().Len() == 0) {
113 return errors.New("message %q is an invalid proto1 MessageSet", m.FullName())
114 }
115 if isProto3 {
116 if m.ExtensionRanges().Len() > 0 {
117 return errors.New("message %q using proto3 semantics cannot have extension ranges", m.FullName())
118 }
119
120
121
122 names := map[string]protoreflect.FieldDescriptor{}
123 for i := 0; i < m.Fields().Len(); i++ {
124 f1 := m.Fields().Get(i)
125 s := strings.Replace(strings.ToLower(string(f1.Name())), "_", "", -1)
126 if f2, ok := names[s]; ok {
127 return errors.New("message %q using proto3 semantics has conflict: %q with %q", m.FullName(), f1.Name(), f2.Name())
128 }
129 names[s] = f1
130 }
131 }
132
133 for j, fd := range md.GetField() {
134 f := &m.L2.Fields.List[j]
135 if m.L2.ReservedNames.Has(f.Name()) {
136 return errors.New("message field %q must not use reserved name", f.FullName())
137 }
138 if !f.Number().IsValid() {
139 return errors.New("message field %q has an invalid number: %d", f.FullName(), f.Number())
140 }
141 if !f.Cardinality().IsValid() {
142 return errors.New("message field %q has an invalid cardinality: %d", f.FullName(), f.Cardinality())
143 }
144 if m.L2.ReservedRanges.Has(f.Number()) {
145 return errors.New("message field %q must not use reserved number %d", f.FullName(), f.Number())
146 }
147 if m.L2.ExtensionRanges.Has(f.Number()) {
148 return errors.New("message field %q with number %d in extension range", f.FullName(), f.Number())
149 }
150 if fd.Extendee != nil {
151 return errors.New("message field %q may not have extendee: %q", f.FullName(), fd.GetExtendee())
152 }
153 if f.L1.IsProto3Optional {
154 if !isProto3 {
155 return errors.New("message field %q under proto3 optional semantics must be specified in the proto3 syntax", f.FullName())
156 }
157 if f.Cardinality() != protoreflect.Optional {
158 return errors.New("message field %q under proto3 optional semantics must have optional cardinality", f.FullName())
159 }
160 if f.ContainingOneof() != nil && f.ContainingOneof().Fields().Len() != 1 {
161 return errors.New("message field %q under proto3 optional semantics must be within a single element oneof", f.FullName())
162 }
163 }
164 if f.IsWeak() && !flags.ProtoLegacy {
165 return errors.New("message field %q is a weak field, which is a legacy proto1 feature that is no longer supported", f.FullName())
166 }
167 if f.IsWeak() && (!f.HasPresence() || !isOptionalMessage(f) || f.ContainingOneof() != nil) {
168 return errors.New("message field %q may only be weak for an optional message", f.FullName())
169 }
170 if f.IsPacked() && !isPackable(f) {
171 return errors.New("message field %q is not packable", f.FullName())
172 }
173 if err := checkValidGroup(file, f); err != nil {
174 return errors.New("message field %q is an invalid group: %v", f.FullName(), err)
175 }
176 if err := checkValidMap(f); err != nil {
177 return errors.New("message field %q is an invalid map: %v", f.FullName(), err)
178 }
179 if isProto3 {
180 if f.Cardinality() == protoreflect.Required {
181 return errors.New("message field %q using proto3 semantics cannot be required", f.FullName())
182 }
183 if f.Enum() != nil && !f.Enum().IsPlaceholder() && f.Enum().IsClosed() {
184 return errors.New("message field %q using proto3 semantics may only depend on open enums", f.FullName())
185 }
186 }
187 if f.Cardinality() == protoreflect.Optional && !f.HasPresence() && f.Enum() != nil && !f.Enum().IsPlaceholder() && f.Enum().IsClosed() {
188 return errors.New("message field %q with implicit presence may only use open enums", f.FullName())
189 }
190 }
191 seenSynthetic := false
192 for j := range md.GetOneofDecl() {
193 o := &m.L2.Oneofs.List[j]
194 if o.Fields().Len() == 0 {
195 return errors.New("message oneof %q must contain at least one field declaration", o.FullName())
196 }
197 if n := o.Fields().Len(); n-1 != (o.Fields().Get(n-1).Index() - o.Fields().Get(0).Index()) {
198 return errors.New("message oneof %q must have consecutively declared fields", o.FullName())
199 }
200
201 if o.IsSynthetic() {
202 seenSynthetic = true
203 continue
204 }
205 if !o.IsSynthetic() && seenSynthetic {
206 return errors.New("message oneof %q must be declared before synthetic oneofs", o.FullName())
207 }
208
209 for i := 0; i < o.Fields().Len(); i++ {
210 f := o.Fields().Get(i)
211 if f.Cardinality() != protoreflect.Optional {
212 return errors.New("message field %q belongs in a oneof and must be optional", f.FullName())
213 }
214 if f.IsWeak() {
215 return errors.New("message field %q belongs in a oneof and must not be a weak reference", f.FullName())
216 }
217 }
218 }
219
220 if err := validateEnumDeclarations(m.L1.Enums.List, md.GetEnumType()); err != nil {
221 return err
222 }
223 if err := validateMessageDeclarations(file, m.L1.Messages.List, md.GetNestedType()); err != nil {
224 return err
225 }
226 if err := validateExtensionDeclarations(file, m.L1.Extensions.List, md.GetExtension()); err != nil {
227 return err
228 }
229 }
230 return nil
231 }
232
233 func validateExtensionDeclarations(f *filedesc.File, xs []filedesc.Extension, xds []*descriptorpb.FieldDescriptorProto) error {
234 for i, xd := range xds {
235 x := &xs[i]
236
237
238
239
240 if n := x.Number(); n < 0 || (protowire.FirstReservedNumber <= n && n <= protowire.LastReservedNumber) {
241 return errors.New("extension field %q has an invalid number: %d", x.FullName(), x.Number())
242 }
243 if !x.Cardinality().IsValid() || x.Cardinality() == protoreflect.Required {
244 return errors.New("extension field %q has an invalid cardinality: %d", x.FullName(), x.Cardinality())
245 }
246 if xd.JsonName != nil {
247
248
249
250 if xd.GetJsonName() != strs.JSONCamelCase(string(x.Name())) {
251 return errors.New("extension field %q may not have an explicitly set JSON name: %q", x.FullName(), xd.GetJsonName())
252 }
253 }
254 if xd.OneofIndex != nil {
255 return errors.New("extension field %q may not be part of a oneof", x.FullName())
256 }
257 if md := x.ContainingMessage(); !md.IsPlaceholder() {
258 if !md.ExtensionRanges().Has(x.Number()) {
259 return errors.New("extension field %q extends %q with non-extension field number: %d", x.FullName(), md.FullName(), x.Number())
260 }
261 isMessageSet := md.Options().(*descriptorpb.MessageOptions).GetMessageSetWireFormat()
262 if isMessageSet && !isOptionalMessage(x) {
263 return errors.New("extension field %q extends MessageSet and must be an optional message", x.FullName())
264 }
265 if !isMessageSet && !x.Number().IsValid() {
266 return errors.New("extension field %q has an invalid number: %d", x.FullName(), x.Number())
267 }
268 }
269 if xd.GetOptions().GetWeak() {
270 return errors.New("extension field %q cannot be a weak reference", x.FullName())
271 }
272 if x.IsPacked() && !isPackable(x) {
273 return errors.New("extension field %q is not packable", x.FullName())
274 }
275 if err := checkValidGroup(f, x); err != nil {
276 return errors.New("extension field %q is an invalid group: %v", x.FullName(), err)
277 }
278 if md := x.Message(); md != nil && md.IsMapEntry() {
279 return errors.New("extension field %q cannot be a map entry", x.FullName())
280 }
281 if f.L1.Edition == fromEditionProto(descriptorpb.Edition_EDITION_PROTO3) {
282 switch x.ContainingMessage().FullName() {
283 case (*descriptorpb.FileOptions)(nil).ProtoReflect().Descriptor().FullName():
284 case (*descriptorpb.EnumOptions)(nil).ProtoReflect().Descriptor().FullName():
285 case (*descriptorpb.EnumValueOptions)(nil).ProtoReflect().Descriptor().FullName():
286 case (*descriptorpb.MessageOptions)(nil).ProtoReflect().Descriptor().FullName():
287 case (*descriptorpb.FieldOptions)(nil).ProtoReflect().Descriptor().FullName():
288 case (*descriptorpb.OneofOptions)(nil).ProtoReflect().Descriptor().FullName():
289 case (*descriptorpb.ExtensionRangeOptions)(nil).ProtoReflect().Descriptor().FullName():
290 case (*descriptorpb.ServiceOptions)(nil).ProtoReflect().Descriptor().FullName():
291 case (*descriptorpb.MethodOptions)(nil).ProtoReflect().Descriptor().FullName():
292 default:
293 return errors.New("extension field %q cannot be declared in proto3 unless extended descriptor options", x.FullName())
294 }
295 }
296 }
297 return nil
298 }
299
300
301
302 func isOptionalMessage(fd protoreflect.FieldDescriptor) bool {
303 return (fd.Kind() == 0 || fd.Kind() == protoreflect.MessageKind) && fd.Cardinality() == protoreflect.Optional
304 }
305
306
307 func isPackable(fd protoreflect.FieldDescriptor) bool {
308 switch fd.Kind() {
309 case protoreflect.StringKind, protoreflect.BytesKind, protoreflect.MessageKind, protoreflect.GroupKind:
310 return false
311 }
312 return fd.IsList()
313 }
314
315
316
317 func checkValidGroup(f *filedesc.File, fd protoreflect.FieldDescriptor) error {
318 md := fd.Message()
319 switch {
320 case fd.Kind() != protoreflect.GroupKind:
321 return nil
322 case f.L1.Edition == fromEditionProto(descriptorpb.Edition_EDITION_PROTO3):
323 return errors.New("invalid under proto3 semantics")
324 case md == nil || md.IsPlaceholder():
325 return errors.New("message must be resolvable")
326 }
327 if f.L1.Edition < fromEditionProto(descriptorpb.Edition_EDITION_2023) {
328 switch {
329 case fd.FullName().Parent() != md.FullName().Parent():
330 return errors.New("message and field must be declared in the same scope")
331 case !unicode.IsUpper(rune(md.Name()[0])):
332 return errors.New("message name must start with an uppercase")
333 case fd.Name() != protoreflect.Name(strings.ToLower(string(md.Name()))):
334 return errors.New("field name must be lowercased form of the message name")
335 }
336 }
337 return nil
338 }
339
340
341
342
343 func checkValidMap(fd protoreflect.FieldDescriptor) error {
344 md := fd.Message()
345 switch {
346 case md == nil || !md.IsMapEntry():
347 return nil
348 case fd.FullName().Parent() != md.FullName().Parent():
349 return errors.New("message and field must be declared in the same scope")
350 case md.Name() != protoreflect.Name(strs.MapEntryName(string(fd.Name()))):
351 return errors.New("incorrect implicit map entry name")
352 case fd.Cardinality() != protoreflect.Repeated:
353 return errors.New("field must be repeated")
354 case md.Fields().Len() != 2:
355 return errors.New("message must have exactly two fields")
356 case md.ExtensionRanges().Len() > 0:
357 return errors.New("message must not have any extension ranges")
358 case md.Enums().Len()+md.Messages().Len()+md.Extensions().Len() > 0:
359 return errors.New("message must not have any nested declarations")
360 }
361 kf := md.Fields().Get(0)
362 vf := md.Fields().Get(1)
363 switch {
364 case kf.Name() != genid.MapEntry_Key_field_name || kf.Number() != genid.MapEntry_Key_field_number || kf.Cardinality() != protoreflect.Optional || kf.ContainingOneof() != nil || kf.HasDefault():
365 return errors.New("invalid key field")
366 case vf.Name() != genid.MapEntry_Value_field_name || vf.Number() != genid.MapEntry_Value_field_number || vf.Cardinality() != protoreflect.Optional || vf.ContainingOneof() != nil || vf.HasDefault():
367 return errors.New("invalid value field")
368 }
369 switch kf.Kind() {
370 case protoreflect.BoolKind:
371 case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
372 case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
373 case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
374 case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
375 case protoreflect.StringKind:
376 default:
377 return errors.New("invalid key kind: %v", kf.Kind())
378 }
379 if e := vf.Enum(); e != nil && e.Values().Len() > 0 && e.Values().Get(0).Number() != 0 {
380 return errors.New("map enum value must have zero number for the first value")
381 }
382 return nil
383 }
384
View as plain text