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