diff options
-rw-r--r-- | docs/gir-1.2.rnc | 11 | ||||
-rw-r--r-- | giscanner/ast.py | 12 | ||||
-rw-r--r-- | giscanner/gdumpparser.py | 8 | ||||
-rw-r--r-- | giscanner/girparser.py | 2 | ||||
-rw-r--r-- | giscanner/girwriter.py | 4 | ||||
-rw-r--r-- | giscanner/transformer.py | 27 | ||||
-rw-r--r-- | tests/scanner/Identfilter-1.0-expected.gir | 7 | ||||
-rw-r--r-- | tests/scanner/Regress-1.0-expected.gir | 13 | ||||
-rw-r--r-- | tests/scanner/Symbolfilter-1.0-expected.gir | 2 | ||||
-rw-r--r-- | tests/scanner/Typedefs-1.0-expected.gir | 1 | ||||
-rw-r--r-- | tests/scanner/test_transformer.py | 39 |
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): |