Skip to content

Commit febffdd

Browse files
committed
reflect/protoregistry: permit conflicting file names
Remove the requirement that all registered files have unique names. Files.FindFileByPath now returns an error if multiple files match the path. Files.RangeFiles iterates over all files, including ones with the same name. Unlike descriptor names, file names are not part of any of the wire encodings. Conflicts in file names only affect file lookups by path, which is an uncommon operation. The Files.RegisterFile documentation already states (inaccurately), "It is permitted for multiple files to have the same file path." This change brings the behavior of RegisterFile in line with the documentation. Fixes golang/protobuf#1122 Change-Id: I2750e35736fd34def23fa6ab6d6a829095a65a26 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/321531 Trust: Damien Neil <[email protected]> Run-TryBot: Damien Neil <[email protected]> Reviewed-by: Joe Tsai <[email protected]>
1 parent 4c193d1 commit febffdd

File tree

2 files changed

+35
-25
lines changed

2 files changed

+35
-25
lines changed

reflect/protoregistry/registry.go

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ type Files struct {
9494
// Note that enum values are in the top-level since that are in the same
9595
// scope as the parent enum.
9696
descsByName map[protoreflect.FullName]interface{}
97-
filesByPath map[string]protoreflect.FileDescriptor
97+
filesByPath map[string][]protoreflect.FileDescriptor
98+
numFiles int
9899
}
99100

100101
type packageDescriptor struct {
@@ -117,17 +118,11 @@ func (r *Files) RegisterFile(file protoreflect.FileDescriptor) error {
117118
r.descsByName = map[protoreflect.FullName]interface{}{
118119
"": &packageDescriptor{},
119120
}
120-
r.filesByPath = make(map[string]protoreflect.FileDescriptor)
121+
r.filesByPath = make(map[string][]protoreflect.FileDescriptor)
121122
}
122123
path := file.Path()
123-
if prev := r.filesByPath[path]; prev != nil {
124+
if len(r.filesByPath[path]) > 0 {
124125
r.checkGenProtoConflict(path)
125-
err := errors.New("file %q is already registered", file.Path())
126-
err = amendErrorWithCaller(err, prev, file)
127-
if r == GlobalFiles && ignoreConflict(file, err) {
128-
err = nil
129-
}
130-
return err
131126
}
132127

133128
for name := file.Package(); name != ""; name = name.Parent() {
@@ -168,7 +163,8 @@ func (r *Files) RegisterFile(file protoreflect.FileDescriptor) error {
168163
rangeTopLevelDescriptors(file, func(d protoreflect.Descriptor) {
169164
r.descsByName[d.FullName()] = d
170165
})
171-
r.filesByPath[path] = file
166+
r.filesByPath[path] = append(r.filesByPath[path], file)
167+
r.numFiles++
172168
return nil
173169
}
174170

@@ -308,6 +304,7 @@ func (s *nameSuffix) Pop() (name protoreflect.Name) {
308304
// FindFileByPath looks up a file by the path.
309305
//
310306
// This returns (nil, NotFound) if not found.
307+
// This returns an error if multiple files have the same path.
311308
func (r *Files) FindFileByPath(path string) (protoreflect.FileDescriptor, error) {
312309
if r == nil {
313310
return nil, NotFound
@@ -316,13 +313,19 @@ func (r *Files) FindFileByPath(path string) (protoreflect.FileDescriptor, error)
316313
globalMutex.RLock()
317314
defer globalMutex.RUnlock()
318315
}
319-
if fd, ok := r.filesByPath[path]; ok {
320-
return fd, nil
316+
fds := r.filesByPath[path]
317+
switch len(fds) {
318+
case 0:
319+
return nil, NotFound
320+
case 1:
321+
return fds[0], nil
322+
default:
323+
return nil, errors.New("multiple files named %q", path)
321324
}
322-
return nil, NotFound
323325
}
324326

325-
// NumFiles reports the number of registered files.
327+
// NumFiles reports the number of registered files,
328+
// including duplicate files with the same name.
326329
func (r *Files) NumFiles() int {
327330
if r == nil {
328331
return 0
@@ -331,10 +334,11 @@ func (r *Files) NumFiles() int {
331334
globalMutex.RLock()
332335
defer globalMutex.RUnlock()
333336
}
334-
return len(r.filesByPath)
337+
return r.numFiles
335338
}
336339

337340
// RangeFiles iterates over all registered files while f returns true.
341+
// If multiple files have the same name, RangeFiles iterates over all of them.
338342
// The iteration order is undefined.
339343
func (r *Files) RangeFiles(f func(protoreflect.FileDescriptor) bool) {
340344
if r == nil {
@@ -344,9 +348,11 @@ func (r *Files) RangeFiles(f func(protoreflect.FileDescriptor) bool) {
344348
globalMutex.RLock()
345349
defer globalMutex.RUnlock()
346350
}
347-
for _, file := range r.filesByPath {
348-
if !f(file) {
349-
return
351+
for _, files := range r.filesByPath {
352+
for _, file := range files {
353+
if !f(file) {
354+
return
355+
}
350356
}
351357
}
352358
}

reflect/protoregistry/registry_test.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ func TestFiles(t *testing.T) {
5555
testFindPath struct {
5656
inPath string
5757
wantFiles []file
58+
wantErr string
5859
}
5960
)
6061

@@ -68,7 +69,7 @@ func TestFiles(t *testing.T) {
6869
files: []testFile{
6970
{inFile: mustMakeFile(`syntax:"proto2" name:"test1.proto" package:"foo.bar"`)},
7071
{inFile: mustMakeFile(`syntax:"proto2" name:"foo/bar/test.proto" package:"my.test"`)},
71-
{inFile: mustMakeFile(`syntax:"proto2" name:"foo/bar/test.proto" package:"foo.bar.baz"`), wantErr: "already registered"},
72+
{inFile: mustMakeFile(`syntax:"proto2" name:"foo/bar/test.proto" package:"foo.bar.baz"`)},
7273
{inFile: mustMakeFile(`syntax:"proto2" name:"test2.proto" package:"my.test.package"`)},
7374
{inFile: mustMakeFile(`syntax:"proto2" name:"weird" package:"foo.bar"`)},
7475
{inFile: mustMakeFile(`syntax:"proto2" name:"foo/bar/baz/../test.proto" package:"my.test"`)},
@@ -103,17 +104,16 @@ func TestFiles(t *testing.T) {
103104
}},
104105

105106
findPaths: []testFindPath{{
106-
inPath: "nothing",
107+
inPath: "nothing",
108+
wantErr: "not found",
107109
}, {
108110
inPath: "weird",
109111
wantFiles: []file{
110112
{"weird", "foo.bar"},
111113
},
112114
}, {
113-
inPath: "foo/bar/test.proto",
114-
wantFiles: []file{
115-
{"foo/bar/test.proto", "my.test"},
116-
},
115+
inPath: "foo/bar/test.proto",
116+
wantErr: `multiple files named "foo/bar/test.proto"`,
117117
}},
118118
}, {
119119
// Test when new enum conflicts with existing package.
@@ -315,9 +315,13 @@ func TestFiles(t *testing.T) {
315315

316316
for _, tc := range tt.findPaths {
317317
var gotFiles []file
318-
if fd, err := files.FindFileByPath(tc.inPath); err == nil {
318+
fd, gotErr := files.FindFileByPath(tc.inPath)
319+
if gotErr == nil {
319320
gotFiles = append(gotFiles, file{fd.Path(), fd.Package()})
320321
}
322+
if ((gotErr == nil) != (tc.wantErr == "")) || !strings.Contains(fmt.Sprint(gotErr), tc.wantErr) {
323+
t.Errorf("FindFileByPath(%v) = %v, want %v", tc.inPath, gotErr, tc.wantErr)
324+
}
321325
if diff := cmp.Diff(tc.wantFiles, gotFiles, sortFiles); diff != "" {
322326
t.Errorf("FindFileByPath(%v) mismatch (-want +got):\n%v", tc.inPath, diff)
323327
}

0 commit comments

Comments
 (0)