Fix toproto behavior for groups and required under editions

PiperOrigin-RevId: 619359463
pull/16315/head
Mike Kruskal 2024-03-26 17:21:01 -07:00 committed by Copybara-Service
parent 6c45efd297
commit 7662fdd8ed
4 changed files with 73 additions and 2 deletions

View File

@ -18,6 +18,8 @@ cc_library(
hdrs = ["def_to_proto.h"],
visibility = ["//visibility:public"],
deps = [
"//upb:base",
"//upb:descriptor_upb_proto",
"//upb:port",
"//upb:reflection",
"//upb/reflection:internal",
@ -64,11 +66,15 @@ cc_test(
srcs = ["def_to_proto_test.cc"],
deps = [
":def_to_proto",
":def_to_proto_editions_test_upb_proto",
":def_to_proto_editions_test_upb_proto_reflection",
":def_to_proto_test_lib",
":def_to_proto_test_upb_proto",
":def_to_proto_test_upb_proto_reflection",
"//:protobuf",
"//src/google/protobuf/util:differencer",
"//upb:base",
"//upb:descriptor_upb_proto",
"//upb:descriptor_upb_proto_reflection",
"//upb:mem",
"//upb:reflection",
@ -108,6 +114,21 @@ cc_library(
],
)
proto_library(
name = "def_to_proto_editions_test_proto",
srcs = ["def_to_proto_editions_test.proto"],
)
upb_c_proto_library(
name = "def_to_proto_editions_test_upb_proto",
deps = ["def_to_proto_editions_test_proto"],
)
upb_proto_reflection_library(
name = "def_to_proto_editions_test_upb_proto_reflection",
deps = ["def_to_proto_editions_test_proto"],
)
proto_library(
name = "required_fields_test_proto",
srcs = [

View File

@ -10,7 +10,10 @@
#include <inttypes.h>
#include <math.h>
#include "google/protobuf/descriptor.upb.h"
#include "upb/base/descriptor_constants.h"
#include "upb/port/vsnprintf_compat.h"
#include "upb/reflection/def.h"
#include "upb/reflection/enum_reserved_range.h"
#include "upb/reflection/extension_range.h"
#include "upb/reflection/internal/field_def.h"
@ -218,8 +221,20 @@ static google_protobuf_FieldDescriptorProto* fielddef_toproto(upb_ToProto_Contex
google_protobuf_FieldDescriptorProto_set_name(proto,
strviewdup(ctx, upb_FieldDef_Name(f)));
google_protobuf_FieldDescriptorProto_set_number(proto, upb_FieldDef_Number(f));
google_protobuf_FieldDescriptorProto_set_label(proto, upb_FieldDef_Label(f));
google_protobuf_FieldDescriptorProto_set_type(proto, upb_FieldDef_Type(f));
if (upb_FieldDef_IsRequired(f) &&
upb_FileDef_Edition(upb_FieldDef_File(f)) >= UPB_DESC(EDITION_2023)) {
google_protobuf_FieldDescriptorProto_set_label(
proto, UPB_DESC(FieldDescriptorProto_LABEL_OPTIONAL));
} else {
google_protobuf_FieldDescriptorProto_set_label(proto, upb_FieldDef_Label(f));
}
if (upb_FieldDef_Type(f) == kUpb_FieldType_Group &&
upb_FileDef_Edition(upb_FieldDef_File(f)) >= UPB_DESC(EDITION_2023)) {
google_protobuf_FieldDescriptorProto_set_type(proto, kUpb_FieldType_Message);
} else {
google_protobuf_FieldDescriptorProto_set_type(proto, upb_FieldDef_Type(f));
}
if (upb_FieldDef_HasJsonName(f)) {
google_protobuf_FieldDescriptorProto_set_json_name(

View File

@ -0,0 +1,8 @@
edition = "2023";
package pkg;
message EditionsMessage {
int32 required_field = 1 [features.field_presence = LEGACY_REQUIRED];
EditionsMessage delimited_field = 2 [features.message_encoding = DELIMITED];
}

View File

@ -7,18 +7,22 @@
#include "upb/util/def_to_proto.h"
#include <cstddef>
#include <memory>
#include <string>
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/descriptor.upb.h"
#include "google/protobuf/descriptor.upbdefs.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "google/protobuf/dynamic_message.h"
#include "google/protobuf/util/message_differencer.h"
#include "upb/base/string_view.h"
#include "upb/mem/arena.hpp"
#include "upb/reflection/def.hpp"
#include "upb/test/parse_text_proto.h"
#include "upb/util/def_to_proto_editions_test.upbdefs.h"
#include "upb/util/def_to_proto_test.h"
#include "upb/util/def_to_proto_test.upbdefs.h"
@ -115,6 +119,29 @@ TEST(DefToProto, Test) {
CheckFile(file, file_desc);
}
// Verifies that editions don't leak out legacy feature APIs (e.g. TYPE_GROUP
// and LABEL_REQUIRED):
// serialized descriptor -> upb def -> serialized descriptor
TEST(DefToProto, TestEditionsLegacyFeatures) {
upb::Arena arena;
upb::DefPool defpool;
upb_StringView test_file_desc =
upb_util_def_to_proto_editions_test_proto_upbdefinit
.descriptor;
const auto* file = google_protobuf_FileDescriptorProto_parse(
test_file_desc.data, test_file_desc.size, arena.ptr());
size_t size;
const auto* messages = google_protobuf_FileDescriptorProto_message_type(file, &size);
ASSERT_EQ(size, 1);
const auto* fields = google_protobuf_DescriptorProto_field(messages[0], &size);
ASSERT_EQ(size, 2);
EXPECT_EQ(google_protobuf_FieldDescriptorProto_label(fields[0]),
google_protobuf_FieldDescriptorProto_LABEL_OPTIONAL);
EXPECT_EQ(google_protobuf_FieldDescriptorProto_type(fields[1]),
google_protobuf_FieldDescriptorProto_TYPE_MESSAGE);
}
// Like the previous test, but uses a message layout built at runtime.
TEST(DefToProto, TestRuntimeReflection) {
upb::Arena arena;