blob: ce9a3e4195e40f641135c93ea30d7121ab15f37d [file] [log] [blame]
Zack Williamse940c7a2019-08-21 14:25:39 -07001package protoparse
2
3import (
4 "bytes"
5 "errors"
6 "fmt"
7 "io"
8 "io/ioutil"
9 "math"
10 "os"
11 "path/filepath"
12 "sort"
13 "strings"
14
15 "github.com/golang/protobuf/proto"
16 dpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
17
18 "github.com/jhump/protoreflect/desc"
19 "github.com/jhump/protoreflect/desc/internal"
20)
21
22//go:generate goyacc -o proto.y.go -p proto proto.y
23
24var errNoImportPathsForAbsoluteFilePath = errors.New("must specify at least one import path if any absolute file paths are given")
25
26func init() {
27 protoErrorVerbose = true
28
29 // fix up the generated "token name" array so that error messages are nicer
30 setTokenName(_STRING_LIT, "string literal")
31 setTokenName(_INT_LIT, "int literal")
32 setTokenName(_FLOAT_LIT, "float literal")
33 setTokenName(_NAME, "identifier")
34 setTokenName(_FQNAME, "fully-qualified name")
35 setTokenName(_TYPENAME, "type name")
36 setTokenName(_ERROR, "error")
37 // for keywords, just show the keyword itself wrapped in quotes
38 for str, i := range keywords {
39 setTokenName(i, fmt.Sprintf(`"%s"`, str))
40 }
41}
42
43func setTokenName(token int, text string) {
44 // NB: this is based on logic in generated parse code that translates the
45 // int returned from the lexer into an internal token number.
46 var intern int
47 if token < len(protoTok1) {
48 intern = protoTok1[token]
49 } else {
50 if token >= protoPrivate {
51 if token < protoPrivate+len(protoTok2) {
52 intern = protoTok2[token-protoPrivate]
53 }
54 }
55 if intern == 0 {
56 for i := 0; i+1 < len(protoTok3); i += 2 {
57 if protoTok3[i] == token {
58 intern = protoTok3[i+1]
59 break
60 }
61 }
62 }
63 }
64
65 if intern >= 1 && intern-1 < len(protoToknames) {
66 protoToknames[intern-1] = text
67 return
68 }
69
70 panic(fmt.Sprintf("Unknown token value: %d", token))
71}
72
73// FileAccessor is an abstraction for opening proto source files. It takes the
74// name of the file to open and returns either the input reader or an error.
75type FileAccessor func(filename string) (io.ReadCloser, error)
76
77// FileContentsFromMap returns a FileAccessor that uses the given map of file
78// contents. This allows proto source files to be constructed in memory and
79// easily supplied to a parser. The map keys are the paths to the proto source
80// files, and the values are the actual proto source contents.
81func FileContentsFromMap(files map[string]string) FileAccessor {
82 return func(filename string) (io.ReadCloser, error) {
83 contents, ok := files[filename]
84 if !ok {
85 return nil, os.ErrNotExist
86 }
87 return ioutil.NopCloser(strings.NewReader(contents)), nil
88 }
89}
90
91// ResolveFilenames tries to resolve fileNames into paths that are relative to
92// directories in the given importPaths. The returned slice has the results in
93// the same order as they are supplied in fileNames.
94//
95// The resulting names should be suitable for passing to Parser.ParseFiles.
96//
97// If importPaths is empty and any path is absolute, this returns error.
98// If importPaths is empty and all paths are relative, this returns the original fileNames.
99func ResolveFilenames(importPaths []string, fileNames ...string) ([]string, error) {
100 if len(importPaths) == 0 {
101 if containsAbsFilePath(fileNames) {
102 // We have to do this as otherwise parseProtoFiles can result in duplicate symbols.
103 // For example, assume we import "foo/bar/bar.proto" in a file "/home/alice/dev/foo/bar/baz.proto"
104 // as we call ParseFiles("/home/alice/dev/foo/bar/bar.proto","/home/alice/dev/foo/bar/baz.proto")
105 // with "/home/alice/dev" as our current directory. Due to the recursive nature of parseProtoFiles,
106 // it will discover the import "foo/bar/bar.proto" in the input file, and call parse on this,
107 // adding "foo/bar/bar.proto" to the parsed results, as well as "/home/alice/dev/foo/bar/bar.proto"
108 // from the input file list. This will result in a
109 // 'duplicate symbol SYMBOL: already defined as field in "/home/alice/dev/foo/bar/bar.proto'
110 // error being returned from ParseFiles.
111 return nil, errNoImportPathsForAbsoluteFilePath
112 }
113 return fileNames, nil
114 }
115 absImportPaths, err := absoluteFilePaths(importPaths)
116 if err != nil {
117 return nil, err
118 }
119 absFileNames, err := absoluteFilePaths(fileNames)
120 if err != nil {
121 return nil, err
122 }
123 resolvedFileNames := make([]string, 0, len(fileNames))
124 for _, absFileName := range absFileNames {
125 resolvedFileName, err := resolveAbsFilename(absImportPaths, absFileName)
126 if err != nil {
127 return nil, err
128 }
129 resolvedFileNames = append(resolvedFileNames, resolvedFileName)
130 }
131 return resolvedFileNames, nil
132}
133
134// Parser parses proto source into descriptors.
135type Parser struct {
136 // The paths used to search for dependencies that are referenced in import
137 // statements in proto source files. If no import paths are provided then
138 // "." (current directory) is assumed to be the only import path.
139 //
140 // This setting is only used during ParseFiles operations. Since calls to
141 // ParseFilesButDoNotLink do not link, there is no need to load and parse
142 // dependencies.
143 ImportPaths []string
144
145 // If true, the supplied file names/paths need not necessarily match how the
146 // files are referenced in import statements. The parser will attempt to
147 // match import statements to supplied paths, "guessing" the import paths
148 // for the files. Note that this inference is not perfect and link errors
149 // could result. It works best when all proto files are organized such that
150 // a single import path can be inferred (e.g. all files under a single tree
151 // with import statements all being relative to the root of this tree).
152 InferImportPaths bool
153
154 // Used to create a reader for a given filename, when loading proto source
155 // file contents. If unset, os.Open is used. If ImportPaths is also empty
156 // then relative paths are will be relative to the process's current working
157 // directory.
158 Accessor FileAccessor
159
160 // If true, the resulting file descriptors will retain source code info,
161 // that maps elements to their location in the source files as well as
162 // includes comments found during parsing (and attributed to elements of
163 // the source file).
164 IncludeSourceCodeInfo bool
165
166 // If true, the results from ParseFilesButDoNotLink will be passed through
167 // some additional validations. But only constraints that do not require
168 // linking can be checked. These include proto2 vs. proto3 language features,
169 // looking for incorrect usage of reserved names or tags, and ensuring that
170 // fields have unique tags and that enum values have unique numbers (unless
171 // the enum allows aliases).
172 ValidateUnlinkedFiles bool
173
174 // If true, the results from ParseFilesButDoNotLink will have options
175 // interpreted. Any uninterpretable options (including any custom options or
176 // options that refer to message and enum types, which can only be
177 // interpreted after linking) will be left in uninterpreted_options. Also,
178 // the "default" pseudo-option for fields can only be interpreted for scalar
179 // fields, excluding enums. (Interpreting default values for enum fields
180 // requires resolving enum names, which requires linking.)
181 InterpretOptionsInUnlinkedFiles bool
182}
183
184// ParseFiles parses the named files into descriptors. The returned slice has
185// the same number of entries as the give filenames, in the same order. So the
186// first returned descriptor corresponds to the first given name, and so on.
187//
188// All dependencies for all specified files (including transitive dependencies)
189// must be accessible via the parser's Accessor or a link error will occur. The
190// exception to this rule is that files can import standard Google-provided
191// files -- e.g. google/protobuf/*.proto -- without needing to supply sources
192// for these files. Like protoc, this parser has a built-in version of these
193// files it can use if they aren't explicitly supplied.
194func (p Parser) ParseFiles(filenames ...string) ([]*desc.FileDescriptor, error) {
195 accessor := p.Accessor
196 if accessor == nil {
197 accessor = func(name string) (io.ReadCloser, error) {
198 return os.Open(name)
199 }
200 }
201 paths := p.ImportPaths
202 if len(paths) > 0 {
203 acc := accessor
204 accessor = func(name string) (io.ReadCloser, error) {
205 var ret error
206 for _, path := range paths {
207 f, err := acc(filepath.Join(path, name))
208 if err != nil {
209 if ret == nil {
210 ret = err
211 }
212 continue
213 }
214 return f, nil
215 }
216 return nil, ret
217 }
218 }
219
220 protos := map[string]*parseResult{}
221 err := parseProtoFiles(accessor, filenames, true, true, protos)
222 if err != nil {
223 return nil, err
224 }
225 if p.InferImportPaths {
226 protos = fixupFilenames(protos)
227 }
228 linkedProtos, err := newLinker(protos).linkFiles()
229 if err != nil {
230 return nil, err
231 }
232 if p.IncludeSourceCodeInfo {
233 for name, fd := range linkedProtos {
234 pr := protos[name]
235 fd.AsFileDescriptorProto().SourceCodeInfo = pr.generateSourceCodeInfo()
236 internal.RecomputeSourceInfo(fd)
237 }
238 }
239 fds := make([]*desc.FileDescriptor, len(filenames))
240 for i, name := range filenames {
241 fd := linkedProtos[name]
242 fds[i] = fd
243 }
244 return fds, nil
245}
246
247// ParseFilesButDoNotLink parses the named files into descriptor protos. The
248// results are just protos, not fully-linked descriptors. It is possible that
249// descriptors are invalid and still be returned in parsed form without error
250// due to the fact that the linking step is skipped (and thus many validation
251// steps omitted).
252//
253// There are a few side effects to not linking the descriptors:
254// 1. No options will be interpreted. Options can refer to extensions or have
255// message and enum types. Without linking, these extension and type
256// references are not resolved, so the options may not be interpretable.
257// So all options will appear in UninterpretedOption fields of the various
258// descriptor options messages.
259// 2. Type references will not be resolved. This means that the actual type
260// names in the descriptors may be unqualified and even relative to the
261// scope in which the type reference appears. This goes for fields that
262// have message and enum types. It also applies to methods and their
263// references to request and response message types.
264// 3. Enum fields are not known. Until a field's type reference is resolved
265// (during linking), it is not known whether the type refers to a message
266// or an enum. So all fields with such type references have their Type set
267// to TYPE_MESSAGE.
268//
269// This method will still validate the syntax of parsed files. If the parser's
270// ValidateUnlinkedFiles field is true, additional checks, beyond syntax will
271// also be performed.
272func (p Parser) ParseFilesButDoNotLink(filenames ...string) ([]*dpb.FileDescriptorProto, error) {
273 accessor := p.Accessor
274 if accessor == nil {
275 accessor = func(name string) (io.ReadCloser, error) {
276 return os.Open(name)
277 }
278 }
279
280 protos := map[string]*parseResult{}
281 err := parseProtoFiles(accessor, filenames, false, p.ValidateUnlinkedFiles, protos)
282 if err != nil {
283 return nil, err
284 }
285 if p.InferImportPaths {
286 protos = fixupFilenames(protos)
287 }
288 fds := make([]*dpb.FileDescriptorProto, len(filenames))
289 for i, name := range filenames {
290 pr := protos[name]
291 fd := pr.fd
292 if p.InterpretOptionsInUnlinkedFiles {
293 pr.lenient = true
294 interpretFileOptions(pr, poorFileDescriptorish{FileDescriptorProto: fd})
295 }
296 if p.IncludeSourceCodeInfo {
297 fd.SourceCodeInfo = pr.generateSourceCodeInfo()
298 }
299 fds[i] = fd
300 }
301 return fds, nil
302}
303
304func containsAbsFilePath(filePaths []string) bool {
305 for _, filePath := range filePaths {
306 if filepath.IsAbs(filePath) {
307 return true
308 }
309 }
310 return false
311}
312
313func absoluteFilePaths(filePaths []string) ([]string, error) {
314 absFilePaths := make([]string, 0, len(filePaths))
315 for _, filePath := range filePaths {
316 absFilePath, err := filepath.Abs(filePath)
317 if err != nil {
318 return nil, err
319 }
320 absFilePaths = append(absFilePaths, absFilePath)
321 }
322 return absFilePaths, nil
323}
324
325func resolveAbsFilename(absImportPaths []string, absFileName string) (string, error) {
326 for _, absImportPath := range absImportPaths {
327 if isDescendant(absImportPath, absFileName) {
328 resolvedPath, err := filepath.Rel(absImportPath, absFileName)
329 if err != nil {
330 return "", err
331 }
332 return resolvedPath, nil
333 }
334 }
335 return "", fmt.Errorf("%s does not reside in any import path", absFileName)
336}
337
338// isDescendant returns true if file is a descendant of dir.
339func isDescendant(dir, file string) bool {
340 dir = filepath.Clean(dir)
341 cur := file
342 for {
343 d := filepath.Dir(cur)
344 if d == dir {
345 return true
346 }
347 if d == "." || d == cur {
348 // we've run out of path elements
349 return false
350 }
351 cur = d
352 }
353}
354
355func fixupFilenames(protos map[string]*parseResult) map[string]*parseResult {
356 // In the event that the given filenames (keys in the supplied map) do not
357 // match the actual paths used in 'import' statements in the files, we try
358 // to revise names in the protos so that they will match and be linkable.
359 revisedProtos := map[string]*parseResult{}
360
361 protoPaths := map[string]struct{}{}
362 // TODO: this is O(n^2) but could likely be O(n) with a clever data structure (prefix tree that is indexed backwards?)
363 importCandidates := map[string]map[string]struct{}{}
364 candidatesAvailable := map[string]struct{}{}
365 for name := range protos {
366 candidatesAvailable[name] = struct{}{}
367 for _, f := range protos {
368 for _, imp := range f.fd.Dependency {
369 if strings.HasSuffix(name, imp) {
370 candidates := importCandidates[imp]
371 if candidates == nil {
372 candidates = map[string]struct{}{}
373 importCandidates[imp] = candidates
374 }
375 candidates[name] = struct{}{}
376 }
377 }
378 }
379 }
380 for imp, candidates := range importCandidates {
381 // if we found multiple possible candidates, use the one that is an exact match
382 // if it exists, and otherwise, guess that it's the shortest path (fewest elements)
383 var best string
384 for c := range candidates {
385 if _, ok := candidatesAvailable[c]; !ok {
386 // already used this candidate and re-written its filename accordingly
387 continue
388 }
389 if c == imp {
390 // exact match!
391 best = c
392 break
393 }
394 if best == "" {
395 best = c
396 } else {
397 // HACK: we can't actually tell which files is supposed to match
398 // this import, so arbitrarily pick the "shorter" one (fewest
399 // path elements) or, on a tie, the lexically earlier one
400 minLen := strings.Count(best, string(filepath.Separator))
401 cLen := strings.Count(c, string(filepath.Separator))
402 if cLen < minLen || (cLen == minLen && c < best) {
403 best = c
404 }
405 }
406 }
407 if best != "" {
408 prefix := best[:len(best)-len(imp)]
409 if len(prefix) > 0 {
410 protoPaths[prefix] = struct{}{}
411 }
412 f := protos[best]
413 f.fd.Name = proto.String(imp)
414 revisedProtos[imp] = f
415 delete(candidatesAvailable, best)
416 }
417 }
418
419 if len(candidatesAvailable) == 0 {
420 return revisedProtos
421 }
422
423 if len(protoPaths) == 0 {
424 for c := range candidatesAvailable {
425 revisedProtos[c] = protos[c]
426 }
427 return revisedProtos
428 }
429
430 // Any remaining candidates are entry-points (not imported by others), so
431 // the best bet to "fixing" their file name is to see if they're in one of
432 // the proto paths we found, and if so strip that prefix.
433 protoPathStrs := make([]string, len(protoPaths))
434 i := 0
435 for p := range protoPaths {
436 protoPathStrs[i] = p
437 i++
438 }
439 sort.Strings(protoPathStrs)
440 // we look at paths in reverse order, so we'll use a longer proto path if
441 // there is more than one match
442 for c := range candidatesAvailable {
443 var imp string
444 for i := len(protoPathStrs) - 1; i >= 0; i-- {
445 p := protoPathStrs[i]
446 if strings.HasPrefix(c, p) {
447 imp = c[len(p):]
448 break
449 }
450 }
451 if imp != "" {
452 f := protos[c]
453 f.fd.Name = proto.String(imp)
454 revisedProtos[imp] = f
455 } else {
456 revisedProtos[c] = protos[c]
457 }
458 }
459
460 return revisedProtos
461}
462
463func parseProtoFiles(acc FileAccessor, filenames []string, recursive, validate bool, parsed map[string]*parseResult) error {
464 for _, name := range filenames {
465 if _, ok := parsed[name]; ok {
466 continue
467 }
468 in, err := acc(name)
469 if err != nil {
470 if d, ok := standardImports[name]; ok {
471 parsed[name] = &parseResult{fd: d}
472 continue
473 }
474 return err
475 }
476 func() {
477 defer in.Close()
478 parsed[name], err = parseProto(name, in, validate)
479 }()
480 if err != nil {
481 return err
482 }
483 if recursive {
484 err = parseProtoFiles(acc, parsed[name].fd.Dependency, true, validate, parsed)
485 if err != nil {
486 return fmt.Errorf("failed to load imports for %q: %s", name, err)
487 }
488 }
489 }
490 return nil
491}
492
493type parseResult struct {
494 // the parsed file descriptor
495 fd *dpb.FileDescriptorProto
496
497 // if set to true, enables lenient interpretation of options, where
498 // unrecognized options will be left uninterpreted instead of resulting in a
499 // link error
500 lenient bool
501
502 // a map of elements in the descriptor to nodes in the AST
503 // (for extracting position information when validating the descriptor)
504 nodes map[proto.Message]node
505
506 // a map of uninterpreted option AST nodes to their relative path
507 // in the resulting options message
508 interpretedOptions map[*optionNode][]int32
509}
510
511func (r *parseResult) getFileNode(f *dpb.FileDescriptorProto) fileDecl {
512 if r.nodes == nil {
513 return noSourceNode{pos: unknownPos(f.GetName())}
514 }
515 return r.nodes[f].(fileDecl)
516}
517
518func (r *parseResult) getOptionNode(o *dpb.UninterpretedOption) optionDecl {
519 if r.nodes == nil {
520 return noSourceNode{pos: unknownPos(r.fd.GetName())}
521 }
522 return r.nodes[o].(optionDecl)
523}
524
525func (r *parseResult) getOptionNamePartNode(o *dpb.UninterpretedOption_NamePart) node {
526 if r.nodes == nil {
527 return noSourceNode{pos: unknownPos(r.fd.GetName())}
528 }
529 return r.nodes[o]
530}
531
532func (r *parseResult) getMessageNode(m *dpb.DescriptorProto) msgDecl {
533 if r.nodes == nil {
534 return noSourceNode{pos: unknownPos(r.fd.GetName())}
535 }
536 return r.nodes[m].(msgDecl)
537}
538
539func (r *parseResult) getFieldNode(f *dpb.FieldDescriptorProto) fieldDecl {
540 if r.nodes == nil {
541 return noSourceNode{pos: unknownPos(r.fd.GetName())}
542 }
543 return r.nodes[f].(fieldDecl)
544}
545
546func (r *parseResult) getOneOfNode(o *dpb.OneofDescriptorProto) node {
547 if r.nodes == nil {
548 return noSourceNode{pos: unknownPos(r.fd.GetName())}
549 }
550 return r.nodes[o]
551}
552
553func (r *parseResult) getExtensionRangeNode(e *dpb.DescriptorProto_ExtensionRange) rangeDecl {
554 if r.nodes == nil {
555 return noSourceNode{pos: unknownPos(r.fd.GetName())}
556 }
557 return r.nodes[e].(rangeDecl)
558}
559
560func (r *parseResult) getMessageReservedRangeNode(rr *dpb.DescriptorProto_ReservedRange) rangeDecl {
561 if r.nodes == nil {
562 return noSourceNode{pos: unknownPos(r.fd.GetName())}
563 }
564 return r.nodes[rr].(rangeDecl)
565}
566
567func (r *parseResult) getEnumNode(e *dpb.EnumDescriptorProto) node {
568 if r.nodes == nil {
569 return noSourceNode{pos: unknownPos(r.fd.GetName())}
570 }
571 return r.nodes[e]
572}
573
574func (r *parseResult) getEnumValueNode(e *dpb.EnumValueDescriptorProto) enumValueDecl {
575 if r.nodes == nil {
576 return noSourceNode{pos: unknownPos(r.fd.GetName())}
577 }
578 return r.nodes[e].(enumValueDecl)
579}
580
581func (r *parseResult) getEnumReservedRangeNode(rr *dpb.EnumDescriptorProto_EnumReservedRange) rangeDecl {
582 if r.nodes == nil {
583 return noSourceNode{pos: unknownPos(r.fd.GetName())}
584 }
585 return r.nodes[rr].(rangeDecl)
586}
587
588func (r *parseResult) getServiceNode(s *dpb.ServiceDescriptorProto) node {
589 if r.nodes == nil {
590 return noSourceNode{pos: unknownPos(r.fd.GetName())}
591 }
592 return r.nodes[s]
593}
594
595func (r *parseResult) getMethodNode(m *dpb.MethodDescriptorProto) methodDecl {
596 if r.nodes == nil {
597 return noSourceNode{pos: unknownPos(r.fd.GetName())}
598 }
599 return r.nodes[m].(methodDecl)
600}
601
602func (r *parseResult) putFileNode(f *dpb.FileDescriptorProto, n *fileNode) {
603 r.nodes[f] = n
604}
605
606func (r *parseResult) putOptionNode(o *dpb.UninterpretedOption, n *optionNode) {
607 r.nodes[o] = n
608}
609
610func (r *parseResult) putOptionNamePartNode(o *dpb.UninterpretedOption_NamePart, n *optionNamePartNode) {
611 r.nodes[o] = n
612}
613
614func (r *parseResult) putMessageNode(m *dpb.DescriptorProto, n msgDecl) {
615 r.nodes[m] = n
616}
617
618func (r *parseResult) putFieldNode(f *dpb.FieldDescriptorProto, n fieldDecl) {
619 r.nodes[f] = n
620}
621
622func (r *parseResult) putOneOfNode(o *dpb.OneofDescriptorProto, n *oneOfNode) {
623 r.nodes[o] = n
624}
625
626func (r *parseResult) putExtensionRangeNode(e *dpb.DescriptorProto_ExtensionRange, n *rangeNode) {
627 r.nodes[e] = n
628}
629
630func (r *parseResult) putMessageReservedRangeNode(rr *dpb.DescriptorProto_ReservedRange, n *rangeNode) {
631 r.nodes[rr] = n
632}
633
634func (r *parseResult) putEnumNode(e *dpb.EnumDescriptorProto, n *enumNode) {
635 r.nodes[e] = n
636}
637
638func (r *parseResult) putEnumValueNode(e *dpb.EnumValueDescriptorProto, n *enumValueNode) {
639 r.nodes[e] = n
640}
641
642func (r *parseResult) putEnumReservedRangeNode(rr *dpb.EnumDescriptorProto_EnumReservedRange, n *rangeNode) {
643 r.nodes[rr] = n
644}
645
646func (r *parseResult) putServiceNode(s *dpb.ServiceDescriptorProto, n *serviceNode) {
647 r.nodes[s] = n
648}
649
650func (r *parseResult) putMethodNode(m *dpb.MethodDescriptorProto, n *methodNode) {
651 r.nodes[m] = n
652}
653
654func parseProto(filename string, r io.Reader, validate bool) (*parseResult, error) {
655 lx := newLexer(r)
656 lx.filename = filename
657 protoParse(lx)
658 if lx.err != nil {
659 if _, ok := lx.err.(ErrorWithSourcePos); ok {
660 return nil, lx.err
661 } else {
662 return nil, ErrorWithSourcePos{Pos: lx.prev(), Underlying: lx.err}
663 }
664 }
665 // parser will not return an error if input is empty, so we
666 // need to also check if the result is non-nil
667 if lx.res == nil {
668 return nil, ErrorWithSourcePos{Pos: lx.prev(), Underlying: errors.New("input is empty")}
669 }
670
671 res, err := createParseResult(filename, lx.res)
672 if err != nil {
673 return nil, err
674 }
675 if validate {
676 if err := basicValidate(res); err != nil {
677 return nil, err
678 }
679 }
680 return res, nil
681}
682
683func createParseResult(filename string, file *fileNode) (*parseResult, error) {
684 res := &parseResult{
685 nodes: map[proto.Message]node{},
686 interpretedOptions: map[*optionNode][]int32{},
687 }
688 err := res.createFileDescriptor(filename, file)
689 return res, err
690}
691
692func (r *parseResult) createFileDescriptor(filename string, file *fileNode) error {
693 fd := &dpb.FileDescriptorProto{Name: proto.String(filename)}
694 r.putFileNode(fd, file)
695
696 isProto3 := false
697 if file.syntax != nil {
698 isProto3 = file.syntax.syntax.val == "proto3"
699 // proto2 is the default, so no need to set unless proto3
700 if isProto3 {
701 fd.Syntax = proto.String(file.syntax.syntax.val)
702 }
703 }
704
705 for _, decl := range file.decls {
706 if decl.enum != nil {
707 fd.EnumType = append(fd.EnumType, r.asEnumDescriptor(decl.enum))
708 } else if decl.extend != nil {
709 r.addExtensions(decl.extend, &fd.Extension, &fd.MessageType, isProto3)
710 } else if decl.imp != nil {
711 file.imports = append(file.imports, decl.imp)
712 index := len(fd.Dependency)
713 fd.Dependency = append(fd.Dependency, decl.imp.name.val)
714 if decl.imp.public {
715 fd.PublicDependency = append(fd.PublicDependency, int32(index))
716 } else if decl.imp.weak {
717 fd.WeakDependency = append(fd.WeakDependency, int32(index))
718 }
719 } else if decl.message != nil {
720 fd.MessageType = append(fd.MessageType, r.asMessageDescriptor(decl.message, isProto3))
721 } else if decl.option != nil {
722 if fd.Options == nil {
723 fd.Options = &dpb.FileOptions{}
724 }
725 fd.Options.UninterpretedOption = append(fd.Options.UninterpretedOption, r.asUninterpretedOption(decl.option))
726 } else if decl.service != nil {
727 fd.Service = append(fd.Service, r.asServiceDescriptor(decl.service))
728 } else if decl.pkg != nil {
729 if fd.Package != nil {
730 return ErrorWithSourcePos{Pos: decl.pkg.start(), Underlying: errors.New("files should have only one package declaration")}
731 }
732 file.pkg = decl.pkg
733 fd.Package = proto.String(decl.pkg.name.val)
734 }
735 }
736 r.fd = fd
737 return nil
738}
739
740func (r *parseResult) asUninterpretedOptions(nodes []*optionNode) []*dpb.UninterpretedOption {
741 opts := make([]*dpb.UninterpretedOption, len(nodes))
742 for i, n := range nodes {
743 opts[i] = r.asUninterpretedOption(n)
744 }
745 return opts
746}
747
748func (r *parseResult) asUninterpretedOption(node *optionNode) *dpb.UninterpretedOption {
749 opt := &dpb.UninterpretedOption{Name: r.asUninterpretedOptionName(node.name.parts)}
750 r.putOptionNode(opt, node)
751
752 switch val := node.val.value().(type) {
753 case bool:
754 if val {
755 opt.IdentifierValue = proto.String("true")
756 } else {
757 opt.IdentifierValue = proto.String("false")
758 }
759 case int64:
760 opt.NegativeIntValue = proto.Int64(val)
761 case uint64:
762 opt.PositiveIntValue = proto.Uint64(val)
763 case float64:
764 opt.DoubleValue = proto.Float64(val)
765 case string:
766 opt.StringValue = []byte(val)
767 case identifier:
768 opt.IdentifierValue = proto.String(string(val))
769 case []*aggregateEntryNode:
770 var buf bytes.Buffer
771 aggToString(val, &buf)
772 aggStr := buf.String()
773 opt.AggregateValue = proto.String(aggStr)
774 }
775 return opt
776}
777
778func (r *parseResult) asUninterpretedOptionName(parts []*optionNamePartNode) []*dpb.UninterpretedOption_NamePart {
779 ret := make([]*dpb.UninterpretedOption_NamePart, len(parts))
780 for i, part := range parts {
781 txt := part.text.val
782 if !part.isExtension {
783 txt = part.text.val[part.offset : part.offset+part.length]
784 }
785 np := &dpb.UninterpretedOption_NamePart{
786 NamePart: proto.String(txt),
787 IsExtension: proto.Bool(part.isExtension),
788 }
789 r.putOptionNamePartNode(np, part)
790 ret[i] = np
791 }
792 return ret
793}
794
795func (r *parseResult) addExtensions(ext *extendNode, flds *[]*dpb.FieldDescriptorProto, msgs *[]*dpb.DescriptorProto, isProto3 bool) {
796 extendee := ext.extendee.val
797 for _, decl := range ext.decls {
798 if decl.field != nil {
799 decl.field.extendee = ext
800 fd := r.asFieldDescriptor(decl.field)
801 fd.Extendee = proto.String(extendee)
802 *flds = append(*flds, fd)
803 } else if decl.group != nil {
804 decl.group.extendee = ext
805 fd, md := r.asGroupDescriptors(decl.group, isProto3)
806 fd.Extendee = proto.String(extendee)
807 *flds = append(*flds, fd)
808 *msgs = append(*msgs, md)
809 }
810 }
811}
812
813func asLabel(lbl *labelNode) *dpb.FieldDescriptorProto_Label {
814 if lbl == nil {
815 return nil
816 }
817 switch {
818 case lbl.repeated:
819 return dpb.FieldDescriptorProto_LABEL_REPEATED.Enum()
820 case lbl.required:
821 return dpb.FieldDescriptorProto_LABEL_REQUIRED.Enum()
822 default:
823 return dpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum()
824 }
825}
826
827func (r *parseResult) asFieldDescriptor(node *fieldNode) *dpb.FieldDescriptorProto {
828 fd := newFieldDescriptor(node.name.val, node.fldType.val, int32(node.tag.val), asLabel(node.label))
829 r.putFieldNode(fd, node)
830 if len(node.options) > 0 {
831 fd.Options = &dpb.FieldOptions{UninterpretedOption: r.asUninterpretedOptions(node.options)}
832 }
833 return fd
834}
835
836func newFieldDescriptor(name string, fieldType string, tag int32, lbl *dpb.FieldDescriptorProto_Label) *dpb.FieldDescriptorProto {
837 fd := &dpb.FieldDescriptorProto{
838 Name: proto.String(name),
839 JsonName: proto.String(internal.JsonName(name)),
840 Number: proto.Int32(tag),
841 Label: lbl,
842 }
843 switch fieldType {
844 case "double":
845 fd.Type = dpb.FieldDescriptorProto_TYPE_DOUBLE.Enum()
846 case "float":
847 fd.Type = dpb.FieldDescriptorProto_TYPE_FLOAT.Enum()
848 case "int32":
849 fd.Type = dpb.FieldDescriptorProto_TYPE_INT32.Enum()
850 case "int64":
851 fd.Type = dpb.FieldDescriptorProto_TYPE_INT64.Enum()
852 case "uint32":
853 fd.Type = dpb.FieldDescriptorProto_TYPE_UINT32.Enum()
854 case "uint64":
855 fd.Type = dpb.FieldDescriptorProto_TYPE_UINT64.Enum()
856 case "sint32":
857 fd.Type = dpb.FieldDescriptorProto_TYPE_SINT32.Enum()
858 case "sint64":
859 fd.Type = dpb.FieldDescriptorProto_TYPE_SINT64.Enum()
860 case "fixed32":
861 fd.Type = dpb.FieldDescriptorProto_TYPE_FIXED32.Enum()
862 case "fixed64":
863 fd.Type = dpb.FieldDescriptorProto_TYPE_FIXED64.Enum()
864 case "sfixed32":
865 fd.Type = dpb.FieldDescriptorProto_TYPE_SFIXED32.Enum()
866 case "sfixed64":
867 fd.Type = dpb.FieldDescriptorProto_TYPE_SFIXED64.Enum()
868 case "bool":
869 fd.Type = dpb.FieldDescriptorProto_TYPE_BOOL.Enum()
870 case "string":
871 fd.Type = dpb.FieldDescriptorProto_TYPE_STRING.Enum()
872 case "bytes":
873 fd.Type = dpb.FieldDescriptorProto_TYPE_BYTES.Enum()
874 default:
875 // NB: we don't have enough info to determine whether this is an enum or a message type,
876 // so we'll change it to enum later once we can ascertain if it's an enum reference
877 fd.Type = dpb.FieldDescriptorProto_TYPE_MESSAGE.Enum()
878 fd.TypeName = proto.String(fieldType)
879 }
880 return fd
881}
882
883func (r *parseResult) asGroupDescriptors(group *groupNode, isProto3 bool) (*dpb.FieldDescriptorProto, *dpb.DescriptorProto) {
884 fieldName := strings.ToLower(group.name.val)
885 fd := &dpb.FieldDescriptorProto{
886 Name: proto.String(fieldName),
887 JsonName: proto.String(internal.JsonName(fieldName)),
888 Number: proto.Int32(int32(group.tag.val)),
889 Label: asLabel(group.label),
890 Type: dpb.FieldDescriptorProto_TYPE_GROUP.Enum(),
891 TypeName: proto.String(group.name.val),
892 }
893 r.putFieldNode(fd, group)
894 md := &dpb.DescriptorProto{Name: proto.String(group.name.val)}
895 r.putMessageNode(md, group)
896 r.addMessageDecls(md, &group.reserved, group.decls, isProto3)
897 return fd, md
898}
899
900func (r *parseResult) asMapDescriptors(mapField *mapFieldNode, isProto3 bool) (*dpb.FieldDescriptorProto, *dpb.DescriptorProto) {
901 var lbl *dpb.FieldDescriptorProto_Label
902 if !isProto3 {
903 lbl = dpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum()
904 }
905 keyFd := newFieldDescriptor("key", mapField.keyType.val, 1, lbl)
906 r.putFieldNode(keyFd, mapField.keyField())
907 valFd := newFieldDescriptor("value", mapField.valueType.val, 2, lbl)
908 r.putFieldNode(valFd, mapField.valueField())
909 entryName := internal.InitCap(internal.JsonName(mapField.name.val)) + "Entry"
910 fd := newFieldDescriptor(mapField.name.val, entryName, int32(mapField.tag.val), dpb.FieldDescriptorProto_LABEL_REPEATED.Enum())
911 if len(mapField.options) > 0 {
912 fd.Options = &dpb.FieldOptions{UninterpretedOption: r.asUninterpretedOptions(mapField.options)}
913 }
914 r.putFieldNode(fd, mapField)
915 md := &dpb.DescriptorProto{
916 Name: proto.String(entryName),
917 Options: &dpb.MessageOptions{MapEntry: proto.Bool(true)},
918 Field: []*dpb.FieldDescriptorProto{keyFd, valFd},
919 }
920 r.putMessageNode(md, mapField)
921 return fd, md
922}
923
924func (r *parseResult) asExtensionRanges(node *extensionRangeNode) []*dpb.DescriptorProto_ExtensionRange {
925 opts := r.asUninterpretedOptions(node.options)
926 ers := make([]*dpb.DescriptorProto_ExtensionRange, len(node.ranges))
927 for i, rng := range node.ranges {
928 er := &dpb.DescriptorProto_ExtensionRange{
929 Start: proto.Int32(rng.st),
930 End: proto.Int32(rng.en + 1),
931 }
932 if len(opts) > 0 {
933 er.Options = &dpb.ExtensionRangeOptions{UninterpretedOption: opts}
934 }
935 r.putExtensionRangeNode(er, rng)
936 ers[i] = er
937 }
938 return ers
939}
940
941func (r *parseResult) asEnumValue(ev *enumValueNode) *dpb.EnumValueDescriptorProto {
942 var num int32
943 if ev.numberP != nil {
944 num = int32(ev.numberP.val)
945 } else {
946 num = int32(ev.numberN.val)
947 }
948 evd := &dpb.EnumValueDescriptorProto{Name: proto.String(ev.name.val), Number: proto.Int32(num)}
949 r.putEnumValueNode(evd, ev)
950 if len(ev.options) > 0 {
951 evd.Options = &dpb.EnumValueOptions{UninterpretedOption: r.asUninterpretedOptions(ev.options)}
952 }
953 return evd
954}
955
956func (r *parseResult) asMethodDescriptor(node *methodNode) *dpb.MethodDescriptorProto {
957 md := &dpb.MethodDescriptorProto{
958 Name: proto.String(node.name.val),
959 InputType: proto.String(node.input.msgType.val),
960 OutputType: proto.String(node.output.msgType.val),
961 }
962 r.putMethodNode(md, node)
963 if node.input.streamKeyword != nil {
964 md.ClientStreaming = proto.Bool(true)
965 }
966 if node.output.streamKeyword != nil {
967 md.ServerStreaming = proto.Bool(true)
968 }
969 // protoc always adds a MethodOptions if there are brackets
970 // We have a non-nil node.options if there are brackets
971 // We do the same to match protoc as closely as possible
972 // https://github.com/protocolbuffers/protobuf/blob/0c3f43a6190b77f1f68b7425d1b7e1a8257a8d0c/src/google/protobuf/compiler/parser.cc#L2152
973 if node.options != nil {
974 md.Options = &dpb.MethodOptions{UninterpretedOption: r.asUninterpretedOptions(node.options)}
975 }
976 return md
977}
978
979func (r *parseResult) asEnumDescriptor(en *enumNode) *dpb.EnumDescriptorProto {
980 ed := &dpb.EnumDescriptorProto{Name: proto.String(en.name.val)}
981 r.putEnumNode(ed, en)
982 for _, decl := range en.decls {
983 if decl.option != nil {
984 if ed.Options == nil {
985 ed.Options = &dpb.EnumOptions{}
986 }
987 ed.Options.UninterpretedOption = append(ed.Options.UninterpretedOption, r.asUninterpretedOption(decl.option))
988 } else if decl.value != nil {
989 ed.Value = append(ed.Value, r.asEnumValue(decl.value))
990 } else if decl.reserved != nil {
991 for _, n := range decl.reserved.names {
992 en.reserved = append(en.reserved, n)
993 ed.ReservedName = append(ed.ReservedName, n.val)
994 }
995 for _, rng := range decl.reserved.ranges {
996 ed.ReservedRange = append(ed.ReservedRange, r.asEnumReservedRange(rng))
997 }
998 }
999 }
1000 return ed
1001}
1002
1003func (r *parseResult) asEnumReservedRange(rng *rangeNode) *dpb.EnumDescriptorProto_EnumReservedRange {
1004 rr := &dpb.EnumDescriptorProto_EnumReservedRange{
1005 Start: proto.Int32(rng.st),
1006 End: proto.Int32(rng.en),
1007 }
1008 r.putEnumReservedRangeNode(rr, rng)
1009 return rr
1010}
1011
1012func (r *parseResult) asMessageDescriptor(node *messageNode, isProto3 bool) *dpb.DescriptorProto {
1013 msgd := &dpb.DescriptorProto{Name: proto.String(node.name.val)}
1014 r.putMessageNode(msgd, node)
1015 r.addMessageDecls(msgd, &node.reserved, node.decls, isProto3)
1016 return msgd
1017}
1018
1019func (r *parseResult) addMessageDecls(msgd *dpb.DescriptorProto, reservedNames *[]*stringLiteralNode, decls []*messageElement, isProto3 bool) {
1020 for _, decl := range decls {
1021 if decl.enum != nil {
1022 msgd.EnumType = append(msgd.EnumType, r.asEnumDescriptor(decl.enum))
1023 } else if decl.extend != nil {
1024 r.addExtensions(decl.extend, &msgd.Extension, &msgd.NestedType, isProto3)
1025 } else if decl.extensionRange != nil {
1026 msgd.ExtensionRange = append(msgd.ExtensionRange, r.asExtensionRanges(decl.extensionRange)...)
1027 } else if decl.field != nil {
1028 msgd.Field = append(msgd.Field, r.asFieldDescriptor(decl.field))
1029 } else if decl.mapField != nil {
1030 fd, md := r.asMapDescriptors(decl.mapField, isProto3)
1031 msgd.Field = append(msgd.Field, fd)
1032 msgd.NestedType = append(msgd.NestedType, md)
1033 } else if decl.group != nil {
1034 fd, md := r.asGroupDescriptors(decl.group, isProto3)
1035 msgd.Field = append(msgd.Field, fd)
1036 msgd.NestedType = append(msgd.NestedType, md)
1037 } else if decl.oneOf != nil {
1038 oodIndex := len(msgd.OneofDecl)
1039 ood := &dpb.OneofDescriptorProto{Name: proto.String(decl.oneOf.name.val)}
1040 r.putOneOfNode(ood, decl.oneOf)
1041 msgd.OneofDecl = append(msgd.OneofDecl, ood)
1042 for _, oodecl := range decl.oneOf.decls {
1043 if oodecl.option != nil {
1044 if ood.Options == nil {
1045 ood.Options = &dpb.OneofOptions{}
1046 }
1047 ood.Options.UninterpretedOption = append(ood.Options.UninterpretedOption, r.asUninterpretedOption(oodecl.option))
1048 } else if oodecl.field != nil {
1049 fd := r.asFieldDescriptor(oodecl.field)
1050 fd.OneofIndex = proto.Int32(int32(oodIndex))
1051 msgd.Field = append(msgd.Field, fd)
1052 }
1053 }
1054 } else if decl.option != nil {
1055 if msgd.Options == nil {
1056 msgd.Options = &dpb.MessageOptions{}
1057 }
1058 msgd.Options.UninterpretedOption = append(msgd.Options.UninterpretedOption, r.asUninterpretedOption(decl.option))
1059 } else if decl.nested != nil {
1060 msgd.NestedType = append(msgd.NestedType, r.asMessageDescriptor(decl.nested, isProto3))
1061 } else if decl.reserved != nil {
1062 for _, n := range decl.reserved.names {
1063 *reservedNames = append(*reservedNames, n)
1064 msgd.ReservedName = append(msgd.ReservedName, n.val)
1065 }
1066 for _, rng := range decl.reserved.ranges {
1067 msgd.ReservedRange = append(msgd.ReservedRange, r.asMessageReservedRange(rng))
1068 }
1069 }
1070 }
1071}
1072
1073func (r *parseResult) asMessageReservedRange(rng *rangeNode) *dpb.DescriptorProto_ReservedRange {
1074 rr := &dpb.DescriptorProto_ReservedRange{
1075 Start: proto.Int32(rng.st),
1076 End: proto.Int32(rng.en + 1),
1077 }
1078 r.putMessageReservedRangeNode(rr, rng)
1079 return rr
1080}
1081
1082func (r *parseResult) asServiceDescriptor(svc *serviceNode) *dpb.ServiceDescriptorProto {
1083 sd := &dpb.ServiceDescriptorProto{Name: proto.String(svc.name.val)}
1084 r.putServiceNode(sd, svc)
1085 for _, decl := range svc.decls {
1086 if decl.option != nil {
1087 if sd.Options == nil {
1088 sd.Options = &dpb.ServiceOptions{}
1089 }
1090 sd.Options.UninterpretedOption = append(sd.Options.UninterpretedOption, r.asUninterpretedOption(decl.option))
1091 } else if decl.rpc != nil {
1092 sd.Method = append(sd.Method, r.asMethodDescriptor(decl.rpc))
1093 }
1094 }
1095 return sd
1096}
1097
1098func toNameParts(ident *identNode, offset int) []*optionNamePartNode {
1099 parts := strings.Split(ident.val[offset:], ".")
1100 ret := make([]*optionNamePartNode, len(parts))
1101 for i, p := range parts {
1102 ret[i] = &optionNamePartNode{text: ident, offset: offset, length: len(p)}
1103 ret[i].setRange(ident, ident)
1104 offset += len(p) + 1
1105 }
1106 return ret
1107}
1108
1109func checkUint64InInt32Range(lex protoLexer, pos *SourcePos, v uint64) {
1110 if v > math.MaxInt32 {
1111 lexError(lex, pos, fmt.Sprintf("constant %d is out of range for int32 (%d to %d)", v, math.MinInt32, math.MaxInt32))
1112 }
1113}
1114
1115func checkInt64InInt32Range(lex protoLexer, pos *SourcePos, v int64) {
1116 if v > math.MaxInt32 || v < math.MinInt32 {
1117 lexError(lex, pos, fmt.Sprintf("constant %d is out of range for int32 (%d to %d)", v, math.MinInt32, math.MaxInt32))
1118 }
1119}
1120
1121func checkTag(lex protoLexer, pos *SourcePos, v uint64) {
1122 if v > internal.MaxTag {
1123 lexError(lex, pos, fmt.Sprintf("tag number %d is higher than max allowed tag number (%d)", v, internal.MaxTag))
1124 } else if v >= internal.SpecialReservedStart && v <= internal.SpecialReservedEnd {
1125 lexError(lex, pos, fmt.Sprintf("tag number %d is in disallowed reserved range %d-%d", v, internal.SpecialReservedStart, internal.SpecialReservedEnd))
1126 }
1127}
1128
1129func aggToString(agg []*aggregateEntryNode, buf *bytes.Buffer) {
1130 buf.WriteString("{")
1131 for _, a := range agg {
1132 buf.WriteString(" ")
1133 buf.WriteString(a.name.value())
1134 if v, ok := a.val.(*aggregateLiteralNode); ok {
1135 aggToString(v.elements, buf)
1136 } else {
1137 buf.WriteString(": ")
1138 elementToString(a.val.value(), buf)
1139 }
1140 }
1141 buf.WriteString(" }")
1142}
1143
1144func elementToString(v interface{}, buf *bytes.Buffer) {
1145 switch v := v.(type) {
1146 case bool, int64, uint64, identifier:
1147 fmt.Fprintf(buf, "%v", v)
1148 case float64:
1149 if math.IsInf(v, 1) {
1150 buf.WriteString(": inf")
1151 } else if math.IsInf(v, -1) {
1152 buf.WriteString(": -inf")
1153 } else if math.IsNaN(v) {
1154 buf.WriteString(": nan")
1155 } else {
1156 fmt.Fprintf(buf, ": %v", v)
1157 }
1158 case string:
1159 buf.WriteRune('"')
1160 writeEscapedBytes(buf, []byte(v))
1161 buf.WriteRune('"')
1162 case []valueNode:
1163 buf.WriteString(": [")
1164 first := true
1165 for _, e := range v {
1166 if first {
1167 first = false
1168 } else {
1169 buf.WriteString(", ")
1170 }
1171 elementToString(e.value(), buf)
1172 }
1173 buf.WriteString("]")
1174 case []*aggregateEntryNode:
1175 aggToString(v, buf)
1176 }
1177}
1178
1179func writeEscapedBytes(buf *bytes.Buffer, b []byte) {
1180 for _, c := range b {
1181 switch c {
1182 case '\n':
1183 buf.WriteString("\\n")
1184 case '\r':
1185 buf.WriteString("\\r")
1186 case '\t':
1187 buf.WriteString("\\t")
1188 case '"':
1189 buf.WriteString("\\\"")
1190 case '\'':
1191 buf.WriteString("\\'")
1192 case '\\':
1193 buf.WriteString("\\\\")
1194 default:
1195 if c >= 0x20 && c <= 0x7f && c != '"' && c != '\\' {
1196 // simple printable characters
1197 buf.WriteByte(c)
1198 } else {
1199 // use octal escape for all other values
1200 buf.WriteRune('\\')
1201 buf.WriteByte('0' + ((c >> 6) & 0x7))
1202 buf.WriteByte('0' + ((c >> 3) & 0x7))
1203 buf.WriteByte('0' + (c & 0x7))
1204 }
1205 }
1206 }
1207}
1208
1209func basicValidate(res *parseResult) error {
1210 fd := res.fd
1211 isProto3 := fd.GetSyntax() == "proto3"
1212
1213 for _, md := range fd.MessageType {
1214 if err := validateMessage(res, isProto3, "", md); err != nil {
1215 return err
1216 }
1217 }
1218
1219 for _, ed := range fd.EnumType {
1220 if err := validateEnum(res, isProto3, "", ed); err != nil {
1221 return err
1222 }
1223 }
1224
1225 for _, fld := range fd.Extension {
1226 if err := validateField(res, isProto3, "", fld); err != nil {
1227 return err
1228 }
1229 }
1230 return nil
1231}
1232
1233func validateMessage(res *parseResult, isProto3 bool, prefix string, md *dpb.DescriptorProto) error {
1234 nextPrefix := md.GetName() + "."
1235
1236 for _, fld := range md.Field {
1237 if err := validateField(res, isProto3, nextPrefix, fld); err != nil {
1238 return err
1239 }
1240 }
1241 for _, fld := range md.Extension {
1242 if err := validateField(res, isProto3, nextPrefix, fld); err != nil {
1243 return err
1244 }
1245 }
1246 for _, ed := range md.EnumType {
1247 if err := validateEnum(res, isProto3, nextPrefix, ed); err != nil {
1248 return err
1249 }
1250 }
1251 for _, nmd := range md.NestedType {
1252 if err := validateMessage(res, isProto3, nextPrefix, nmd); err != nil {
1253 return err
1254 }
1255 }
1256
1257 scope := fmt.Sprintf("message %s%s", prefix, md.GetName())
1258
1259 if isProto3 && len(md.ExtensionRange) > 0 {
1260 n := res.getExtensionRangeNode(md.ExtensionRange[0])
1261 return ErrorWithSourcePos{Pos: n.start(), Underlying: fmt.Errorf("%s: extension ranges are not allowed in proto3", scope)}
1262 }
1263
1264 if index, err := findOption(res, scope, md.Options.GetUninterpretedOption(), "map_entry"); err != nil {
1265 return err
1266 } else if index >= 0 {
1267 opt := md.Options.UninterpretedOption[index]
1268 optn := res.getOptionNode(opt)
1269 md.Options.UninterpretedOption = removeOption(md.Options.UninterpretedOption, index)
1270 valid := false
1271 if opt.IdentifierValue != nil {
1272 if opt.GetIdentifierValue() == "true" {
1273 return ErrorWithSourcePos{Pos: optn.getValue().start(), Underlying: fmt.Errorf("%s: map_entry option should not be set explicitly; use map type instead", scope)}
1274 } else if opt.GetIdentifierValue() == "false" {
1275 md.Options.MapEntry = proto.Bool(false)
1276 valid = true
1277 }
1278 }
1279 if !valid {
1280 return ErrorWithSourcePos{Pos: optn.getValue().start(), Underlying: fmt.Errorf("%s: expecting bool value for map_entry option", scope)}
1281 }
1282 }
1283
1284 // reserved ranges should not overlap
1285 rsvd := make(tagRanges, len(md.ReservedRange))
1286 for i, r := range md.ReservedRange {
1287 n := res.getMessageReservedRangeNode(r)
1288 rsvd[i] = tagRange{start: r.GetStart(), end: r.GetEnd(), node: n}
1289
1290 }
1291 sort.Sort(rsvd)
1292 for i := 1; i < len(rsvd); i++ {
1293 if rsvd[i].start < rsvd[i-1].end {
1294 return ErrorWithSourcePos{Pos: rsvd[i].node.start(), Underlying: fmt.Errorf("%s: reserved ranges overlap: %d to %d and %d to %d", scope, rsvd[i-1].start, rsvd[i-1].end-1, rsvd[i].start, rsvd[i].end-1)}
1295 }
1296 }
1297
1298 // extensions ranges should not overlap
1299 exts := make(tagRanges, len(md.ExtensionRange))
1300 for i, r := range md.ExtensionRange {
1301 n := res.getExtensionRangeNode(r)
1302 exts[i] = tagRange{start: r.GetStart(), end: r.GetEnd(), node: n}
1303 }
1304 sort.Sort(exts)
1305 for i := 1; i < len(exts); i++ {
1306 if exts[i].start < exts[i-1].end {
1307 return ErrorWithSourcePos{Pos: exts[i].node.start(), Underlying: fmt.Errorf("%s: extension ranges overlap: %d to %d and %d to %d", scope, exts[i-1].start, exts[i-1].end-1, exts[i].start, exts[i].end-1)}
1308 }
1309 }
1310
1311 // see if any extension range overlaps any reserved range
1312 var i, j int // i indexes rsvd; j indexes exts
1313 for i < len(rsvd) && j < len(exts) {
1314 if rsvd[i].start >= exts[j].start && rsvd[i].start < exts[j].end ||
1315 exts[j].start >= rsvd[i].start && exts[j].start < rsvd[i].end {
1316
1317 var pos *SourcePos
1318 if rsvd[i].start >= exts[j].start && rsvd[i].start < exts[j].end {
1319 pos = rsvd[i].node.start()
1320 } else {
1321 pos = exts[j].node.start()
1322 }
1323 // ranges overlap
1324 return ErrorWithSourcePos{Pos: pos, Underlying: fmt.Errorf("%s: extension range %d to %d overlaps reserved range %d to %d", scope, exts[j].start, exts[j].end-1, rsvd[i].start, rsvd[i].end-1)}
1325 }
1326 if rsvd[i].start < exts[j].start {
1327 i++
1328 } else {
1329 j++
1330 }
1331 }
1332
1333 // now, check that fields don't re-use tags and don't try to use extension
1334 // or reserved ranges or reserved names
1335 rsvdNames := map[string]struct{}{}
1336 for _, n := range md.ReservedName {
1337 rsvdNames[n] = struct{}{}
1338 }
1339 fieldTags := map[int32]string{}
1340 for _, fld := range md.Field {
1341 fn := res.getFieldNode(fld)
1342 if _, ok := rsvdNames[fld.GetName()]; ok {
1343 return ErrorWithSourcePos{Pos: fn.fieldName().start(), Underlying: fmt.Errorf("%s: field %s is using a reserved name", scope, fld.GetName())}
1344 }
1345 if existing := fieldTags[fld.GetNumber()]; existing != "" {
1346 return ErrorWithSourcePos{Pos: fn.fieldTag().start(), Underlying: fmt.Errorf("%s: fields %s and %s both have the same tag %d", scope, existing, fld.GetName(), fld.GetNumber())}
1347 }
1348 fieldTags[fld.GetNumber()] = fld.GetName()
1349 // check reserved ranges
1350 r := sort.Search(len(rsvd), func(index int) bool { return rsvd[index].end > fld.GetNumber() })
1351 if r < len(rsvd) && rsvd[r].start <= fld.GetNumber() {
1352 return ErrorWithSourcePos{Pos: fn.fieldTag().start(), Underlying: fmt.Errorf("%s: field %s is using tag %d which is in reserved range %d to %d", scope, fld.GetName(), fld.GetNumber(), rsvd[r].start, rsvd[r].end-1)}
1353 }
1354 // and check extension ranges
1355 e := sort.Search(len(exts), func(index int) bool { return exts[index].end > fld.GetNumber() })
1356 if e < len(exts) && exts[e].start <= fld.GetNumber() {
1357 return ErrorWithSourcePos{Pos: fn.fieldTag().start(), Underlying: fmt.Errorf("%s: field %s is using tag %d which is in extension range %d to %d", scope, fld.GetName(), fld.GetNumber(), exts[e].start, exts[e].end-1)}
1358 }
1359 }
1360
1361 return nil
1362}
1363
1364func validateEnum(res *parseResult, isProto3 bool, prefix string, ed *dpb.EnumDescriptorProto) error {
1365 scope := fmt.Sprintf("enum %s%s", prefix, ed.GetName())
1366
1367 if index, err := findOption(res, scope, ed.Options.GetUninterpretedOption(), "allow_alias"); err != nil {
1368 return err
1369 } else if index >= 0 {
1370 opt := ed.Options.UninterpretedOption[index]
1371 ed.Options.UninterpretedOption = removeOption(ed.Options.UninterpretedOption, index)
1372 valid := false
1373 if opt.IdentifierValue != nil {
1374 if opt.GetIdentifierValue() == "true" {
1375 ed.Options.AllowAlias = proto.Bool(true)
1376 valid = true
1377 } else if opt.GetIdentifierValue() == "false" {
1378 ed.Options.AllowAlias = proto.Bool(false)
1379 valid = true
1380 }
1381 }
1382 if !valid {
1383 optNode := res.getOptionNode(opt)
1384 return ErrorWithSourcePos{Pos: optNode.getValue().start(), Underlying: fmt.Errorf("%s: expecting bool value for allow_alias option", scope)}
1385 }
1386 }
1387
1388 if isProto3 && ed.Value[0].GetNumber() != 0 {
1389 evNode := res.getEnumValueNode(ed.Value[0])
1390 return ErrorWithSourcePos{Pos: evNode.getNumber().start(), Underlying: fmt.Errorf("%s: proto3 requires that first value in enum have numeric value of 0", scope)}
1391 }
1392
1393 if !ed.Options.GetAllowAlias() {
1394 // make sure all value numbers are distinct
1395 vals := map[int32]string{}
1396 for _, evd := range ed.Value {
1397 if existing := vals[evd.GetNumber()]; existing != "" {
1398 evNode := res.getEnumValueNode(evd)
1399 return ErrorWithSourcePos{Pos: evNode.getNumber().start(), Underlying: fmt.Errorf("%s: values %s and %s both have the same numeric value %d; use allow_alias option if intentional", scope, existing, evd.GetName(), evd.GetNumber())}
1400 }
1401 vals[evd.GetNumber()] = evd.GetName()
1402 }
1403 }
1404
1405 // reserved ranges should not overlap
1406 rsvd := make(tagRanges, len(ed.ReservedRange))
1407 for i, r := range ed.ReservedRange {
1408 n := res.getEnumReservedRangeNode(r)
1409 rsvd[i] = tagRange{start: r.GetStart(), end: r.GetEnd(), node: n}
1410 }
1411 sort.Sort(rsvd)
1412 for i := 1; i < len(rsvd); i++ {
1413 if rsvd[i].start <= rsvd[i-1].end {
1414 return ErrorWithSourcePos{Pos: rsvd[i].node.start(), Underlying: fmt.Errorf("%s: reserved ranges overlap: %d to %d and %d to %d", scope, rsvd[i-1].start, rsvd[i-1].end, rsvd[i].start, rsvd[i].end)}
1415 }
1416 }
1417
1418 // now, check that fields don't re-use tags and don't try to use extension
1419 // or reserved ranges or reserved names
1420 rsvdNames := map[string]struct{}{}
1421 for _, n := range ed.ReservedName {
1422 rsvdNames[n] = struct{}{}
1423 }
1424 for _, ev := range ed.Value {
1425 evn := res.getEnumValueNode(ev)
1426 if _, ok := rsvdNames[ev.GetName()]; ok {
1427 return ErrorWithSourcePos{Pos: evn.getName().start(), Underlying: fmt.Errorf("%s: value %s is using a reserved name", scope, ev.GetName())}
1428 }
1429 // check reserved ranges
1430 r := sort.Search(len(rsvd), func(index int) bool { return rsvd[index].end >= ev.GetNumber() })
1431 if r < len(rsvd) && rsvd[r].start <= ev.GetNumber() {
1432 return ErrorWithSourcePos{Pos: evn.getNumber().start(), Underlying: fmt.Errorf("%s: value %s is using number %d which is in reserved range %d to %d", scope, ev.GetName(), ev.GetNumber(), rsvd[r].start, rsvd[r].end)}
1433 }
1434 }
1435
1436 return nil
1437}
1438
1439func validateField(res *parseResult, isProto3 bool, prefix string, fld *dpb.FieldDescriptorProto) error {
1440 scope := fmt.Sprintf("field %s%s", prefix, fld.GetName())
1441
1442 node := res.getFieldNode(fld)
1443 if isProto3 {
1444 if fld.GetType() == dpb.FieldDescriptorProto_TYPE_GROUP {
1445 n := node.(*groupNode)
1446 return ErrorWithSourcePos{Pos: n.groupKeyword.start(), Underlying: fmt.Errorf("%s: groups are not allowed in proto3", scope)}
1447 }
1448 if fld.Label != nil && fld.GetLabel() != dpb.FieldDescriptorProto_LABEL_REPEATED {
1449 return ErrorWithSourcePos{Pos: node.fieldLabel().start(), Underlying: fmt.Errorf("%s: field has label %v, but proto3 should omit labels other than 'repeated'", scope, fld.GetLabel())}
1450 }
1451 if index, err := findOption(res, scope, fld.Options.GetUninterpretedOption(), "default"); err != nil {
1452 return err
1453 } else if index >= 0 {
1454 optNode := res.getOptionNode(fld.Options.GetUninterpretedOption()[index])
1455 return ErrorWithSourcePos{Pos: optNode.getName().start(), Underlying: fmt.Errorf("%s: default values are not allowed in proto3", scope)}
1456 }
1457 } else {
1458 if fld.Label == nil && fld.OneofIndex == nil {
1459 return ErrorWithSourcePos{Pos: node.fieldName().start(), Underlying: fmt.Errorf("%s: field has no label, but proto2 must indicate 'optional' or 'required'", scope)}
1460 }
1461 if fld.GetExtendee() != "" && fld.Label != nil && fld.GetLabel() == dpb.FieldDescriptorProto_LABEL_REQUIRED {
1462 return ErrorWithSourcePos{Pos: node.fieldLabel().start(), Underlying: fmt.Errorf("%s: extension fields cannot be 'required'", scope)}
1463 }
1464 }
1465
1466 // finally, set any missing label to optional
1467 if fld.Label == nil {
1468 fld.Label = dpb.FieldDescriptorProto_LABEL_OPTIONAL.Enum()
1469 }
1470 return nil
1471}
1472
1473func findOption(res *parseResult, scope string, opts []*dpb.UninterpretedOption, name string) (int, error) {
1474 found := -1
1475 for i, opt := range opts {
1476 if len(opt.Name) != 1 {
1477 continue
1478 }
1479 if opt.Name[0].GetIsExtension() || opt.Name[0].GetNamePart() != name {
1480 continue
1481 }
1482 if found >= 0 {
1483 optNode := res.getOptionNode(opt)
1484 return -1, ErrorWithSourcePos{Pos: optNode.getName().start(), Underlying: fmt.Errorf("%s: option %s cannot be defined more than once", scope, name)}
1485 }
1486 found = i
1487 }
1488 return found, nil
1489}
1490
1491func removeOption(uo []*dpb.UninterpretedOption, indexToRemove int) []*dpb.UninterpretedOption {
1492 if indexToRemove == 0 {
1493 return uo[1:]
1494 } else if int(indexToRemove) == len(uo)-1 {
1495 return uo[:len(uo)-1]
1496 } else {
1497 return append(uo[:indexToRemove], uo[indexToRemove+1:]...)
1498 }
1499}
1500
1501type tagRange struct {
1502 start int32
1503 end int32
1504 node rangeDecl
1505}
1506
1507type tagRanges []tagRange
1508
1509func (r tagRanges) Len() int {
1510 return len(r)
1511}
1512
1513func (r tagRanges) Less(i, j int) bool {
1514 return r[i].start < r[j].start ||
1515 (r[i].start == r[j].start && r[i].end < r[j].end)
1516}
1517
1518func (r tagRanges) Swap(i, j int) {
1519 r[i], r[j] = r[j], r[i]
1520}