summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTorsten Schönfeld <kaffeetisch@gmx.de>2011-09-10 16:52:51 +0200
committerTorsten Schönfeld <kaffeetisch@gmx.de>2011-09-11 00:34:28 +0200
commitea68ec234ad31b0a1d92adbf0c911a5dd541b647 (patch)
tree125930f400320b4bddfa7948396a10915f83c1b5
parentc3da3d46ffa9c3b53e7f7132eaa9c9c722ebc859 (diff)
downloadgobject-introspection-ea68ec234ad31b0a1d92adbf0c911a5dd541b647.tar.gz
scanner: correctly handle structs with arrays of anon unions
This applies mainly to GValue, which is defined as: struct _GValue { /*< private >*/ GType g_type; /* public for GTypeValueTable methods */ union { gint v_int; guint v_uint; glong v_long; gulong v_ulong; gint64 v_int64; guint64 v_uint64; gfloat v_float; gdouble v_double; gpointer v_pointer; } data[2]; }; Previously, the scanner did not understand the array of unions. This resulted in g_struct_info_get_size returning an incorrect size for GValue (at least on 32bit systems). Fix this by making up a separate union declaration for the GIR that can be referenced by the array. https://bugzilla.gnome.org/show_bug.cgi?id=657040
-rw-r--r--giscanner/transformer.py54
-rw-r--r--tests/repository/Makefile.am2
-rw-r--r--tests/repository/gitypelibtest.c26
-rw-r--r--tests/scanner/Regress-1.0-expected.gir39
-rw-r--r--tests/scanner/regress.h17
5 files changed, 126 insertions, 12 deletions
diff --git a/giscanner/transformer.py b/giscanner/transformer.py
index 4ce2ac0e..d3a056b3 100644
--- a/giscanner/transformer.py
+++ b/giscanner/transformer.py
@@ -315,7 +315,7 @@ raise ValueError."""
return '_' + name
return name
- def _traverse_one(self, symbol, stype=None):
+ def _traverse_one(self, symbol, stype=None, parent_symbol=None):
assert isinstance(symbol, SourceSymbol), symbol
if stype is None:
@@ -329,7 +329,7 @@ raise ValueError."""
elif stype == CSYMBOL_TYPE_ENUM:
return self._create_enum(symbol)
elif stype == CSYMBOL_TYPE_MEMBER:
- return self._create_member(symbol)
+ return self._create_member(symbol, parent_symbol)
elif stype == CSYMBOL_TYPE_UNION:
return self._create_union(symbol)
elif stype == CSYMBOL_TYPE_CONST:
@@ -442,7 +442,29 @@ raise ValueError."""
for child in base_type.child_list:
yield self._create_parameter(child)
- def _create_member(self, symbol):
+ def _synthesize_union_type(self, symbol, parent_symbol):
+ # Synthesize a named union so that it can be referenced.
+ parent_ident = parent_symbol.ident
+ # FIXME: Should split_ctype_namespaces handle the hidden case?
+ hidden = parent_ident.startswith('_')
+ if hidden:
+ parent_ident = parent_ident[1:]
+ matches = self.split_ctype_namespaces(parent_ident)
+ (namespace, parent_name) = matches[-1]
+ assert namespace and parent_name
+ if hidden:
+ parent_name = '_' + parent_name
+ fake_union = ast.Union("%s__%s__union" % (parent_name, symbol.ident))
+ # _parse_fields accesses <type>.base_type.child_list, so we have to
+ # pass symbol.base_type even though that refers to the array, not the
+ # union.
+ self._parse_fields(symbol.base_type, fake_union)
+ self._append_new_node(fake_union)
+ fake_type = ast.Type(
+ target_giname="%s.%s" % (namespace.name, fake_union.name))
+ return fake_type
+
+ def _create_member(self, symbol, parent_symbol=None):
source_type = symbol.base_type
if (source_type.type == CTYPE_POINTER and
symbol.base_type.base_type.type == CTYPE_FUNCTION):
@@ -455,14 +477,24 @@ raise ValueError."""
# Special handling for fields; we don't have annotations on them
# to apply later, yet.
if source_type.type == CTYPE_ARRAY:
- ctype = self._create_source_type(source_type)
- canonical_ctype = self._canonicalize_ctype(ctype)
- if canonical_ctype[-1] == '*':
- derefed_name = canonical_ctype[:-1]
+ # If the array contains anonymous unions, like in the GValue
+ # struct, we need to handle this specially. This is necessary
+ # to be able to properly calculate the size of the compound
+ # type (e.g. GValue) that contains this array, see
+ # <https://bugzilla.gnome.org/show_bug.cgi?id=657040>.
+ if (source_type.base_type.type == CTYPE_UNION and
+ source_type.base_type.name is None):
+ synthesized_type = self._synthesize_union_type(symbol, parent_symbol)
+ ftype = ast.Array(None, synthesized_type)
else:
- derefed_name = canonical_ctype
- ftype = ast.Array(None, self.create_type_from_ctype_string(ctype),
- ctype=derefed_name)
+ ctype = self._create_source_type(source_type)
+ canonical_ctype = self._canonicalize_ctype(ctype)
+ if canonical_ctype[-1] == '*':
+ derefed_name = canonical_ctype[:-1]
+ else:
+ derefed_name = canonical_ctype
+ ftype = ast.Array(None, self.create_type_from_ctype_string(ctype),
+ ctype=derefed_name)
child_list = list(symbol.base_type.child_list)
ftype.zeroterminated = False
if child_list:
@@ -677,7 +709,7 @@ raise ValueError."""
def _parse_fields(self, symbol, compound):
for child in symbol.base_type.child_list:
- child_node = self._traverse_one(child)
+ child_node = self._traverse_one(child, parent_symbol=symbol)
if not child_node:
continue
if isinstance(child_node, ast.Field):
diff --git a/tests/repository/Makefile.am b/tests/repository/Makefile.am
index ffc635fe..6331cd30 100644
--- a/tests/repository/Makefile.am
+++ b/tests/repository/Makefile.am
@@ -17,5 +17,5 @@ gitypelibtest_CPPFLAGS = $(GIREPO_CFLAGS) -I$(top_srcdir)/girepository
gitypelibtest_LDADD = $(top_builddir)/libgirepository-1.0.la $(GIREPO_LIBS)
TESTS = gitestrepo gitestthrows gitypelibtest
-TESTS_ENVIRONMENT=env GI_TYPELIB_PATH=$(top_builddir):$(top_builddir)/tests \
+TESTS_ENVIRONMENT=env GI_TYPELIB_PATH=$(top_builddir):$(top_builddir)/tests:$(top_builddir)/tests/scanner \
XDG_DATA_DIRS="$(top_srcdir)/gir:$(XDG_DATA_DIRS)" $(DEBUG)
diff --git a/tests/repository/gitypelibtest.c b/tests/repository/gitypelibtest.c
index 2896846a..6e69b096 100644
--- a/tests/repository/gitypelibtest.c
+++ b/tests/repository/gitypelibtest.c
@@ -106,6 +106,31 @@ test_enum_and_flags_static_methods(GIRepository *repo)
g_base_info_unref (enum_info);
}
+static void
+test_size_of_struct_with_array_of_anon_unions(GIRepository *repo)
+{
+ GITypelib *ret;
+ GError *error = NULL;
+ GIBaseInfo *struct_info;
+
+ ret = g_irepository_require (repo, "Regress", NULL, 0, &error);
+ if (!ret)
+ g_error ("%s", error->message);
+
+ struct_info = g_irepository_find_by_name (repo, "Regress", "TestStructE");
+ if (!struct_info)
+ g_error ("Could not find Regress.TestStructE");
+ g_assert (g_struct_info_get_size (struct_info)
+ == sizeof (GType) + 2*sizeof (gint64));
+ g_base_info_unref (struct_info);
+
+ struct_info = g_irepository_find_by_name (repo, "GObject", "Value");
+ if (!struct_info)
+ g_error ("Could not find GObject.Value");
+ g_assert (g_struct_info_get_size (struct_info) == sizeof (GValue));
+ g_base_info_unref (struct_info);
+}
+
int
main(int argc, char **argv)
{
@@ -118,6 +143,7 @@ main(int argc, char **argv)
/* do tests */
test_enum_and_flags_cidentifier (repo);
test_enum_and_flags_static_methods (repo);
+ test_size_of_struct_with_array_of_anon_unions (repo);
exit(0);
}
diff --git a/tests/scanner/Regress-1.0-expected.gir b/tests/scanner/Regress-1.0-expected.gir
index 2f4b5c21..79ca1d31 100644
--- a/tests/scanner/Regress-1.0-expected.gir
+++ b/tests/scanner/Regress-1.0-expected.gir
@@ -1162,6 +1162,45 @@ TpAccount::status-changed</doc>
</array>
</field>
</record>
+ <record name="TestStructE" c:type="RegressTestStructE">
+ <field name="some_type" writable="1">
+ <type name="GType" c:type="GType"/>
+ </field>
+ <field name="some_union" writable="1">
+ <array zero-terminated="0" fixed-size="2">
+ <type name="TestStructE__some_union__union"/>
+ </array>
+ </field>
+ </record>
+ <union name="TestStructE__some_union__union">
+ <field name="v_int" writable="1">
+ <type name="gint" c:type="gint"/>
+ </field>
+ <field name="v_uint" writable="1">
+ <type name="guint" c:type="guint"/>
+ </field>
+ <field name="v_long" writable="1">
+ <type name="glong" c:type="glong"/>
+ </field>
+ <field name="v_ulong" writable="1">
+ <type name="gulong" c:type="gulong"/>
+ </field>
+ <field name="v_int64" writable="1">
+ <type name="gint64" c:type="gint64"/>
+ </field>
+ <field name="v_uint64" writable="1">
+ <type name="guint64" c:type="guint64"/>
+ </field>
+ <field name="v_float" writable="1">
+ <type name="gfloat" c:type="gfloat"/>
+ </field>
+ <field name="v_double" writable="1">
+ <type name="gdouble" c:type="gdouble"/>
+ </field>
+ <field name="v_pointer" writable="1">
+ <type name="gpointer" c:type="gpointer"/>
+ </field>
+ </union>
<record name="TestStructFixedArray" c:type="RegressTestStructFixedArray">
<field name="just_int" writable="1">
<type name="gint" c:type="gint"/>
diff --git a/tests/scanner/regress.h b/tests/scanner/regress.h
index f30fcd78..4afb9b06 100644
--- a/tests/scanner/regress.h
+++ b/tests/scanner/regress.h
@@ -243,6 +243,23 @@ struct _RegressTestStructD
GPtrArray *garray;
};
+/* This one has an array of anonymous unions, inspired by GValue */
+struct RegressTestStructE
+{
+ GType some_type;
+ union {
+ gint v_int;
+ guint v_uint;
+ glong v_long;
+ gulong v_ulong;
+ gint64 v_int64;
+ guint64 v_uint64;
+ gfloat v_float;
+ gdouble v_double;
+ gpointer v_pointer;
+ } some_union[2];
+};
+
/* plain-old-data boxed types */
typedef struct _RegressTestSimpleBoxedA RegressTestSimpleBoxedA;
typedef struct _RegressTestSimpleBoxedB RegressTestSimpleBoxedB;