diff --git a/php/ext/google/protobuf/message.c b/php/ext/google/protobuf/message.c index 58511c2637..f38b326c0d 100644 --- a/php/ext/google/protobuf/message.c +++ b/php/ext/google/protobuf/message.c @@ -913,7 +913,7 @@ PHP_METHOD(Message, whichOneof) { return; } - field = upb_Message_WhichOneof(intern->msg, oneof); + field = upb_Message_WhichOneofByDef(intern->msg, oneof); RETURN_STRING(field ? upb_FieldDef_Name(field) : ""); } diff --git a/php/ext/google/protobuf/wkt.inc b/php/ext/google/protobuf/wkt.inc index 4579c7e30d..799a48fd46 100644 --- a/php/ext/google/protobuf/wkt.inc +++ b/php/ext/google/protobuf/wkt.inc @@ -1350,7 +1350,7 @@ static PHP_METHOD(google_protobuf_Value, getKind) { const upb_OneofDef *oneof = upb_MessageDef_FindOneofByName( intern->desc->msgdef, "kind"); const upb_FieldDef *field = - upb_Message_WhichOneof(intern->msg, oneof); + upb_Message_WhichOneofByDef(intern->msg, oneof); RETURN_STRING(field ? upb_FieldDef_Name(field) : ""); } static zend_function_entry google_protobuf_Value_phpmethods[] = { diff --git a/python/message.c b/python/message.c index d5213ab1af..42bf90236d 100644 --- a/python/message.c +++ b/python/message.c @@ -1039,9 +1039,9 @@ static PyObject* PyUpb_Message_HasField(PyObject* _self, PyObject* arg) { if (PyUpb_Message_IsStub(self)) Py_RETURN_FALSE; - return PyBool_FromLong(field ? upb_Message_HasFieldByDef(self->ptr.msg, field) - : upb_Message_WhichOneof(self->ptr.msg, oneof) != - NULL); + return PyBool_FromLong( + field ? upb_Message_HasFieldByDef(self->ptr.msg, field) + : upb_Message_WhichOneofByDef(self->ptr.msg, oneof) != NULL); } static PyObject* PyUpb_Message_Contains(PyObject* _self, PyObject* arg) { @@ -1421,7 +1421,7 @@ static PyObject* PyUpb_Message_ClearField(PyObject* _self, PyObject* arg) { return NULL; } - if (o) f = upb_Message_WhichOneof(self->ptr.msg, o); + if (o) f = upb_Message_WhichOneofByDef(self->ptr.msg, o); if (f) PyUpb_Message_DoClearField(_self, f); Py_RETURN_NONE; } @@ -1616,7 +1616,7 @@ static PyObject* PyUpb_Message_WhichOneof(PyObject* _self, PyObject* name) { } upb_Message* msg = PyUpb_Message_GetIfReified(_self); if (!msg) Py_RETURN_NONE; - const upb_FieldDef* f = upb_Message_WhichOneof(msg, o); + const upb_FieldDef* f = upb_Message_WhichOneofByDef(msg, o); if (!f) Py_RETURN_NONE; return PyUnicode_FromString(upb_FieldDef_Name(f)); } diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c index 706e3df5fe..acd900ffb7 100644 --- a/ruby/ext/google/protobuf_c/message.c +++ b/ruby/ext/google/protobuf_c/message.c @@ -248,7 +248,7 @@ static int extract_method_call(VALUE method_name, Message* self, static VALUE Message_oneof_accessor(VALUE _self, const upb_OneofDef* o, int accessor_type) { Message* self = ruby_to_Message(_self); - const upb_FieldDef* oneof_field = upb_Message_WhichOneof(self->msg, o); + const upb_FieldDef* oneof_field = upb_Message_WhichOneofByDef(self->msg, o); switch (accessor_type) { case METHOD_PRESENCE: diff --git a/ruby/lib/google/protobuf/ffi/message.rb b/ruby/lib/google/protobuf/ffi/message.rb index a3dc2d189b..40e33a313a 100644 --- a/ruby/lib/google/protobuf/ffi/message.rb +++ b/ruby/lib/google/protobuf/ffi/message.rb @@ -21,7 +21,7 @@ module Google attach_function :json_encode_message, :upb_JsonEncode, [:Message, Descriptor, :DefPool, :int, :binary_string, :size_t, Status.by_ref], :size_t attach_function :decode_message, :upb_Decode, [:binary_string, :size_t, :Message, MiniTable.by_ref, :ExtensionRegistry, :int, Internal::Arena], DecodeStatus attach_function :get_mutable_message, :upb_Message_Mutable, [:Message, FieldDescriptor, Internal::Arena], MutableMessageValue.by_value - attach_function :get_message_which_oneof, :upb_Message_WhichOneof, [:Message, OneofDescriptor], FieldDescriptor + attach_function :get_message_which_oneof, :upb_Message_WhichOneofByDef, [:Message, OneofDescriptor], FieldDescriptor attach_function :message_discard_unknown, :upb_Message_DiscardUnknown, [:Message, Descriptor, :int], :bool attach_function :message_next, :upb_Message_Next, [:Message, Descriptor, :DefPool, :FieldDefPointer, MessageValue.by_ref, :pointer], :bool # MessageValue diff --git a/src/google/protobuf/compiler/php/php_generator.cc b/src/google/protobuf/compiler/php/php_generator.cc index 39944b59ed..006d6debd5 100644 --- a/src/google/protobuf/compiler/php/php_generator.cc +++ b/src/google/protobuf/compiler/php/php_generator.cc @@ -1758,7 +1758,7 @@ void GenerateCMessage(const Descriptor* message, io::Printer* printer) { " const upb_OneofDef *oneof = upb_MessageDef_FindOneofByName(\n" " intern->desc->msgdef, \"$name$\");\n" " const upb_FieldDef *field = \n" - " upb_Message_WhichOneof(intern->msg, oneof);\n" + " upb_Message_WhichOneofByDef(intern->msg, oneof);\n" " RETURN_STRING(field ? upb_FieldDef_Name(field) : \"\");\n" "}\n", "c_name", c_name, "name", oneof->name(), "camel_name", diff --git a/upb/json/decode.c b/upb/json/decode.c index c578451836..8fe655ccfd 100644 --- a/upb/json/decode.c +++ b/upb/json/decode.c @@ -957,7 +957,7 @@ static void jsondec_field(jsondec* d, upb_Message* msg, } if (upb_FieldDef_RealContainingOneof(f) && - upb_Message_WhichOneof(msg, upb_FieldDef_ContainingOneof(f))) { + upb_Message_WhichOneofByDef(msg, upb_FieldDef_ContainingOneof(f))) { jsondec_err(d, "More than one field for this oneof."); } diff --git a/upb/message/accessors.h b/upb/message/accessors.h index 9e9b54b127..922026ee48 100644 --- a/upb/message/accessors.h +++ b/upb/message/accessors.h @@ -247,6 +247,12 @@ UPB_API_INLINE void* upb_Message_ResizeArrayUninitialized( UPB_API_INLINE uint32_t upb_Message_WhichOneofFieldNumber( const upb_Message* message, const upb_MiniTableField* oneof_field); +// For a field `f` which is in a oneof, return the field of that +// oneof that is actually set (or NULL if none). +UPB_API_INLINE const upb_MiniTableField* upb_Message_WhichOneof( + const upb_Message* msg, const upb_MiniTable* m, + const upb_MiniTableField* f); + // Updates a map entry given an entry message. bool upb_Message_SetMapEntry(upb_Map* map, const upb_MiniTable* mini_table, const upb_MiniTableField* field, diff --git a/upb/message/accessors_test.cc b/upb/message/accessors_test.cc index 76248578b3..014056e9fd 100644 --- a/upb/message/accessors_test.cc +++ b/upb/message/accessors_test.cc @@ -500,4 +500,32 @@ TEST(GeneratedCode, OneofClear) { upb_Arena_Free(arena); } +TEST(GeneratedCode, OneofAccess) { + upb_Arena* arena = upb_Arena_New(); + + protobuf_test_messages_proto2_TestAllTypesProto2* msg = + protobuf_test_messages_proto2_TestAllTypesProto2_new(arena); + + const upb_MiniTable* table = + &protobuf_0test_0messages__proto2__TestAllTypesProto2_msg_init; + + // oneof_uint32 + const upb_MiniTableField* oneofField = + upb_MiniTable_FindFieldByNumber(table, 111); + EXPECT_TRUE(upb_MiniTableField_IsInOneof(oneofField)); + + const upb_MiniTableField* oneOfFirstFetch = + upb_Message_WhichOneof((upb_Message*)msg, table, oneofField); + // one of not set, so should initially yield nullptr + EXPECT_EQ(oneOfFirstFetch, nullptr); + + protobuf_test_messages_proto2_TestAllTypesProto2_set_oneof_uint32(msg, 522); + const upb_MiniTableField* oneOfSecondFetch = + upb_Message_WhichOneof((upb_Message*)msg, table, oneofField); + // this oneof has now been set, so should yield the MiniTableField + EXPECT_EQ(oneOfSecondFetch, oneofField); + + upb_Arena_Free(arena); +} + } // namespace diff --git a/upb/message/internal/accessors.h b/upb/message/internal/accessors.h index d28e2ebfaf..5bbfb1e0bc 100644 --- a/upb/message/internal/accessors.h +++ b/upb/message/internal/accessors.h @@ -122,6 +122,17 @@ UPB_API_INLINE uint32_t upb_Message_WhichOneofFieldNumber( return UPB_PRIVATE(_upb_Message_GetOneofCase)(message, oneof_field); } +UPB_API_INLINE const upb_MiniTableField* upb_Message_WhichOneof( + const struct upb_Message* msg, const upb_MiniTable* m, + const upb_MiniTableField* f) { + uint32_t field_number = upb_Message_WhichOneofFieldNumber(msg, f); + if (field_number == 0) { + // No field in the oneof is set. + return NULL; + } + return upb_MiniTable_FindFieldByNumber(m, field_number); +} + // LINT.ThenChange(GoogleInternalName2) // Returns false if the message is missing any of its required fields. diff --git a/upb/reflection/message.c b/upb/reflection/message.c index 9211738c33..285418295a 100644 --- a/upb/reflection/message.c +++ b/upb/reflection/message.c @@ -41,8 +41,8 @@ bool upb_Message_HasFieldByDef(const upb_Message* msg, const upb_FieldDef* f) { } } -const upb_FieldDef* upb_Message_WhichOneof(const upb_Message* msg, - const upb_OneofDef* o) { +const upb_FieldDef* upb_Message_WhichOneofByDef(const upb_Message* msg, + const upb_OneofDef* o) { const upb_FieldDef* f = upb_OneofDef_Field(o, 0); if (upb_OneofDef_IsSynthetic(o)) { UPB_ASSERT(upb_OneofDef_FieldCount(o) == 1); diff --git a/upb/reflection/message.h b/upb/reflection/message.h index b3b52d7ace..fbe34f4d04 100644 --- a/upb/reflection/message.h +++ b/upb/reflection/message.h @@ -30,8 +30,8 @@ UPB_API upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg, upb_Arena* a); // Returns the field that is set in the oneof, or NULL if none are set. -UPB_API const upb_FieldDef* upb_Message_WhichOneof(const upb_Message* msg, - const upb_OneofDef* o); +UPB_API const upb_FieldDef* upb_Message_WhichOneofByDef(const upb_Message* msg, + const upb_OneofDef* o); // Clear all data and unknown fields. void upb_Message_ClearByDef(upb_Message* msg, const upb_MessageDef* m);