From 11e8075e5111dea799d5c896ce87a1d4ad236d0c Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Tue, 6 Feb 2024 13:34:17 +0000 Subject: [PATCH 1/4] giunioninfo: Split success and return value for get_discriminator_offset() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise there’s no obvious suitable return value to return when the union is *not* discriminated. This is an API break, but libgirepository has not been in a stable release yet, so that’s fine. Signed-off-by: Philip Withnall Helps: #3155 --- docs/reference/girepository/migrating-gi.md | 1 + girepository/girwriter.c | 2 +- girepository/giunioninfo.c | 21 ++++++++++++++++----- girepository/giunioninfo.h | 3 ++- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/docs/reference/girepository/migrating-gi.md b/docs/reference/girepository/migrating-gi.md index cca213fd7..4a285708f 100644 --- a/docs/reference/girepository/migrating-gi.md +++ b/docs/reference/girepository/migrating-gi.md @@ -72,5 +72,6 @@ your code if integer type warnings are enabled. | `g_type_info_get_array_length` | [method@GIRepository.TypeInfo.get_array_length_index] | | `g_typelib_new_from_*` | All replaced with `gi_typelib_new_from_bytes()` | | `GI_FUNCTION_THROWS` and `GI_VFUNC_THROWS` | [method@GIRepository.CallableInfo.can_throw_gerror] | +| `g_union_info_get_discriminator_offset` | Split success and failure return values out into a new out-argument and return value | | `g_union_info_get_copy_function` | [method@GIRepository.UnionInfo.get_copy_function_name] | | `g_union_info_get_free_function` | [method@GIRepository.UnionInfo.get_free_function_name] | diff --git a/girepository/girwriter.c b/girepository/girwriter.c index cb4a7a1e0..a2ba83dc2 100644 --- a/girepository/girwriter.c +++ b/girepository/girwriter.c @@ -1283,7 +1283,7 @@ write_union_info (const char *ns, size_t offset; GITypeInfo *type; - offset = gi_union_info_get_discriminator_offset (info); + gi_union_info_get_discriminator_offset (info, &offset); type = gi_union_info_get_discriminator_type (info); xml_start_element (file, "discriminator"); diff --git a/girepository/giunioninfo.c b/girepository/giunioninfo.c index d64ec2c01..11a17b775 100644 --- a/girepository/giunioninfo.c +++ b/girepository/giunioninfo.c @@ -151,19 +151,30 @@ gi_union_info_is_discriminated (GIUnionInfo *info) /** * gi_union_info_get_discriminator_offset: * @info: a #GIUnionInfo + * @out_offset: (out) (optional): return location for the offset, in bytes, of + * the discriminator * - * Returns the offset of the discriminator field in the structure. + * Obtain the offset of the discriminator field within the structure. * - * Returns: offset, in bytes, of the discriminator + * The union must be discriminated, or `FALSE` will be returned. + * + * Returns: `TRUE` if the union is discriminated * Since: 2.80 */ -size_t -gi_union_info_get_discriminator_offset (GIUnionInfo *info) +gboolean +gi_union_info_get_discriminator_offset (GIUnionInfo *info, + size_t *out_offset) { GIRealInfo *rinfo = (GIRealInfo *)info; UnionBlob *blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset]; + size_t discriminator_offset; - return blob->discriminator_offset; + discriminator_offset = (blob->discriminated) ? blob->discriminator_offset : 0; + + if (out_offset != NULL) + *out_offset = discriminator_offset; + + return blob->discriminated; } /** diff --git a/girepository/giunioninfo.h b/girepository/giunioninfo.h index 6826c7b1f..d2273621f 100644 --- a/girepository/giunioninfo.h +++ b/girepository/giunioninfo.h @@ -76,7 +76,8 @@ GI_AVAILABLE_IN_ALL gboolean gi_union_info_is_discriminated (GIUnionInfo *info); GI_AVAILABLE_IN_ALL -size_t gi_union_info_get_discriminator_offset (GIUnionInfo *info); +gboolean gi_union_info_get_discriminator_offset (GIUnionInfo *info, + size_t *out_offset); GI_AVAILABLE_IN_ALL GITypeInfo * gi_union_info_get_discriminator_type (GIUnionInfo *info); From e286497c1fbf7caa29952793cf77cf8bedf10e0d Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Tue, 6 Feb 2024 13:35:23 +0000 Subject: [PATCH 2/4] giunioninfo: Mark get_discriminator_type() as nullable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It may (and should) return `NULL` if called on a union which isn’t discriminated. Signed-off-by: Philip Withnall Helps: #3155 --- girepository/giunioninfo.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/girepository/giunioninfo.c b/girepository/giunioninfo.c index 11a17b775..3091937ce 100644 --- a/girepository/giunioninfo.c +++ b/girepository/giunioninfo.c @@ -183,7 +183,8 @@ gi_union_info_get_discriminator_offset (GIUnionInfo *info, * * Obtain the type information of the union discriminator. * - * Returns: (transfer full): the [type@GIRepository.TypeInfo], free it with + * Returns: (transfer full) (nullable): the [type@GIRepository.TypeInfo], or + * `NULL` if the union is not discriminated. Free it with * [method@GIRepository.BaseInfo.unref] when done. * Since: 2.80 */ @@ -191,6 +192,10 @@ GITypeInfo * gi_union_info_get_discriminator_type (GIUnionInfo *info) { GIRealInfo *rinfo = (GIRealInfo *)info; + UnionBlob *blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (!blob->discriminated) + return NULL; return gi_type_info_new ((GIBaseInfo*)info, rinfo->typelib, rinfo->offset + 24); } From c8946b8a9283345bcdce10c1f5486fb58dd0b606 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Tue, 6 Feb 2024 13:40:20 +0000 Subject: [PATCH 3/4] gitypes: Fix integer values of GIInfoType This effectively reverts commit 0910e2f6ad. I thought that `GIInfoType` was decoupled from `GITypelibBlobType`, but it turns out that `girepository.c` calls `gi_info_new_full()` with blob types, implicitly converting them to info types. This was causing anything with a type higher than the `INVALID_0` value to be loaded as the wrong type. Signed-off-by: Philip Withnall Helps: #3155 --- girepository/gitypelib-internal.h | 1 + girepository/gitypes.h | 25 ++++++++++++++----------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/girepository/gitypelib-internal.h b/girepository/gitypelib-internal.h index 2639c0e1f..e47c74d0d 100644 --- a/girepository/gitypelib-internal.h +++ b/girepository/gitypelib-internal.h @@ -179,6 +179,7 @@ Changes since 0.1: * Since: 2.80 */ typedef enum { + /* The values here must be kept in sync with GIInfoType */ BLOB_TYPE_INVALID, BLOB_TYPE_FUNCTION, BLOB_TYPE_CALLBACK, diff --git a/girepository/gitypes.h b/girepository/gitypes.h index 12a8048bd..a2f925152 100644 --- a/girepository/gitypes.h +++ b/girepository/gitypes.h @@ -241,6 +241,7 @@ typedef union _GIArgument GIArgument; */ typedef enum { + /* The values here must be kept in sync with GITypelibBlobType */ GI_INFO_TYPE_INVALID, GI_INFO_TYPE_FUNCTION, GI_INFO_TYPE_CALLBACK, @@ -251,17 +252,19 @@ typedef enum GI_INFO_TYPE_OBJECT, GI_INFO_TYPE_INTERFACE, GI_INFO_TYPE_CONSTANT, - GI_INFO_TYPE_UNION, /* 10 */ - GI_INFO_TYPE_VALUE, - GI_INFO_TYPE_SIGNAL, - GI_INFO_TYPE_VFUNC, - GI_INFO_TYPE_PROPERTY, - GI_INFO_TYPE_FIELD, /* 15 */ - GI_INFO_TYPE_ARG, - GI_INFO_TYPE_TYPE, - GI_INFO_TYPE_UNRESOLVED, - GI_INFO_TYPE_CALLABLE, - GI_INFO_TYPE_REGISTERED_TYPE, /* 20 */ + /* 10 is skipped, it used to be used, but was removed before girepository-2.0 + * It is, however, part of the binary format in GITypelibBlobType */ + GI_INFO_TYPE_UNION = 11, + GI_INFO_TYPE_VALUE = 12, + GI_INFO_TYPE_SIGNAL = 13, + GI_INFO_TYPE_VFUNC = 14, + GI_INFO_TYPE_PROPERTY = 15, + GI_INFO_TYPE_FIELD = 16, + GI_INFO_TYPE_ARG = 17, + GI_INFO_TYPE_TYPE = 18, + GI_INFO_TYPE_UNRESOLVED = 19, + GI_INFO_TYPE_CALLABLE = 20, + GI_INFO_TYPE_REGISTERED_TYPE = 21, /* keep GI_INFO_TYPE_N_TYPES in sync with this */ } GIInfoType; From 44e3ebccd1f12cd0375d302b909f6202ae92051c Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Tue, 6 Feb 2024 13:42:43 +0000 Subject: [PATCH 4/4] tests: Add basic tests for GIUnionInfo These would have caught the regression fixed in the previous commit. Signed-off-by: Philip Withnall Helps: #3155 --- girepository/tests/meson.build | 3 + girepository/tests/union-info.c | 100 ++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 girepository/tests/union-info.c diff --git a/girepository/tests/meson.build b/girepository/tests/meson.build index 3af29bd36..a4a8dc740 100644 --- a/girepository/tests/meson.build +++ b/girepository/tests/meson.build @@ -30,6 +30,9 @@ if enable_gir 'throws' : { 'depends': [glib_gir, gio_gir], }, + 'union-info' : { + 'depends': [glib_gir], + }, } endif diff --git a/girepository/tests/union-info.c b/girepository/tests/union-info.c new file mode 100644 index 000000000..7eca2b664 --- /dev/null +++ b/girepository/tests/union-info.c @@ -0,0 +1,100 @@ +/* + * Copyright 2024 GNOME Foundation + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + */ + +#include "config.h" + +#include "girepository.h" +#include "test-common.h" + +static void +test_basic (RepositoryFixture *fx, + const void *unused) +{ + GIUnionInfo *double_info = NULL; + GIFieldInfo *field_info = NULL; + size_t offset = 123; + + g_test_summary ("Test basic properties of GIUnionInfo"); + + double_info = GI_UNION_INFO (gi_repository_find_by_name (fx->repository, "GLib", "DoubleIEEE754")); + g_assert_nonnull (double_info); + + g_assert_cmpuint (gi_union_info_get_n_fields (double_info), ==, 1); + + field_info = gi_union_info_get_field (double_info, 0); + g_assert_true (GI_IS_FIELD_INFO (field_info)); + g_assert_cmpstr (gi_base_info_get_name (GI_BASE_INFO (field_info)), ==, "v_double"); + g_clear_pointer (&field_info, gi_base_info_unref); + + g_assert_cmpuint (gi_union_info_get_n_methods (double_info), ==, 0); + g_assert_null (gi_union_info_find_method (double_info, "not_exist")); + + g_assert_false (gi_union_info_is_discriminated (double_info)); + g_assert_false (gi_union_info_get_discriminator_offset (double_info, &offset)); + g_assert_cmpuint (offset, ==, 0); + g_assert_null (gi_union_info_get_discriminator_type (double_info)); + g_assert_null (gi_union_info_get_discriminator (double_info, 0)); + + g_assert_cmpuint (gi_union_info_get_size (double_info), ==, 8); + g_assert_cmpuint (gi_union_info_get_alignment (double_info), ==, 8); + + g_assert_null (gi_union_info_get_copy_function_name (double_info)); + g_assert_null (gi_union_info_get_free_function_name (double_info)); + + g_clear_pointer (&double_info, gi_base_info_unref); +} + +static void +test_methods (RepositoryFixture *fx, + const void *unused) +{ + GIUnionInfo *mutex_info = NULL; + GIFunctionInfo *method_info = NULL; + + g_test_summary ("Test retrieving methods from GIUnionInfo"); + + mutex_info = GI_UNION_INFO (gi_repository_find_by_name (fx->repository, "GLib", "Mutex")); + g_assert_nonnull (mutex_info); + + g_assert_cmpuint (gi_union_info_get_n_methods (mutex_info), ==, 5); + + method_info = gi_union_info_get_method (mutex_info, 0); + g_assert_true (GI_IS_FUNCTION_INFO (method_info)); + g_assert_cmpstr (gi_base_info_get_name (GI_BASE_INFO (method_info)), ==, "clear"); + g_clear_pointer (&method_info, gi_base_info_unref); + + method_info = gi_union_info_find_method (mutex_info, "trylock"); + g_assert_true (GI_IS_FUNCTION_INFO (method_info)); + g_assert_cmpstr (gi_base_info_get_name (GI_BASE_INFO (method_info)), ==, "trylock"); + g_clear_pointer (&method_info, gi_base_info_unref); + + g_clear_pointer (&mutex_info, gi_base_info_unref); +} + +int +main (int argc, + char *argv[]) +{ + repository_init (&argc, &argv); + + ADD_REPOSITORY_TEST ("/union-info/basic", test_basic, &typelib_load_spec_glib); + ADD_REPOSITORY_TEST ("/union-info/methods", test_methods, &typelib_load_spec_glib); + + return g_test_run (); +}