diff --git a/rust/test/BUILD b/rust/test/BUILD index 436c5ae71c..2b3285de3d 100644 --- a/rust/test/BUILD +++ b/rust/test/BUILD @@ -1,10 +1,10 @@ -load("@rules_cc//cc:defs.bzl", "cc_proto_library") load( "//rust:defs.bzl", "rust_cc_proto_library", "rust_proto_library", "rust_upb_proto_library", ) +load("@rules_cc//cc:defs.bzl", "cc_proto_library") UNITTEST_PROTO_TARGET = "//src/google/protobuf:test_protos" @@ -440,3 +440,64 @@ rust_upb_proto_library( ], deps = [":struct"], ) + +proto_library( + name = "imported_types_proto", + testonly = True, + srcs = ["imported_types.proto"], +) + +cc_proto_library( + name = "imported_types_cc_proto", + testonly = True, + deps = [":imported_types_proto"], +) + +rust_cc_proto_library( + name = "imported_types_cc_rust_proto", + testonly = True, + visibility = [ + "//rust/test/shared:__subpackages__", + ], + deps = [":imported_types_cc_proto"], +) + +rust_upb_proto_library( + name = "imported_types_upb_rust_proto", + testonly = True, + visibility = [ + "//rust/test/shared:__subpackages__", + ], + deps = [":imported_types_proto"], +) + +proto_library( + name = "fields_with_imported_types_proto", + testonly = True, + srcs = ["fields_with_imported_types.proto"], + deps = [":imported_types_proto"], +) + +cc_proto_library( + name = "fields_with_imported_types_cc_proto", + testonly = True, + deps = [":fields_with_imported_types_proto"], +) + +rust_cc_proto_library( + name = "fields_with_imported_types_cc_rust_proto", + testonly = True, + visibility = [ + "//rust/test/shared:__subpackages__", + ], + deps = [":fields_with_imported_types_cc_proto"], +) + +rust_upb_proto_library( + name = "fields_with_imported_types_upb_rust_proto", + testonly = True, + visibility = [ + "//rust/test/shared:__subpackages__", + ], + deps = [":fields_with_imported_types_proto"], +) diff --git a/rust/test/fields_with_imported_types.proto b/rust/test/fields_with_imported_types.proto new file mode 100644 index 0000000000..2610ff2c74 --- /dev/null +++ b/rust/test/fields_with_imported_types.proto @@ -0,0 +1,22 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2024 Google LLC. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +syntax = "proto2"; + +package main; + +import "google/protobuf/rust/test/imported_types.proto"; + +message MsgWithFieldsWithImportedTypes { + optional imported_types.ImportedMessage imported_message_field = 1; + optional imported_types.ImportedEnum imported_enum_field = 2; + + oneof imported_types_oneof { + imported_types.ImportedMessage imported_message_oneof = 3; + imported_types.ImportedEnum imported_enum_oneof = 4; + } +} diff --git a/rust/test/imported_types.proto b/rust/test/imported_types.proto new file mode 100644 index 0000000000..fbf06db7da --- /dev/null +++ b/rust/test/imported_types.proto @@ -0,0 +1,19 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2024 Google LLC. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +syntax = "proto2"; + +package imported_types; + +message ImportedMessage { + optional int32 num = 1; +} + +enum ImportedEnum { + IMPORTED_ENUM_UNKNOWN = 0; + IMPORTED_ENUM_BAR = 1; +} diff --git a/rust/test/shared/BUILD b/rust/test/shared/BUILD index 28678a45fd..60395b98de 100644 --- a/rust/test/shared/BUILD +++ b/rust/test/shared/BUILD @@ -481,3 +481,33 @@ rust_test( "//rust/test:struct_upb_rust_proto", ], ) + +rust_test( + name = "fields_with_imported_types_cpp_test", + srcs = ["fields_with_imported_types_test.rs"], + tags = [ + # TODO: Enable testing on arm once we support sanitizers for Rust on Arm. + "not_build:arm", + ], + deps = [ + "//rust:protobuf_cpp", + "//rust/test:fields_with_imported_types_cc_rust_proto", + "//rust/test:imported_types_cc_rust_proto", + "@crate_index//:googletest", + ], +) + +rust_test( + name = "fields_with_imported_types_upb_test", + srcs = ["fields_with_imported_types_test.rs"], + tags = [ + # TODO: Enable testing on arm once we support sanitizers for Rust on Arm. + "not_build:arm", + ], + deps = [ + "//rust:protobuf_upb", + "//rust/test:fields_with_imported_types_upb_rust_proto", + "//rust/test:imported_types_upb_rust_proto", + "@crate_index//:googletest", + ], +) diff --git a/rust/test/shared/fields_with_imported_types_test.rs b/rust/test/shared/fields_with_imported_types_test.rs new file mode 100644 index 0000000000..c0651a61b9 --- /dev/null +++ b/rust/test/shared/fields_with_imported_types_test.rs @@ -0,0 +1,42 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2024 Google LLC. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +/// Tests covering that fields with types that are defined in imported .proto +/// files are generated. In particular where the imported .proto file is part of +/// a separate proto_library target. +use googletest::prelude::*; + +#[test] +fn test_message_field_generated() { + use fields_with_imported_types_proto::MsgWithFieldsWithImportedTypes; + use imported_types_proto::ImportedMessageView; + + let msg = MsgWithFieldsWithImportedTypes::new(); + assert_that!(msg.imported_message_field(), matches_pattern!(ImportedMessageView { .. })); +} + +#[test] +fn test_enum_field_generated() { + use fields_with_imported_types_proto::MsgWithFieldsWithImportedTypes; + use imported_types_proto::ImportedEnum; + + let msg = MsgWithFieldsWithImportedTypes::new(); + assert_that!(msg.imported_enum_field(), eq(ImportedEnum::Unknown)); +} + +#[test] +fn test_oneof_message_field_generated() { + use fields_with_imported_types_proto::MsgWithFieldsWithImportedTypes; + use fields_with_imported_types_proto::MsgWithFieldsWithImportedTypes_::ImportedTypesOneof::not_set; + use imported_types_proto::ImportedEnum; + use imported_types_proto::ImportedMessageView; + + let msg = MsgWithFieldsWithImportedTypes::new(); + assert_that!(msg.imported_message_oneof(), matches_pattern!(ImportedMessageView { .. })); + assert_that!(msg.imported_enum_oneof(), eq(ImportedEnum::Unknown)); + assert_that!(msg.imported_types_oneof(), matches_pattern!(not_set(_))); +} diff --git a/src/google/protobuf/compiler/rust/accessors/accessors.cc b/src/google/protobuf/compiler/rust/accessors/accessors.cc index 6bd951f27f..d63c79628c 100644 --- a/src/google/protobuf/compiler/rust/accessors/accessors.cc +++ b/src/google/protobuf/compiler/rust/accessors/accessors.cc @@ -64,12 +64,6 @@ std::unique_ptr AccessorGeneratorFor( } return std::make_unique(); case FieldDescriptor::TYPE_ENUM: - // TODO: support enums which are defined in other crates. - if (!IsInCurrentlyGeneratingCrate(ctx, *field.enum_type())) { - return std::make_unique( - "enum fields that are imported from another proto_library" - " (defined in a separate Rust crate) are not supported"); - } if (field.is_repeated()) { return std::make_unique(); } @@ -81,12 +75,6 @@ std::unique_ptr AccessorGeneratorFor( } return std::make_unique(); case FieldDescriptor::TYPE_MESSAGE: - // TODO: support messages which are defined in other crates. - if (!IsInCurrentlyGeneratingCrate(ctx, *field.message_type())) { - return std::make_unique( - "message fields that are imported from another proto_library" - " (defined in a separate Rust crate) are not supported"); - } if (field.is_repeated()) { return std::make_unique(); } diff --git a/src/google/protobuf/compiler/rust/naming.cc b/src/google/protobuf/compiler/rust/naming.cc index eca7efd383..10eb6b162b 100644 --- a/src/google/protobuf/compiler/rust/naming.cc +++ b/src/google/protobuf/compiler/rust/naming.cc @@ -167,6 +167,22 @@ std::string ThunkName(Context& ctx, const Descriptor& msg, op); } +std::string GetFullyQualifiedPath(Context& ctx, const Descriptor& msg) { + auto rel_path = GetCrateRelativeQualifiedPath(ctx, msg); + if (IsInCurrentlyGeneratingCrate(ctx, msg)) { + return absl::StrCat("crate::", rel_path); + } + return absl::StrCat(GetCrateName(ctx, *msg.file()), "::", rel_path); +} + +std::string GetFullyQualifiedPath(Context& ctx, const EnumDescriptor& enum_) { + auto rel_path = GetCrateRelativeQualifiedPath(ctx, enum_); + if (IsInCurrentlyGeneratingCrate(ctx, enum_)) { + return absl::StrCat("crate::", rel_path); + } + return absl::StrCat(GetCrateName(ctx, *enum_.file()), "::", rel_path); +} + std::string RsTypePath(Context& ctx, const FieldDescriptor& field) { switch (field.type()) { case FieldDescriptor::TYPE_BOOL: @@ -194,13 +210,9 @@ std::string RsTypePath(Context& ctx, const FieldDescriptor& field) { case FieldDescriptor::TYPE_STRING: return "::__pb::ProtoStr"; case FieldDescriptor::TYPE_MESSAGE: - // TODO: Fix depending on types from other proto_libraries. - return absl::StrCat( - "crate::", GetCrateRelativeQualifiedPath(ctx, *field.message_type())); + return GetFullyQualifiedPath(ctx, *field.message_type()); case FieldDescriptor::TYPE_ENUM: - // TODO: Fix depending on types from other proto_libraries. - return absl::StrCat( - "crate::", GetCrateRelativeQualifiedPath(ctx, *field.enum_type())); + return GetFullyQualifiedPath(ctx, *field.enum_type()); default: break; } diff --git a/src/google/protobuf/compiler/rust/oneof.cc b/src/google/protobuf/compiler/rust/oneof.cc index bb7e1f091b..e07541183d 100644 --- a/src/google/protobuf/compiler/rust/oneof.cc +++ b/src/google/protobuf/compiler/rust/oneof.cc @@ -106,16 +106,8 @@ std::string RsTypeNameView(Context& ctx, const FieldDescriptor& field) { case FieldDescriptor::TYPE_STRING: return "&'msg ::__pb::ProtoStr"; case FieldDescriptor::TYPE_MESSAGE: - // TODO: support messages which are defined in other crates. - if (!IsInCurrentlyGeneratingCrate(ctx, *field.message_type())) { - return ""; - } return absl::StrCat("::__pb::View<'msg, ", RsTypePath(ctx, field), ">"); case FieldDescriptor::TYPE_ENUM: - // TODO: support enums which are defined in other crates. - if (!IsInCurrentlyGeneratingCrate(ctx, *field.enum_type())) { - return ""; - } return absl::StrCat("::__pb::View<'msg, ", RsTypePath(ctx, field), ">"); case FieldDescriptor::TYPE_GROUP: // Not supported yet. return ""; @@ -151,16 +143,8 @@ std::string RsTypeNameMut(Context& ctx, const FieldDescriptor& field) { case FieldDescriptor::TYPE_STRING: return "::__pb::ProtoStrMut<'msg>"; case FieldDescriptor::TYPE_MESSAGE: - // TODO: support messages which are defined in other crates. - if (!IsInCurrentlyGeneratingCrate(ctx, *field.message_type())) { - return ""; - } return absl::StrCat("::__pb::Mut<'msg, ", RsTypePath(ctx, field), ">"); case FieldDescriptor::TYPE_ENUM: - // TODO: support enums which are defined in other crates. - if (!IsInCurrentlyGeneratingCrate(ctx, *field.enum_type())) { - return ""; - } return absl::StrCat("::__pb::Mut<'msg, ", RsTypePath(ctx, field), ">"); case FieldDescriptor::TYPE_GROUP: // Not supported yet. return ""; diff --git a/src/google/protobuf/editions/codegen_tests/BUILD b/src/google/protobuf/editions/codegen_tests/BUILD index f2853fe42d..7433a091fa 100644 --- a/src/google/protobuf/editions/codegen_tests/BUILD +++ b/src/google/protobuf/editions/codegen_tests/BUILD @@ -1,7 +1,7 @@ load("@rules_cc//cc:defs.bzl", "cc_proto_library") exports_files( - glob(["*.proto"]), + glob(["*.proto"]) + ["rust_bazel_crate_mapping.txt"], visibility = [ "//src/google/protobuf/editions:__pkg__", ], diff --git a/src/google/protobuf/editions/codegen_tests/rust_bazel_crate_mapping.txt b/src/google/protobuf/editions/codegen_tests/rust_bazel_crate_mapping.txt new file mode 100644 index 0000000000..2464639010 --- /dev/null +++ b/src/google/protobuf/editions/codegen_tests/rust_bazel_crate_mapping.txt @@ -0,0 +1,27 @@ +proto3_implicit_proto +1 +third_party/protobuf/editions/codegen_tests/proto3_implicit.proto +proto2_optional_proto +1 +third_party/protobuf/editions/codegen_tests/proto2_optional.proto +proto3_enum_proto +1 +third_party/protobuf/editions/codegen_tests/proto3_enum.proto +struct +1 +google/protobuf/struct.proto +wrappers +1 +google/protobuf/wrappers.proto +duration +1 +google/protobuf/duration.proto +timestamp +1 +google/protobuf/timestamp.proto +field_mask +1 +google/protobuf/field_mask.proto +any +1 +google/protobuf/any.proto \ No newline at end of file