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