From 384ffc0af85a3a5c421bb78c58d325cd11981dd9 Mon Sep 17 00:00:00 2001 From: Eric Salo Date: Thu, 17 Nov 2022 12:57:40 -0800 Subject: [PATCH] implement reserved names and ranges for messages and enums https://github.com/protocolbuffers/protobuf/issues/10158 PiperOrigin-RevId: 489285657 --- BUILD | 6 ++ upb/reflection/common.h | 2 + upb/reflection/enum_def.c | 59 +++++++++++-- upb/reflection/enum_def.h | 8 ++ upb/reflection/enum_reserved_range.c | 85 +++++++++++++++++++ upb/reflection/enum_reserved_range.h | 51 +++++++++++ upb/reflection/enum_reserved_range_internal.h | 55 ++++++++++++ upb/reflection/extension_range.c | 4 +- upb/reflection/field_def.c | 3 +- upb/reflection/message_def.c | 51 ++++++++++- upb/reflection/message_def.h | 8 ++ upb/reflection/message_reserved_range.c | 80 +++++++++++++++++ upb/reflection/message_reserved_range.h | 51 +++++++++++ .../message_reserved_range_internal.h | 55 ++++++++++++ upb/util/def_to_proto.c | 66 ++++++++++++-- 15 files changed, 566 insertions(+), 18 deletions(-) create mode 100644 upb/reflection/enum_reserved_range.c create mode 100644 upb/reflection/enum_reserved_range.h create mode 100644 upb/reflection/enum_reserved_range_internal.h create mode 100644 upb/reflection/message_reserved_range.c create mode 100644 upb/reflection/message_reserved_range.h create mode 100644 upb/reflection/message_reserved_range_internal.h diff --git a/BUILD b/BUILD index f39c19b560..01300fc0cb 100644 --- a/BUILD +++ b/BUILD @@ -523,12 +523,14 @@ cc_library( "upb/reflection/def_type.c", "upb/reflection/desc_state.c", "upb/reflection/enum_def.c", + "upb/reflection/enum_reserved_range.c", "upb/reflection/enum_value_def.c", "upb/reflection/extension_range.c", "upb/reflection/field_def.c", "upb/reflection/file_def.c", "upb/reflection/message.c", "upb/reflection/message_def.c", + "upb/reflection/message_reserved_range.c", "upb/reflection/method_def.c", "upb/reflection/oneof_def.c", "upb/reflection/service_def.c", @@ -544,6 +546,8 @@ cc_library( "upb/reflection/desc_state_internal.h", "upb/reflection/enum_def.h", "upb/reflection/enum_def_internal.h", + "upb/reflection/enum_reserved_range.h", + "upb/reflection/enum_reserved_range_internal.h", "upb/reflection/enum_value_def.h", "upb/reflection/enum_value_def_internal.h", "upb/reflection/extension_range.h", @@ -556,6 +560,8 @@ cc_library( "upb/reflection/message.hpp", "upb/reflection/message_def.h", "upb/reflection/message_def_internal.h", + "upb/reflection/message_reserved_range.h", + "upb/reflection/message_reserved_range_internal.h", "upb/reflection/method_def.h", "upb/reflection/method_def_internal.h", "upb/reflection/oneof_def.h", diff --git a/upb/reflection/common.h b/upb/reflection/common.h index 04b98a620e..fa74e2cc27 100644 --- a/upb/reflection/common.h +++ b/upb/reflection/common.h @@ -39,11 +39,13 @@ typedef enum { kUpb_Syntax_Proto2 = 2, kUpb_Syntax_Proto3 = 3 } upb_Syntax; // Forward declarations for circular references. typedef struct upb_DefPool upb_DefPool; typedef struct upb_EnumDef upb_EnumDef; +typedef struct upb_EnumReservedRange upb_EnumReservedRange; typedef struct upb_EnumValueDef upb_EnumValueDef; typedef struct upb_ExtensionRange upb_ExtensionRange; typedef struct upb_FieldDef upb_FieldDef; typedef struct upb_FileDef upb_FileDef; typedef struct upb_MessageDef upb_MessageDef; +typedef struct upb_MessageReservedRange upb_MessageReservedRange; typedef struct upb_MethodDef upb_MethodDef; typedef struct upb_OneofDef upb_OneofDef; typedef struct upb_ServiceDef upb_ServiceDef; diff --git a/upb/reflection/enum_def.c b/upb/reflection/enum_def.c index 39419e1d8c..789ab9b8af 100644 --- a/upb/reflection/enum_def.c +++ b/upb/reflection/enum_def.c @@ -32,6 +32,7 @@ #include "upb/reflection/def_type.h" #include "upb/reflection/desc_state_internal.h" #include "upb/reflection/enum_def_internal.h" +#include "upb/reflection/enum_reserved_range_internal.h" #include "upb/reflection/enum_value_def_internal.h" #include "upb/reflection/file_def_internal.h" #include "upb/reflection/message_def_internal.h" @@ -48,7 +49,11 @@ struct upb_EnumDef { upb_strtable ntoi; upb_inttable iton; const upb_EnumValueDef* values; + const upb_EnumReservedRange* res_ranges; + const upb_StringView* res_names; int value_count; + int res_range_count; + int res_name_count; int32_t defaultval; bool is_sorted; // Whether all of the values are defined in ascending order. }; @@ -109,6 +114,25 @@ int32_t upb_EnumDef_Default(const upb_EnumDef* e) { return e->defaultval; } +int upb_EnumDef_ReservedRangeCount(const upb_EnumDef* e) { + return e->res_range_count; +} + +const upb_EnumReservedRange* upb_EnumDef_ReservedRange(const upb_EnumDef* e, + int i) { + UPB_ASSERT(0 <= i && i < e->res_range_count); + return _upb_EnumReservedRange_At(e->res_ranges, i); +} + +int upb_EnumDef_ReservedNameCount(const upb_EnumDef* e) { + return e->res_name_count; +} + +upb_StringView upb_EnumDef_ReservedName(const upb_EnumDef* e, int i) { + UPB_ASSERT(0 <= i && i < e->res_name_count); + return e->res_names[i]; +} + int upb_EnumDef_ValueCount(const upb_EnumDef* e) { return e->value_count; } const upb_EnumValueDef* upb_EnumDef_FindValueByName(const upb_EnumDef* e, @@ -201,12 +225,25 @@ static upb_MiniTableEnum* create_enumlayout(upb_DefBuilder* ctx, return layout; } +static upb_StringView* _upb_EnumReservedNames_New( + upb_DefBuilder* ctx, int n, const upb_StringView* protos) { + upb_StringView* sv = _upb_DefBuilder_Alloc(ctx, sizeof(upb_StringView) * n); + for (size_t i = 0; i < n; i++) { + sv[i].data = + upb_strdup2(protos[i].data, protos[i].size, _upb_DefBuilder_Arena(ctx)); + sv[i].size = protos[i].size; + } + return sv; +} + static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, const google_protobuf_EnumDescriptorProto* enum_proto, upb_EnumDef* e) { const google_protobuf_EnumValueDescriptorProto* const* values; + const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* res_ranges; + const upb_StringView* res_names; upb_StringView name; - size_t n; + size_t n_value, n_res_range, n_res_name; // Must happen before _upb_DefBuilder_Add() e->file = _upb_DefBuilder_File(ctx); @@ -218,23 +255,33 @@ static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, _upb_DefBuilder_Add(ctx, e->full_name, _upb_DefType_Pack(e, UPB_DEFTYPE_ENUM)); - values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n); + values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n_value); - bool ok = upb_strtable_init(&e->ntoi, n, ctx->arena); + bool ok = upb_strtable_init(&e->ntoi, n_value, ctx->arena); if (!ok) _upb_DefBuilder_OomErr(ctx); ok = upb_inttable_init(&e->iton, ctx->arena); if (!ok) _upb_DefBuilder_OomErr(ctx); e->defaultval = 0; - e->value_count = n; - e->values = _upb_EnumValueDefs_New(ctx, prefix, n, values, e, &e->is_sorted); + e->value_count = n_value; + e->values = + _upb_EnumValueDefs_New(ctx, prefix, n_value, values, e, &e->is_sorted); - if (n == 0) { + if (n_value == 0) { _upb_DefBuilder_Errf(ctx, "enums must contain at least one value (%s)", e->full_name); } + res_ranges = + google_protobuf_EnumDescriptorProto_reserved_range(enum_proto, &n_res_range); + e->res_range_count = n_res_range; + e->res_ranges = _upb_EnumReservedRanges_New(ctx, n_res_range, res_ranges, e); + + res_names = google_protobuf_EnumDescriptorProto_reserved_name(enum_proto, &n_res_name); + e->res_name_count = n_res_name; + e->res_names = _upb_EnumReservedNames_New(ctx, n_res_name, res_names); + UPB_DEF_SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); upb_inttable_compact(&e->iton, ctx->arena); diff --git a/upb/reflection/enum_def.h b/upb/reflection/enum_def.h index d8ee28b13c..246e712d1f 100644 --- a/upb/reflection/enum_def.h +++ b/upb/reflection/enum_def.h @@ -60,6 +60,14 @@ bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, upb_Arena* a, const char* upb_EnumDef_Name(const upb_EnumDef* e); const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e); + +upb_StringView upb_EnumDef_ReservedName(const upb_EnumDef* e, int i); +int upb_EnumDef_ReservedNameCount(const upb_EnumDef* e); + +const upb_EnumReservedRange* upb_EnumDef_ReservedRange(const upb_EnumDef* e, + int i); +int upb_EnumDef_ReservedRangeCount(const upb_EnumDef* e); + const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i); int upb_EnumDef_ValueCount(const upb_EnumDef* e); diff --git a/upb/reflection/enum_reserved_range.c b/upb/reflection/enum_reserved_range.c new file mode 100644 index 0000000000..56baea97c6 --- /dev/null +++ b/upb/reflection/enum_reserved_range.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/reflection/def_builder_internal.h" +#include "upb/reflection/enum_def.h" +#include "upb/reflection/enum_reserved_range_internal.h" +// #include "upb/reflection/extension_range_internal.h" +#include "upb/reflection/field_def.h" +// #include "upb/reflection/message_def.h" + +// Must be last. +#include "upb/port/def.inc" + +struct upb_EnumReservedRange { + int32_t start; + int32_t end; +}; + +upb_EnumReservedRange* _upb_EnumReservedRange_At(const upb_EnumReservedRange* r, + int i) { + return (upb_EnumReservedRange*)&r[i]; +} + +int32_t upb_EnumReservedRange_Start(const upb_EnumReservedRange* r) { + return r->start; +} +int32_t upb_EnumReservedRange_End(const upb_EnumReservedRange* r) { + return r->end; +} + +upb_EnumReservedRange* _upb_EnumReservedRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* protos, + const upb_EnumDef* e) { + upb_EnumReservedRange* r = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_EnumReservedRange) * n); + + for (int i = 0; i < n; i++) { + const int32_t start = + google_protobuf_EnumDescriptorProto_EnumReservedRange_start(protos[i]); + const int32_t end = + google_protobuf_EnumDescriptorProto_EnumReservedRange_end(protos[i]); + const int32_t max = kUpb_MaxFieldNumber + 1; + + // A full validation would also check that each range is disjoint, and that + // none of the fields overlap with the extension ranges, but we are just + // sanity checking here. + + // Note: Not a typo! Unlike extension ranges and message reserved ranges, + // the end value of an enum reserved range is *inclusive*! + if (start < 1 || end < start || end > max) { + _upb_DefBuilder_Errf(ctx, "Reserved range (%d, %d) is invalid, enum=%s\n", + (int)start, (int)end, upb_EnumDef_FullName(e)); + } + + r[i].start = start; + r[i].end = end; + } + + return r; +} diff --git a/upb/reflection/enum_reserved_range.h b/upb/reflection/enum_reserved_range.h new file mode 100644 index 0000000000..8627d882ad --- /dev/null +++ b/upb/reflection/enum_reserved_range.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_ENUM_RESERVED_RANGE_H_ +#define UPB_REFLECTION_ENUM_RESERVED_RANGE_H_ + +#include "upb/reflection/common.h" + +// Must be last. +#include "upb/port/def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t upb_EnumReservedRange_Start(const upb_EnumReservedRange* r); +int32_t upb_EnumReservedRange_End(const upb_EnumReservedRange* r); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port/undef.inc" + +#endif /* UPB_REFLECTION_ENUM_RESERVED_RANGE_H_ */ diff --git a/upb/reflection/enum_reserved_range_internal.h b/upb/reflection/enum_reserved_range_internal.h new file mode 100644 index 0000000000..e3aa2ede26 --- /dev/null +++ b/upb/reflection/enum_reserved_range_internal.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UPB_REFLECTION_ENUM_RESERVED_RANGE_INTERNAL_H_ +#define UPB_REFLECTION_ENUM_RESERVED_RANGE_INTERNAL_H_ + +#include "upb/reflection/enum_reserved_range.h" + +// Must be last. +#include "upb/port/def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +upb_EnumReservedRange* _upb_EnumReservedRange_At(const upb_EnumReservedRange* r, + int i); + +// Allocate and initialize an array of |n| reserved ranges owned by |e|. +upb_EnumReservedRange* _upb_EnumReservedRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* protos, + const upb_EnumDef* e); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port/undef.inc" + +#endif /* UPB_REFLECTION_ENUM_RESERVED_RANGE_INTERNAL_H_ */ diff --git a/upb/reflection/extension_range.c b/upb/reflection/extension_range.c index eb098cb8ed..25a4246023 100644 --- a/upb/reflection/extension_range.c +++ b/upb/reflection/extension_range.c @@ -27,8 +27,8 @@ #include "upb/reflection/def_builder_internal.h" #include "upb/reflection/extension_range_internal.h" -#include "upb/reflection/field_def_internal.h" -#include "upb/reflection/message_def_internal.h" +#include "upb/reflection/field_def.h" +#include "upb/reflection/message_def.h" // Must be last. #include "upb/port/def.inc" diff --git a/upb/reflection/field_def.c b/upb/reflection/field_def.c index 5209c0a9ff..7c8e5d0339 100644 --- a/upb/reflection/field_def.c +++ b/upb/reflection/field_def.c @@ -35,7 +35,6 @@ #include "upb/reflection/desc_state_internal.h" #include "upb/reflection/enum_def_internal.h" #include "upb/reflection/enum_value_def_internal.h" -#include "upb/reflection/extension_range_internal.h" #include "upb/reflection/field_def_internal.h" #include "upb/reflection/file_def_internal.h" #include "upb/reflection/message_def_internal.h" @@ -407,7 +406,7 @@ static void parse_default(upb_DefBuilder* ctx, const char* str, size_t len, case kUpb_CType_UInt64: case kUpb_CType_Double: case kUpb_CType_Float: - /* Standard C number parsing functions expect null-terminated strings. */ + // Standard C number parsing functions expect null-terminated strings. if (len >= sizeof(nullz) - 1) { _upb_DefBuilder_Errf(ctx, "Default too long: %.*s", (int)len, str); } diff --git a/upb/reflection/message_def.c b/upb/reflection/message_def.c index aeea121bb5..86f04e1c28 100644 --- a/upb/reflection/message_def.c +++ b/upb/reflection/message_def.c @@ -36,6 +36,7 @@ #include "upb/reflection/field_def_internal.h" #include "upb/reflection/file_def_internal.h" #include "upb/reflection/message_def_internal.h" +#include "upb/reflection/message_reserved_range_internal.h" #include "upb/reflection/oneof_def_internal.h" // Must be last. @@ -58,13 +59,19 @@ struct upb_MessageDef { const upb_FieldDef* fields; const upb_OneofDef* oneofs; const upb_ExtensionRange* ext_ranges; + const upb_StringView* res_names; const upb_MessageDef* nested_msgs; + const upb_MessageReservedRange* res_ranges; const upb_EnumDef* nested_enums; const upb_FieldDef* nested_exts; + + // TODO(salo): These counters don't need anywhere near 32 bits. int field_count; int real_oneof_count; int oneof_count; int ext_range_count; + int res_range_count; + int res_name_count; int nested_msg_count; int nested_enum_count; int nested_ext_count; @@ -231,6 +238,14 @@ int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m) { return m->ext_range_count; } +int upb_MessageDef_ReservedRangeCount(const upb_MessageDef* m) { + return m->res_range_count; +} + +int upb_MessageDef_ReservedNameCount(const upb_MessageDef* m) { + return m->res_name_count; +} + int upb_MessageDef_FieldCount(const upb_MessageDef* m) { return m->field_count; } @@ -261,6 +276,17 @@ const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, return _upb_ExtensionRange_At(m->ext_ranges, i); } +const upb_MessageReservedRange* upb_MessageDef_ReservedRange( + const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->res_range_count); + return _upb_MessageReservedRange_At(m->res_ranges, i); +} + +upb_StringView upb_MessageDef_ReservedName(const upb_MessageDef* m, int i) { + UPB_ASSERT(0 <= i && i < m->res_name_count); + return m->res_names[i]; +} + const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i) { UPB_ASSERT(0 <= i && i < m->field_count); return _upb_FieldDef_At(m->fields, i); @@ -546,6 +572,17 @@ bool upb_MessageDef_MiniDescriptorEncode(const upb_MessageDef* m, upb_Arena* a, return true; } +static upb_StringView* _upb_ReservedNames_New(upb_DefBuilder* ctx, int n, + const upb_StringView* protos) { + upb_StringView* sv = _upb_DefBuilder_Alloc(ctx, sizeof(upb_StringView) * n); + for (size_t i = 0; i < n; i++) { + sv[i].data = + upb_strdup2(protos[i].data, protos[i].size, _upb_DefBuilder_Arena(ctx)); + sv[i].size = protos[i].size; + } + return sv; +} + static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, const google_protobuf_DescriptorProto* msg_proto, const upb_MessageDef* containing_type, @@ -553,7 +590,10 @@ static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, const google_protobuf_OneofDescriptorProto* const* oneofs; const google_protobuf_FieldDescriptorProto* const* fields; const google_protobuf_DescriptorProto_ExtensionRange* const* ext_ranges; - size_t n_oneof, n_field, n_ext_range, n_enum, n_ext, n_msg; + const google_protobuf_DescriptorProto_ReservedRange* const* res_ranges; + const upb_StringView* res_names; + size_t n_oneof, n_field, n_enum, n_ext, n_msg; + size_t n_ext_range, n_res_range, n_res_name; upb_StringView name; // Must happen before _upb_DefBuilder_Add() @@ -571,6 +611,8 @@ static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, oneofs = google_protobuf_DescriptorProto_oneof_decl(msg_proto, &n_oneof); fields = google_protobuf_DescriptorProto_field(msg_proto, &n_field); ext_ranges = google_protobuf_DescriptorProto_extension_range(msg_proto, &n_ext_range); + res_ranges = google_protobuf_DescriptorProto_reserved_range(msg_proto, &n_res_range); + res_names = google_protobuf_DescriptorProto_reserved_name(msg_proto, &n_res_name); bool ok = upb_inttable_init(&m->itof, ctx->arena); if (!ok) _upb_DefBuilder_OomErr(ctx); @@ -608,6 +650,13 @@ static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, m->ext_range_count = n_ext_range; m->ext_ranges = _upb_ExtensionRanges_New(ctx, n_ext_range, ext_ranges, m); + m->res_range_count = n_res_range; + m->res_ranges = + _upb_MessageReservedRanges_New(ctx, n_res_range, res_ranges, m); + + m->res_name_count = n_res_name; + m->res_names = _upb_ReservedNames_New(ctx, n_res_name, res_names); + const size_t synthetic_count = _upb_OneofDefs_Finalize(ctx, m); m->real_oneof_count = m->oneof_count - synthetic_count; diff --git a/upb/reflection/message_def.h b/upb/reflection/message_def.h index 3be3491813..5122331628 100644 --- a/upb/reflection/message_def.h +++ b/upb/reflection/message_def.h @@ -152,6 +152,14 @@ const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i); int upb_MessageDef_OneofCount(const upb_MessageDef* m); const google_protobuf_MessageOptions* upb_MessageDef_Options(const upb_MessageDef* m); + +upb_StringView upb_MessageDef_ReservedName(const upb_MessageDef* m, int i); +int upb_MessageDef_ReservedNameCount(const upb_MessageDef* m); + +const upb_MessageReservedRange* upb_MessageDef_ReservedRange( + const upb_MessageDef* m, int i); +int upb_MessageDef_ReservedRangeCount(const upb_MessageDef* m); + upb_Syntax upb_MessageDef_Syntax(const upb_MessageDef* m); upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m); diff --git a/upb/reflection/message_reserved_range.c b/upb/reflection/message_reserved_range.c new file mode 100644 index 0000000000..caf80dbc87 --- /dev/null +++ b/upb/reflection/message_reserved_range.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "upb/reflection/def_builder_internal.h" +#include "upb/reflection/enum_def.h" +#include "upb/reflection/extension_range_internal.h" +#include "upb/reflection/field_def.h" +#include "upb/reflection/message_def.h" + +// Must be last. +#include "upb/port/def.inc" + +struct upb_MessageReservedRange { + int32_t start; + int32_t end; +}; + +upb_MessageReservedRange* _upb_MessageReservedRange_At( + const upb_MessageReservedRange* r, int i) { + return (upb_MessageReservedRange*)&r[i]; +} + +int32_t upb_MessageReservedRange_Start(const upb_MessageReservedRange* r) { + return r->start; +} +int32_t upb_MessageReservedRange_End(const upb_MessageReservedRange* r) { + return r->end; +} + +upb_MessageReservedRange* _upb_MessageReservedRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_DescriptorProto_ReservedRange* const* protos, + const upb_MessageDef* m) { + upb_MessageReservedRange* r = + _upb_DefBuilder_Alloc(ctx, sizeof(upb_MessageReservedRange) * n); + + for (int i = 0; i < n; i++) { + const int32_t start = google_protobuf_DescriptorProto_ReservedRange_start(protos[i]); + const int32_t end = google_protobuf_DescriptorProto_ReservedRange_end(protos[i]); + const int32_t max = kUpb_MaxFieldNumber + 1; + + // A full validation would also check that each range is disjoint, and that + // none of the fields overlap with the extension ranges, but we are just + // sanity checking here. + if (start < 1 || end <= start || end > max) { + _upb_DefBuilder_Errf(ctx, + "Reserved range (%d, %d) is invalid, message=%s\n", + (int)start, (int)end, upb_MessageDef_FullName(m)); + } + + r[i].start = start; + r[i].end = end; + } + + return r; +} diff --git a/upb/reflection/message_reserved_range.h b/upb/reflection/message_reserved_range.h new file mode 100644 index 0000000000..a24815a29b --- /dev/null +++ b/upb/reflection/message_reserved_range.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// IWYU pragma: private, include "third_party/upb/upb/reflection/def.h" + +#ifndef UPB_REFLECTION_MESSAGE_RESERVED_RANGE_H_ +#define UPB_REFLECTION_MESSAGE_RESERVED_RANGE_H_ + +#include "upb/reflection/common.h" + +// Must be last. +#include "upb/port/def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +int32_t upb_MessageReservedRange_Start(const upb_MessageReservedRange* r); +int32_t upb_MessageReservedRange_End(const upb_MessageReservedRange* r); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port/undef.inc" + +#endif /* UPB_REFLECTION_MESSAGE_RESERVED_RANGE_H_ */ diff --git a/upb/reflection/message_reserved_range_internal.h b/upb/reflection/message_reserved_range_internal.h new file mode 100644 index 0000000000..03e8a8ad76 --- /dev/null +++ b/upb/reflection/message_reserved_range_internal.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2009-2021, Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Google LLC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UPB_REFLECTION_MESSAGE_RESERVED_RANGE_INTERNAL_H_ +#define UPB_REFLECTION_MESSAGE_RESERVED_RANGE_INTERNAL_H_ + +#include "upb/reflection/message_reserved_range.h" + +// Must be last. +#include "upb/port/def.inc" + +#ifdef __cplusplus +extern "C" { +#endif + +upb_MessageReservedRange* _upb_MessageReservedRange_At( + const upb_MessageReservedRange* r, int i); + +// Allocate and initialize an array of |n| reserved ranges owned by |m|. +upb_MessageReservedRange* _upb_MessageReservedRanges_New( + upb_DefBuilder* ctx, int n, + const google_protobuf_DescriptorProto_ReservedRange* const* protos, + const upb_MessageDef* m); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#include "upb/port/undef.inc" + +#endif /* UPB_REFLECTION_MESSAGE_RESERVED_RANGE_INTERNAL_H_ */ diff --git a/upb/util/def_to_proto.c b/upb/util/def_to_proto.c index b994577e05..78030bd676 100644 --- a/upb/util/def_to_proto.c +++ b/upb/util/def_to_proto.c @@ -31,9 +31,12 @@ #include #include "upb/port/vsnprintf_compat.h" +#include "upb/reflection/enum_reserved_range.h" +#include "upb/reflection/extension_range.h" #include "upb/reflection/field_def_internal.h" #include "upb/reflection/file_def_internal.h" #include "upb/reflection/message.h" +#include "upb/reflection/message_reserved_range.h" // Must be last. #include "upb/port/def.inc" @@ -169,6 +172,34 @@ static upb_StringView default_string(upb_ToProto_Context* ctx, } } +static google_protobuf_DescriptorProto_ReservedRange* resrange_toproto( + upb_ToProto_Context* ctx, const upb_MessageReservedRange* r) { + google_protobuf_DescriptorProto_ReservedRange* proto = + google_protobuf_DescriptorProto_ReservedRange_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_DescriptorProto_ReservedRange_set_start( + proto, upb_MessageReservedRange_Start(r)); + google_protobuf_DescriptorProto_ReservedRange_set_end(proto, + upb_MessageReservedRange_End(r)); + + return proto; +} + +static google_protobuf_EnumDescriptorProto_EnumReservedRange* enumresrange_toproto( + upb_ToProto_Context* ctx, const upb_EnumReservedRange* r) { + google_protobuf_EnumDescriptorProto_EnumReservedRange* proto = + google_protobuf_EnumDescriptorProto_EnumReservedRange_new(ctx->arena); + CHK_OOM(proto); + + google_protobuf_EnumDescriptorProto_EnumReservedRange_set_start( + proto, upb_EnumReservedRange_Start(r)); + google_protobuf_EnumDescriptorProto_EnumReservedRange_set_end( + proto, upb_EnumReservedRange_End(r)); + + return proto; +} + static google_protobuf_FieldDescriptorProto* fielddef_toproto( upb_ToProto_Context* ctx, const upb_FieldDef* f) { google_protobuf_FieldDescriptorProto* proto = @@ -270,9 +301,7 @@ static google_protobuf_EnumDescriptorProto* enumdef_toproto( google_protobuf_EnumDescriptorProto_set_name( proto, strviewdup(ctx, upb_EnumDef_Name(e))); - int n; - - n = upb_EnumDef_ValueCount(e); + int n = upb_EnumDef_ValueCount(e); google_protobuf_EnumValueDescriptorProto** vals = google_protobuf_EnumDescriptorProto_resize_value(proto, n, ctx->arena); CHK_OOM(vals); @@ -280,7 +309,19 @@ static google_protobuf_EnumDescriptorProto* enumdef_toproto( vals[i] = enumvaldef_toproto(ctx, upb_EnumDef_Value(e, i)); } - // TODO: reserved range, reserved name + n = upb_EnumDef_ReservedRangeCount(e); + google_protobuf_EnumDescriptorProto_EnumReservedRange** res_ranges = + google_protobuf_EnumDescriptorProto_resize_reserved_range(proto, n, ctx->arena); + for (int i = 0; i < n; i++) { + res_ranges[i] = enumresrange_toproto(ctx, upb_EnumDef_ReservedRange(e, i)); + } + + n = upb_EnumDef_ReservedNameCount(e); + upb_StringView* res_names = + google_protobuf_EnumDescriptorProto_resize_reserved_name(proto, n, ctx->arena); + for (int i = 0; i < n; i++) { + res_names[i] = upb_EnumDef_ReservedName(e, i); + } if (upb_EnumDef_HasOptions(e)) { SET_OPTIONS(proto, EnumDescriptorProto, EnumOptions, @@ -359,13 +400,24 @@ static google_protobuf_DescriptorProto* msgdef_toproto( n = upb_MessageDef_ExtensionRangeCount(m); google_protobuf_DescriptorProto_ExtensionRange** ext_ranges = - google_protobuf_DescriptorProto_resize_extension_range(proto, n, - ctx->arena); + google_protobuf_DescriptorProto_resize_extension_range(proto, n, ctx->arena); for (int i = 0; i < n; i++) { ext_ranges[i] = extrange_toproto(ctx, upb_MessageDef_ExtensionRange(m, i)); } - // TODO: reserved ranges and reserved names + n = upb_MessageDef_ReservedRangeCount(m); + google_protobuf_DescriptorProto_ReservedRange** res_ranges = + google_protobuf_DescriptorProto_resize_reserved_range(proto, n, ctx->arena); + for (int i = 0; i < n; i++) { + res_ranges[i] = resrange_toproto(ctx, upb_MessageDef_ReservedRange(m, i)); + } + + n = upb_MessageDef_ReservedNameCount(m); + upb_StringView* res_names = + google_protobuf_DescriptorProto_resize_reserved_name(proto, n, ctx->arena); + for (int i = 0; i < n; i++) { + res_names[i] = upb_MessageDef_ReservedName(m, i); + } if (upb_MessageDef_HasOptions(m)) { SET_OPTIONS(proto, DescriptorProto, MessageOptions,