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