1
2
3
4
5
6
7
8
9
10
11
12
13 package protodesc
14
15 import (
16 "google.golang.org/protobuf/internal/editionssupport"
17 "google.golang.org/protobuf/internal/errors"
18 "google.golang.org/protobuf/internal/filedesc"
19 "google.golang.org/protobuf/internal/pragma"
20 "google.golang.org/protobuf/internal/strs"
21 "google.golang.org/protobuf/proto"
22 "google.golang.org/protobuf/reflect/protoreflect"
23 "google.golang.org/protobuf/reflect/protoregistry"
24
25 "google.golang.org/protobuf/types/descriptorpb"
26 )
27
28
29
30
31
32
33 type Resolver interface {
34 FindFileByPath(string) (protoreflect.FileDescriptor, error)
35 FindDescriptorByName(protoreflect.FullName) (protoreflect.Descriptor, error)
36 }
37
38
39 type FileOptions struct {
40 pragma.NoUnkeyedLiterals
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 AllowUnresolvable bool
63 }
64
65
66
67 func NewFile(fd *descriptorpb.FileDescriptorProto, r Resolver) (protoreflect.FileDescriptor, error) {
68 return FileOptions{}.New(fd, r)
69 }
70
71
72
73 func NewFiles(fd *descriptorpb.FileDescriptorSet) (*protoregistry.Files, error) {
74 return FileOptions{}.NewFiles(fd)
75 }
76
77
78
79
80
81
82
83
84
85 func (o FileOptions) New(fd *descriptorpb.FileDescriptorProto, r Resolver) (protoreflect.FileDescriptor, error) {
86 if r == nil {
87 r = (*protoregistry.Files)(nil)
88 }
89
90
91 f := &filedesc.File{L2: &filedesc.FileL2{}}
92 switch fd.GetSyntax() {
93 case "proto2", "":
94 f.L1.Syntax = protoreflect.Proto2
95 f.L1.Edition = filedesc.EditionProto2
96 case "proto3":
97 f.L1.Syntax = protoreflect.Proto3
98 f.L1.Edition = filedesc.EditionProto3
99 case "editions":
100 f.L1.Syntax = protoreflect.Editions
101 f.L1.Edition = fromEditionProto(fd.GetEdition())
102 default:
103 return nil, errors.New("invalid syntax: %q", fd.GetSyntax())
104 }
105 if f.L1.Syntax == protoreflect.Editions && (fd.GetEdition() < editionssupport.Minimum || fd.GetEdition() > editionssupport.Maximum) {
106 return nil, errors.New("use of edition %v not yet supported by the Go Protobuf runtime", fd.GetEdition())
107 }
108 f.L1.Path = fd.GetName()
109 if f.L1.Path == "" {
110 return nil, errors.New("file path must be populated")
111 }
112 f.L1.Package = protoreflect.FullName(fd.GetPackage())
113 if !f.L1.Package.IsValid() && f.L1.Package != "" {
114 return nil, errors.New("invalid package: %q", f.L1.Package)
115 }
116 if opts := fd.GetOptions(); opts != nil {
117 opts = proto.Clone(opts).(*descriptorpb.FileOptions)
118 f.L2.Options = func() protoreflect.ProtoMessage { return opts }
119 }
120 initFileDescFromFeatureSet(f, fd.GetOptions().GetFeatures())
121
122 f.L2.Imports = make(filedesc.FileImports, len(fd.GetDependency()))
123 for _, i := range fd.GetPublicDependency() {
124 if !(0 <= i && int(i) < len(f.L2.Imports)) || f.L2.Imports[i].IsPublic {
125 return nil, errors.New("invalid or duplicate public import index: %d", i)
126 }
127 f.L2.Imports[i].IsPublic = true
128 }
129 for _, i := range fd.GetWeakDependency() {
130 if !(0 <= i && int(i) < len(f.L2.Imports)) || f.L2.Imports[i].IsWeak {
131 return nil, errors.New("invalid or duplicate weak import index: %d", i)
132 }
133 f.L2.Imports[i].IsWeak = true
134 }
135 imps := importSet{f.Path(): true}
136 for i, path := range fd.GetDependency() {
137 imp := &f.L2.Imports[i]
138 f, err := r.FindFileByPath(path)
139 if err == protoregistry.NotFound && (o.AllowUnresolvable || imp.IsWeak) {
140 f = filedesc.PlaceholderFile(path)
141 } else if err != nil {
142 return nil, errors.New("could not resolve import %q: %v", path, err)
143 }
144 imp.FileDescriptor = f
145
146 if imps[imp.Path()] {
147 return nil, errors.New("already imported %q", path)
148 }
149 imps[imp.Path()] = true
150 }
151 for i := range fd.GetDependency() {
152 imp := &f.L2.Imports[i]
153 imps.importPublic(imp.Imports())
154 }
155
156
157 f.L2.Locations.File = f
158 for _, loc := range fd.GetSourceCodeInfo().GetLocation() {
159 var l protoreflect.SourceLocation
160
161 l.Path = protoreflect.SourcePath(loc.GetPath())
162 s := loc.GetSpan()
163 switch len(s) {
164 case 3:
165 l.StartLine, l.StartColumn, l.EndLine, l.EndColumn = int(s[0]), int(s[1]), int(s[0]), int(s[2])
166 case 4:
167 l.StartLine, l.StartColumn, l.EndLine, l.EndColumn = int(s[0]), int(s[1]), int(s[2]), int(s[3])
168 default:
169 return nil, errors.New("invalid span: %v", s)
170 }
171
172
173 if false && (l.EndLine < l.StartLine || l.StartLine < 0 || l.StartColumn < 0 || l.EndColumn < 0 ||
174 (l.StartLine == l.EndLine && l.EndColumn <= l.StartColumn)) {
175 return nil, errors.New("invalid span: %v", s)
176 }
177 l.LeadingDetachedComments = loc.GetLeadingDetachedComments()
178 l.LeadingComments = loc.GetLeadingComments()
179 l.TrailingComments = loc.GetTrailingComments()
180 f.L2.Locations.List = append(f.L2.Locations.List, l)
181 }
182
183
184
185
186
187
188
189
190
191 var err error
192 sb := new(strs.Builder)
193 r1 := make(descsByName)
194 if f.L1.Enums.List, err = r1.initEnumDeclarations(fd.GetEnumType(), f, sb); err != nil {
195 return nil, err
196 }
197 if f.L1.Messages.List, err = r1.initMessagesDeclarations(fd.GetMessageType(), f, sb); err != nil {
198 return nil, err
199 }
200 if f.L1.Extensions.List, err = r1.initExtensionDeclarations(fd.GetExtension(), f, sb); err != nil {
201 return nil, err
202 }
203 if f.L1.Services.List, err = r1.initServiceDeclarations(fd.GetService(), f, sb); err != nil {
204 return nil, err
205 }
206
207
208 r2 := &resolver{local: r1, remote: r, imports: imps, allowUnresolvable: o.AllowUnresolvable}
209 if err := r2.resolveMessageDependencies(f.L1.Messages.List, fd.GetMessageType()); err != nil {
210 return nil, err
211 }
212 if err := r2.resolveExtensionDependencies(f.L1.Extensions.List, fd.GetExtension()); err != nil {
213 return nil, err
214 }
215 if err := r2.resolveServiceDependencies(f.L1.Services.List, fd.GetService()); err != nil {
216 return nil, err
217 }
218
219
220 if err := validateEnumDeclarations(f.L1.Enums.List, fd.GetEnumType()); err != nil {
221 return nil, err
222 }
223 if err := validateMessageDeclarations(f, f.L1.Messages.List, fd.GetMessageType()); err != nil {
224 return nil, err
225 }
226 if err := validateExtensionDeclarations(f, f.L1.Extensions.List, fd.GetExtension()); err != nil {
227 return nil, err
228 }
229
230 return f, nil
231 }
232
233 type importSet map[string]bool
234
235 func (is importSet) importPublic(imps protoreflect.FileImports) {
236 for i := 0; i < imps.Len(); i++ {
237 if imp := imps.Get(i); imp.IsPublic {
238 is[imp.Path()] = true
239 is.importPublic(imp.Imports())
240 }
241 }
242 }
243
244
245
246
247
248 func (o FileOptions) NewFiles(fds *descriptorpb.FileDescriptorSet) (*protoregistry.Files, error) {
249 files := make(map[string]*descriptorpb.FileDescriptorProto)
250 for _, fd := range fds.File {
251 if _, ok := files[fd.GetName()]; ok {
252 return nil, errors.New("file appears multiple times: %q", fd.GetName())
253 }
254 files[fd.GetName()] = fd
255 }
256 r := &protoregistry.Files{}
257 for _, fd := range files {
258 if err := o.addFileDeps(r, fd, files); err != nil {
259 return nil, err
260 }
261 }
262 return r, nil
263 }
264 func (o FileOptions) addFileDeps(r *protoregistry.Files, fd *descriptorpb.FileDescriptorProto, files map[string]*descriptorpb.FileDescriptorProto) error {
265
266 files[fd.GetName()] = nil
267 for _, dep := range fd.Dependency {
268 depfd, ok := files[dep]
269 if depfd == nil {
270 if ok {
271 return errors.New("import cycle in file: %q", dep)
272 }
273 continue
274 }
275 if err := o.addFileDeps(r, depfd, files); err != nil {
276 return err
277 }
278 }
279
280 delete(files, fd.GetName())
281 f, err := o.New(fd, r)
282 if err != nil {
283 return err
284 }
285 return r.RegisterFile(f)
286 }
287
View as plain text