Skip to content

protoc-gen-go: import public should be recursive #695

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
dsnet opened this issue Sep 4, 2018 · 3 comments
Open

protoc-gen-go: import public should be recursive #695

dsnet opened this issue Sep 4, 2018 · 3 comments
Labels

Comments

@dsnet
Copy link
Member

dsnet commented Sep 4, 2018

Consider the following set of files.

In file test1.proto:

syntax = "proto2";
import public "google/protobuf/descriptor.proto";

In file test2.proto:

syntax = "proto2";
import public "test1.proto";

In file test3.proto:

syntax = "proto2";
import public "test2.proto";

message Foo { optional google.protobuf.FileDescriptorProto field = 1; }

Compiling these with protoc --go_out=. test3.proto produces:

2018/09/03 22:46:30 protoc-gen-go: WARNING: failed finding publicly imported dependency for .google.protobuf.FileDescriptorProto, used in test3.proto
2018/09/03 22:46:30 protoc-gen-go: WARNING: failed finding publicly imported dependency for .google.protobuf.FileDescriptorProto, used in test3.proto
2018/09/03 22:46:30 protoc-gen-go: WARNING: failed finding publicly imported dependency for .google.protobuf.FileDescriptorProto, used in test3.proto

However, C++ is able to resolve google.protobuf.FileDescriptorProto just fine when running protoc --cpp_out=. test3.proto.

It seems that the behavior is that indirectly publicly import declarations are exported.

\cc @neild

@dsnet
Copy link
Member Author

dsnet commented Sep 4, 2018

It seems that this can be addressed in the new API by changing protoreflect.FileDescriptor.DescriptorByName:

// DescriptorByName looks up any descriptor declared within this file
// by full name. It returns nil if not found.
DescriptorByName(FullName) Descriptor

to also search the name within any files that were publicly imported (by also calling DescriptorByName which will have the desired recursive effect).

@dsnet dsnet added the bug label Sep 4, 2018
@dsnet
Copy link
Member Author

dsnet commented Sep 24, 2018

I'm fairly certain that the v2 API resolves this since prototype.findMessageDescriptor is responsible for resolving the message name, for which it searches the protoregistry.Files for all declarations that have been imported thus far:

func findMessageDescriptor(s string, r *protoregistry.Files) (protoreflect.MessageDescriptor, error) {
if !strings.HasPrefix(s, ".") {
return nil, errors.New("identifier name must be fully qualified with a leading dot: %v", s)
}
name := protoreflect.FullName(strings.TrimPrefix(s, "."))
switch m, err := r.FindDescriptorByName(name); {
case err == nil:
m, ok := m.(protoreflect.MessageDescriptor)
if !ok {
return nil, errors.New("resolved wrong type: got %v, want message", typeName(m))
}
return m, nil
case err == protoregistry.NotFound:
return PlaceholderMessage(name), nil
default:
return nil, err
}
}

However, this behavior is a more liberal than necessary, and validation (when implemented) will need to make sure not to accidentally break this again.

@dsnet dsnet added api-v2 and removed bug labels Sep 24, 2018
@dsnet dsnet added bug and removed api-v2 labels Jul 10, 2019
@dsymonds
Copy link
Contributor

FYI, the definition of "import public" back when it was introduced (circa 2010) was not transitive. Maybe something changed, but it's possible that C++ is only "accidentally" supporting it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants