summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/gir-1.2.rnc11
-rw-r--r--giscanner/ast.py12
-rw-r--r--giscanner/gdumpparser.py8
-rw-r--r--giscanner/girparser.py2
-rw-r--r--giscanner/girwriter.py4
-rw-r--r--giscanner/transformer.py27
-rw-r--r--tests/scanner/Identfilter-1.0-expected.gir7
-rw-r--r--tests/scanner/Regress-1.0-expected.gir13
-rw-r--r--tests/scanner/Symbolfilter-1.0-expected.gir2
-rw-r--r--tests/scanner/Typedefs-1.0-expected.gir1
-rw-r--r--tests/scanner/test_transformer.py39
11 files changed, 106 insertions, 20 deletions
diff --git a/docs/gir-1.2.rnc b/docs/gir-1.2.rnc
index b7960ffa..a1db5279 100644
--- a/docs/gir-1.2.rnc
+++ b/docs/gir-1.2.rnc
@@ -215,9 +215,16 @@ grammar {
attribute name { xsd:string },
## Corresponding C type of the record
attribute c:type { xsd:string }?,
- ## Binary attribute to tell if the record is disguised, i.e. whether the c:type is a typedef that doesn't look like a pointer, but is one internally
- ## Its second meaning is "private" and is set when any typedef struct is parsed which doesn't also include a full struct with fields (https://gitlab.gnome.org/GNOME/gobject-introspection/issues/101)
+ ## Deprecated. Binary attribute to tell if the record is disguised, i.e. whether the c:type
+ ## is a typedef that doesn't look like a pointer, but is one internally. Its second meaning
+ ## is "private" and is set when any typedef struct is parsed which doesn't also include a
+ ## full struct with fields (https://gitlab.gnome.org/GNOME/gobject-introspection/issues/101)
+ ## Replaced by "opaque" and "pointer".
attribute disguised { "0" | "1" }?,
+ ## Binary attribute for a typedef struct that does not have a corresponding public structure definition
+ attribute opaque { "0" | "1" }?,
+ ## Binary attribute for a typedef struct pointer, e.g. typedef struct Foo* FooPtr
+ attribute pointer { "0" | "1" }?,
## GObject compatible C type of the record
attribute glib:type-name { xsd:string }?,
## Function to get the GObject compatible type of the record
diff --git a/giscanner/ast.py b/giscanner/ast.py
index bbfbe267..ad94f437 100644
--- a/giscanner/ast.py
+++ b/giscanner/ast.py
@@ -1021,6 +1021,8 @@ class Compound(Node, Registered):
get_type=None,
c_symbol_prefix=None,
disguised=False,
+ opaque=False,
+ pointer=False,
tag_name=None):
Node.__init__(self, name)
Registered.__init__(self, gtype_name, get_type)
@@ -1030,6 +1032,8 @@ class Compound(Node, Registered):
self.fields = []
self.constructors = []
self.disguised = disguised
+ self.opaque = opaque
+ self.pointer = pointer
self.gtype_name = gtype_name
self.get_type = get_type
self.c_symbol_prefix = c_symbol_prefix
@@ -1116,6 +1120,8 @@ class Record(Compound):
get_type=None,
c_symbol_prefix=None,
disguised=False,
+ opaque=False,
+ pointer=False,
tag_name=None):
Compound.__init__(self, name,
ctype=ctype,
@@ -1123,6 +1129,8 @@ class Record(Compound):
get_type=get_type,
c_symbol_prefix=c_symbol_prefix,
disguised=disguised,
+ opaque=opaque,
+ pointer=pointer,
tag_name=tag_name)
# If non-None, this record defines the FooClass C structure
# for some Foo GObject (or similar for GInterface)
@@ -1143,6 +1151,8 @@ class Union(Compound):
get_type=None,
c_symbol_prefix=None,
disguised=False,
+ opaque=False,
+ pointer=False,
tag_name=None):
Compound.__init__(self, name,
ctype=ctype,
@@ -1150,6 +1160,8 @@ class Union(Compound):
get_type=get_type,
c_symbol_prefix=c_symbol_prefix,
disguised=disguised,
+ opaque=opaque,
+ pointer=pointer,
tag_name=tag_name)
# If non-None, this union has a copy function for heap
# allocated instances
diff --git a/giscanner/gdumpparser.py b/giscanner/gdumpparser.py
index b5ca4362..10cbcc91 100644
--- a/giscanner/gdumpparser.py
+++ b/giscanner/gdumpparser.py
@@ -229,7 +229,10 @@ blob containing data gleaned from GObject's primitive introspection."""
get_type='intern',
c_symbol_prefix='variant')
elif record.name == 'InitiallyUnownedClass':
+ # InitiallyUnowned is just GObject with extra steps, so we alias
+ # it in the introspection data
record.fields = self._namespace.get('ObjectClass').fields
+ record.opaque = False
record.disguised = False
# Introspection over the data we get from the dynamic
@@ -522,8 +525,9 @@ different --identifier-prefix.""" % (xmlnode.attrib['name'], self._namespace.ide
pair_node.add_gtype(boxed.gtype_name, boxed.get_type)
assert boxed.c_symbol_prefix is not None
pair_node.c_symbol_prefix = boxed.c_symbol_prefix
- # Quick hack - reset the disguised flag; we're setting it
- # incorrectly in the scanner
+ # Backward compatibility hack - reset the disguised flag; we're
+ # setting it incorrectly in the scanner. We don't change the
+ # opaque flag, because it's a new one and we define its behavior
pair_node.disguised = False
else:
return False
diff --git a/giscanner/girparser.py b/giscanner/girparser.py
index 2f8c5f66..b652f2d6 100644
--- a/giscanner/girparser.py
+++ b/giscanner/girparser.py
@@ -435,6 +435,8 @@ class GIRParser(object):
compound = cls(node.attrib.get('name'),
ctype=node.attrib.get(_cns('type')),
disguised=node.attrib.get('disguised') == '1',
+ opaque=node.attrib.get('opaque') == '1',
+ pointer=node.attrib.get('pointer') == '1',
gtype_name=node.attrib.get(_glibns('type-name')),
get_type=node.attrib.get(_glibns('get-type')),
c_symbol_prefix=node.attrib.get(_cns('symbol-prefix')))
diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py
index 810acad6..db4dccb4 100644
--- a/giscanner/girwriter.py
+++ b/giscanner/girwriter.py
@@ -587,6 +587,10 @@ class GIRWriter(XMLWriter):
attrs.append(('c:type', record.ctype))
if record.disguised:
attrs.append(('disguised', '1'))
+ if record.opaque:
+ attrs.append(('opaque', '1'))
+ if record.pointer:
+ attrs.append(('pointer', '1'))
if record.foreign:
attrs.append(('foreign', '1'))
if record.is_gtype_struct_for is not None:
diff --git a/giscanner/transformer.py b/giscanner/transformer.py
index ad2a87f4..3b0bea8a 100644
--- a/giscanner/transformer.py
+++ b/giscanner/transformer.py
@@ -613,7 +613,7 @@ raise ValueError."""
elif (ctype == CTYPE_FUNCTION):
node = self._create_typedef_callback(symbol)
elif (ctype == CTYPE_POINTER and symbol.base_type.base_type.type == CTYPE_STRUCT):
- node = self._create_typedef_compound(ast.Record, symbol, disguised=True)
+ node = self._create_typedef_compound(ast.Record, symbol, disguised=True, pointer=True)
elif ctype == CTYPE_STRUCT:
node = self._create_typedef_compound(ast.Record, symbol)
elif ctype == CTYPE_UNION:
@@ -801,7 +801,7 @@ raise ValueError."""
const.add_symbol_reference(symbol)
return const
- def _create_typedef_compound(self, compound_class, symbol, disguised=False):
+ def _create_typedef_compound(self, compound_class, symbol, disguised=False, pointer=False):
name = self.strip_identifier(symbol.ident)
assert symbol.base_type
if symbol.base_type.name:
@@ -840,12 +840,14 @@ raise ValueError."""
# Structs with a typedef name are promoted into the main namespace
# by it being returned to the "parse" function and are also added to
# the tag namespace if it has a tag_name set.
- compound = compound_class(name, symbol.ident, disguised=disguised, tag_name=tag_name)
+ compound = compound_class(name, symbol.ident, disguised=disguised, pointer=pointer, tag_name=tag_name)
if tag_name:
- # Force the struct as disguised for now since we do not yet know
- # if it has fields that will be parsed. Note that this is using
- # an erroneous definition of disguised and we should eventually
- # only look at the field count when needed.
+ # Force the struct as opaque for now since we do not yet know
+ # if it has fields that will be parsed.
+ compound.opaque = True
+ # Set disguised as well, for backward compatibility; the "disguised" field
+ # is used incorrectly, here, but it's too late for us to change this. See
+ # https://gitlab.gnome.org/GNOME/gobject-introspection/-/issues/101
compound.disguised = True
else:
# Case where we have an anonymous struct which is typedef'd:
@@ -864,12 +866,17 @@ raise ValueError."""
else:
compound = compound_class(None, symbol.ident, tag_name=symbol.ident)
- # Make sure disguised is False as we are now about to parse the
- # fields of the real struct.
- compound.disguised = False
# Fields may need to be parsed in either of the above cases because the
# Record can be created with a typedef prior to the struct definition.
self._parse_fields(symbol, compound)
+
+ # A compound type with no fields is opaque
+ compound.opaque = len(compound.fields) == 0
+ # Unconditionally set disguised to false, for backward compatibility;
+ # the "disguised" field is used incorrectly, here, but it's too late for
+ # us to change this. See:
+ # https://gitlab.gnome.org/GNOME/gobject-introspection/-/issues/101
+ compound.disguised = False
compound.add_symbol_reference(symbol)
return compound
diff --git a/tests/scanner/Identfilter-1.0-expected.gir b/tests/scanner/Identfilter-1.0-expected.gir
index 15cd408a..05af2a56 100644
--- a/tests/scanner/Identfilter-1.0-expected.gir
+++ b/tests/scanner/Identfilter-1.0-expected.gir
@@ -11,10 +11,13 @@ and/or use gtk-doc annotations. -->
shared-library=""
c:identifier-prefixes="Identfilter"
c:symbol-prefixes="identfilter">
- <record name="Context" c:type="identfilter_t" disguised="1">
+ <record name="Context" c:type="identfilter_t" disguised="1" opaque="1">
<source-position filename="identfilter.h" line="4"/>
</record>
- <record name="Object" c:type="identfilter_object_t" disguised="1">
+ <record name="Object"
+ c:type="identfilter_object_t"
+ disguised="1"
+ opaque="1">
<source-position filename="identfilter.h" line="5"/>
<method name="foo_method" c:identifier="identfilter_object_foo_method">
<source-position filename="identfilter.h" line="8"/>
diff --git a/tests/scanner/Regress-1.0-expected.gir b/tests/scanner/Regress-1.0-expected.gir
index ecfc5cb6..902513d7 100644
--- a/tests/scanner/Regress-1.0-expected.gir
+++ b/tests/scanner/Regress-1.0-expected.gir
@@ -1511,6 +1511,7 @@ it says it's pointer but it's actually a string.</doc>
</union>
<record name="FooBoxed"
c:type="RegressFooBoxed"
+ opaque="1"
glib:type-name="RegressFooBoxed"
glib:get-type="regress_foo_boxed_get_type"
c:symbol-prefix="foo_boxed">
@@ -1557,6 +1558,7 @@ it says it's pointer but it's actually a string.</doc>
<record name="FooBufferClass"
c:type="RegressFooBufferClass"
disguised="1"
+ opaque="1"
glib:is-gtype-struct-for="FooBuffer">
<source-position filename="foo.h" line="52"/>
</record>
@@ -1582,6 +1584,7 @@ it says it's pointer but it's actually a string.</doc>
</callback>
<record name="FooDBusData"
c:type="RegressFooDBusData"
+ opaque="1"
glib:type-name="RegressFooDBusData"
glib:get-type="regress_foo_dbus_data_get_type"
c:symbol-prefix="foo_dbus_data">
@@ -2252,6 +2255,7 @@ uses a C sugar return type.</doc>
<record name="FooOtherObjectClass"
c:type="RegressFooOtherObjectClass"
disguised="1"
+ opaque="1"
glib:is-gtype-struct-for="FooOtherObject">
<source-position filename="foo.h" line="54"/>
</record>
@@ -2378,7 +2382,8 @@ exposed to language bindings.</doc>
</record>
<record name="FooStructPrivate"
c:type="RegressFooStructPrivate"
- disguised="1">
+ disguised="1"
+ opaque="1">
<source-position filename="foo.h" line="325"/>
</record>
<interface name="FooSubInterface"
@@ -2648,7 +2653,7 @@ exposed to language bindings.</doc>
<source-position filename="regress.h" line="520"/>
<type name="gint" c:type="gint"/>
</constant>
- <record name="Intset" c:type="RegressIntset" disguised="1">
+ <record name="Intset" c:type="RegressIntset" disguised="1" opaque="1">
<doc xml:space="preserve"
filename="regress.h"
line="1422">Like telepathy-glib's TpIntset.</doc>
@@ -3137,6 +3142,7 @@ use it should be.</doc>
</record>
<record name="TestBoxedD"
c:type="RegressTestBoxedD"
+ opaque="1"
copy-function="regress_test_boxed_d_copy"
free-function="regress_test_boxed_d_free"
glib:type-name="RegressTestBoxedD"
@@ -3193,7 +3199,8 @@ use it should be.</doc>
</record>
<record name="TestBoxedPrivate"
c:type="RegressTestBoxedPrivate"
- disguised="1">
+ disguised="1"
+ opaque="1">
<source-position filename="regress.h" line="677"/>
</record>
<callback name="TestCallback" c:type="RegressTestCallback">
diff --git a/tests/scanner/Symbolfilter-1.0-expected.gir b/tests/scanner/Symbolfilter-1.0-expected.gir
index 80fe0d4b..176b4f07 100644
--- a/tests/scanner/Symbolfilter-1.0-expected.gir
+++ b/tests/scanner/Symbolfilter-1.0-expected.gir
@@ -11,7 +11,7 @@ and/or use gtk-doc annotations. -->
shared-library=""
c:identifier-prefixes="Symbolfilter"
c:symbol-prefixes="symbolfilter">
- <record name="Object" c:type="SymbolfilterObject" disguised="1">
+ <record name="Object" c:type="SymbolfilterObject" disguised="1" opaque="1">
<source-position filename="symbolfilter.h" line="4"/>
<method name="filterObjectFooMethod"
c:identifier="SymbolfilterObjectFooMethod">
diff --git a/tests/scanner/Typedefs-1.0-expected.gir b/tests/scanner/Typedefs-1.0-expected.gir
index 05df44b9..94a50e7b 100644
--- a/tests/scanner/Typedefs-1.0-expected.gir
+++ b/tests/scanner/Typedefs-1.0-expected.gir
@@ -26,6 +26,7 @@ and/or use gtk-doc annotations. -->
</record>
<record name="BoxedWithHiddenStruct"
c:type="TypedefsBoxedWithHiddenStruct"
+ opaque="1"
glib:type-name="TypedefsBoxedWithHiddenStruct"
glib:get-type="typedefs_boxed_with_hidden_struct_get_type"
c:symbol-prefix="boxed_with_hidden_struct">
diff --git a/tests/scanner/test_transformer.py b/tests/scanner/test_transformer.py
index 3feed441..1b7aef3c 100644
--- a/tests/scanner/test_transformer.py
+++ b/tests/scanner/test_transformer.py
@@ -97,6 +97,8 @@ class TestStructTypedefs(unittest.TestCase):
node = self.namespace.get('Struct')
self.assertTrue(node is not None)
self.assertTrue(isinstance(node, ast.Record))
+ self.assertFalse(node.opaque)
+ self.assertFalse(node.pointer)
self.assertFalse(node.disguised)
self.assertEqual(len(node.fields), 1)
@@ -111,6 +113,8 @@ class TestStructTypedefs(unittest.TestCase):
node = self.namespace.get('Struct')
self.assertTrue(node is not None)
self.assertTrue(isinstance(node, ast.Record))
+ self.assertFalse(node.opaque)
+ self.assertFalse(node.pointer)
self.assertFalse(node.disguised)
self.assertEqual(len(node.fields), 1)
@@ -125,6 +129,8 @@ class TestStructTypedefs(unittest.TestCase):
node = self.namespace.get('Struct')
self.assertTrue(node is not None)
self.assertTrue(isinstance(node, ast.Record))
+ self.assertFalse(node.opaque)
+ self.assertFalse(node.pointer)
self.assertFalse(node.disguised)
self.assertEqual(len(node.fields), 1)
@@ -138,6 +144,8 @@ class TestStructTypedefs(unittest.TestCase):
node = self.namespace.get('Struct')
self.assertTrue(node is not None)
self.assertTrue(isinstance(node, ast.Record))
+ self.assertFalse(node.opaque)
+ self.assertFalse(node.pointer)
self.assertFalse(node.disguised)
self.assertEqual(len(node.fields), 1)
@@ -151,6 +159,8 @@ class TestStructTypedefs(unittest.TestCase):
node = self.namespace.get('Struct')
self.assertTrue(node is not None)
self.assertTrue(isinstance(node, ast.Record))
+ self.assertFalse(node.opaque)
+ self.assertFalse(node.pointer)
self.assertFalse(node.disguised)
self.assertEqual(len(node.fields), 1)
@@ -167,6 +177,8 @@ class TestStructTypedefs(unittest.TestCase):
node = self.namespace.get('Struct')
self.assertTrue(node is not None)
self.assertTrue(isinstance(node, ast.Record))
+ self.assertFalse(node.opaque)
+ self.assertFalse(node.pointer)
self.assertFalse(node.disguised)
self.assertEqual(len(node.fields), 1)
@@ -194,6 +206,8 @@ class TestStructTypedefs(unittest.TestCase):
node = self.namespace.get('Struct')
self.assertTrue(node is not None)
self.assertTrue(isinstance(node, ast.Record))
+ self.assertFalse(node.opaque)
+ self.assertFalse(node.pointer)
self.assertFalse(node.disguised)
self.assertEqual(len(node.fields), 1)
self.assertEqual(node.ctype, 'TestStruct')
@@ -201,6 +215,8 @@ class TestStructTypedefs(unittest.TestCase):
shared = self.namespace.get('StructAlias')
self.assertTrue(shared is not None)
self.assertTrue(isinstance(shared, ast.Record))
+ self.assertFalse(shared.opaque)
+ self.assertFalse(shared.pointer)
self.assertFalse(shared.disguised)
self.assertEqual(len(shared.fields), 1)
self.assertEqual(shared.ctype, 'TestStructAlias')
@@ -218,6 +234,8 @@ class TestStructTypedefs(unittest.TestCase):
node = self.namespace.get('Struct')
self.assertTrue(node is not None)
self.assertTrue(isinstance(node, ast.Record))
+ self.assertFalse(node.opaque)
+ self.assertFalse(node.pointer)
self.assertFalse(node.disguised)
self.assertEqual(len(node.fields), 1)
self.assertEqual(node.ctype, 'TestStruct')
@@ -225,6 +243,8 @@ class TestStructTypedefs(unittest.TestCase):
shared = self.namespace.get('StructAlias')
self.assertTrue(shared is not None)
self.assertTrue(isinstance(shared, ast.Record))
+ self.assertFalse(shared.opaque)
+ self.assertFalse(shared.pointer)
self.assertFalse(shared.disguised)
self.assertEqual(len(shared.fields), 1)
self.assertEqual(shared.ctype, 'TestStructAlias')
@@ -262,6 +282,8 @@ class TestStructTypedefs(unittest.TestCase):
node = self.namespace.get('Struct')
self.assertTrue(node is not None)
self.assertTrue(isinstance(node, ast.Record))
+ self.assertFalse(node.opaque)
+ self.assertFalse(node.pointer)
self.assertFalse(node.disguised)
self.assertEqual(node.ctype, 'TestStruct')
self.assertEqual(len(node.fields), 1)
@@ -270,10 +292,27 @@ class TestStructTypedefs(unittest.TestCase):
self.assertTrue(ptr is not None)
# This currently gives a disguised Record instead of an Alias
self.assertTrue(isinstance(ptr, ast.Record))
+ self.assertFalse(ptr.opaque)
+ self.assertTrue(ptr.pointer)
self.assertTrue(ptr.disguised)
self.assertEqual(len(ptr.fields), 0)
self.assertEqual(ptr.ctype, 'TestStructPtr')
+ def test_opaque_struct(self):
+ load_namespace_from_source_string(self.namespace, """
+ typedef struct _TestStruct TestStruct;
+ """)
+ self.assertEqual(len(self.namespace.names), 1)
+
+ node = self.namespace.get('Struct')
+ self.assertIsNotNone(node)
+ self.assertIsInstance(node, ast.Record)
+ self.assertTrue(node.opaque)
+ self.assertFalse(node.pointer)
+ self.assertTrue(node.disguised)
+ self.assertEqual(node.ctype, 'TestStruct')
+ self.assertFalse(node.fields)
+
class TestNestedStructs(unittest.TestCase):
def setUp(self):