Bug 557788 – Return types for constructors in generated typelib bogus
[gnome.gobject-introspection] / giscanner / glibtransformer.py
1 # -*- Mode: Python -*-
2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008  Johan Dahlin
4 #
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 # 02110-1301, USA.
19 #
20
21 import os
22 import re
23 import ctypes
24 from ctypes.util import find_library
25
26 from . import cgobject
27 from .ast import (Callback, Constant, Enum, Function, Member, Namespace,
28                   Parameter, Property, Return, Struct, Type, Alias,
29                   Union, Field, type_name_from_ctype,
30                   default_array_types, TYPE_UINT8, PARAM_DIRECTION_IN)
31 from .transformer import Names
32 from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember, GLibFlags,
33                       GLibInterface, GLibObject, GLibSignal, GLibBoxedStruct,
34                       GLibBoxedUnion, GLibBoxedOther, type_names)
35 from .utils import extract_libtool, to_underscores, to_underscores_noprefix
36
37 default_array_types['guchar*'] = TYPE_UINT8
38
39 SYMBOL_BLACKLIST = [
40     # These ones break GError conventions
41     'g_simple_async_result_new_from_error',
42     'g_simple_async_result_set_from_error',
43     'g_simple_async_result_propagate_error',
44     'g_simple_async_result_report_error_in_idle',
45     'gtk_print_operation_get_error',
46 ]
47
48 SYMBOL_BLACKLIST_RE = [re.compile(x) for x in \
49                            [r'\w+_marshal_[A-Z]+__', ]]
50
51
52 class Unresolved(object):
53
54     def __init__(self, target):
55         self.target = target
56
57
58 class UnknownTypeError(Exception):
59     pass
60
61
62 class GLibTransformer(object):
63
64     def __init__(self, transformer, noclosure=False):
65         self._transformer = transformer
66         self._transformer.set_container_types(['GList*', 'GSList*'],
67                                               ['GHashtable*'])
68         self._namespace_name = None
69         self._names = Names()
70         self._uscore_type_names = {}
71         self._libraries = []
72         self._failed_types = {}
73         self._boxed_types = {}
74         self._private_internal_types = {}
75         self._noclosure = noclosure
76         self._validating = False
77
78     # Public API
79
80     def add_library(self, libname):
81         # For testing mainly.
82         libtool_libname = 'lib' + libname + '.la'
83         if os.path.exists(libtool_libname):
84             found_libname = extract_libtool(libtool_libname)
85         elif libname.endswith('.la'):
86             found_libname = extract_libtool(libname)
87         else:
88             found_libname = find_library(libname)
89         if not found_libname:
90             raise ValueError("Failed to find library: %r" % (libname, ))
91         self._libraries.append(ctypes.cdll.LoadLibrary(found_libname))
92
93     def _print_statistics(self):
94         nodes = list(self._names.names.itervalues())
95
96         def count_type(otype):
97             return len([x for x in nodes
98                         if isinstance(x[1], otype)])
99         objectcount = count_type(GLibObject)
100         ifacecount = count_type(GLibInterface)
101         enumcount = count_type(GLibEnum)
102         print " %d nodes; %d objects, %d interfaces, %d enums" \
103             % (len(nodes), objectcount, ifacecount, enumcount)
104
105     def parse(self):
106         namespace = self._transformer.parse()
107         self._namespace_name = namespace.name
108
109         # First pass: parsing
110         for node in namespace.nodes:
111             self._parse_node(node)
112
113         # We don't want an alias for this - it's handled specially in
114         # the typelib compiler.
115         if namespace.name == 'GObject':
116             del self._names.aliases['Type']
117
118         # Introspection is done from within parsing
119
120         # Second pass: pair boxed structures
121         for boxed in self._boxed_types.itervalues():
122             self._pair_boxed_type(boxed)
123         # Third pass: delete class structures, resolve
124         # all types we now know about
125         nodes = list(self._names.names.itervalues())
126         for (ns, node) in nodes:
127             try:
128                 self._resolve_node(node)
129             except KeyError, e:
130                 print "WARNING: DELETING node %s: %s" % (node.name, e)
131                 self._remove_attribute(node.name)
132             # associate GtkButtonClass with GtkButton
133             if isinstance(node, Struct):
134                 self._pair_class_struct(node)
135         for (ns, alias) in self._names.aliases.itervalues():
136             self._resolve_alias(alias)
137
138         self._print_statistics()
139         # Fourth pass: ensure all types are known
140         if not self._noclosure:
141             self._validate(nodes)
142
143         # Create a new namespace with what we found
144         namespace = Namespace(namespace.name, namespace.version)
145         namespace.nodes = map(lambda x: x[1], self._names.aliases.itervalues())
146         for (ns, x) in self._names.names.itervalues():
147             namespace.nodes.append(x)
148         return namespace
149
150     # Private
151
152     def _add_attribute(self, node, replace=False):
153         node_name = node.name
154         if (not replace) and node_name in self._names.names:
155             return
156         self._names.names[node_name] = (None, node)
157
158     def _remove_attribute(self, name):
159         del self._names.names[name]
160
161     def _get_attribute(self, name):
162         node = self._names.names.get(name)
163         if node:
164             return node[1]
165         return None
166
167     def _register_internal_type(self, type_name, node):
168         self._names.type_names[type_name] = (None, node)
169         uscored = to_underscores(type_name).lower()
170         self._uscore_type_names[uscored] = node
171         # Besides the straight underscore conversion, we also try
172         # removing the underscores from the namespace as a possible C
173         # mapping; e.g. it's webkit_web_view, not web_kit_web_view
174         suffix = self._transformer.remove_prefix(type_name)
175         prefix = type_name[:-len(suffix)]
176         no_uscore_prefixed = (prefix + '_' + to_underscores(suffix)).lower()
177         self._uscore_type_names[no_uscore_prefixed] = node
178
179     # Helper functions
180
181     def _type_from_gtype(self, type_id):
182         ctype = cgobject.type_name(type_id)
183         type_name = type_name_from_ctype(ctype)
184         type_name = type_name.replace('*', '')
185         type_name = self._resolve_type_name(type_name)
186
187         type = Type(type_name, ctype)
188         type._gtype = type_id
189         return type
190
191     def _resolve_gtypename(self, gtype_name):
192         try:
193             return self._transformer.gtypename_to_giname(gtype_name,
194                                                          self._names)
195         except KeyError, e:
196             return Unresolved(gtype_name)
197
198     def _create_gobject(self, node):
199         type_name = 'G' + node.name
200         if type_name == 'GObject':
201             parent_gitype = None
202             symbol = 'intern'
203         else:
204             type_id = cgobject.type_from_name(type_name)
205             parent_type_name = cgobject.type_name(
206                 cgobject.type_parent(type_id))
207             parent_gitype = self._resolve_gtypename(parent_type_name)
208             symbol = to_underscores(type_name).lower() + '_get_type'
209         node = GLibObject(node.name, parent_gitype, type_name, symbol, True)
210         type_id = cgobject.TYPE_OBJECT
211         self._introspect_properties(node, type_id)
212         self._introspect_signals(node, type_id)
213         self._add_attribute(node)
214         self._register_internal_type(type_name, node)
215
216     # Parser
217
218     def _parse_node(self, node):
219         if isinstance(node, Enum):
220             self._parse_enum(node)
221         elif isinstance(node, Function):
222             self._parse_function(node)
223         elif isinstance(node, Struct):
224             self._parse_struct(node)
225         elif isinstance(node, Callback):
226             self._parse_callback(node)
227         elif isinstance(node, Alias):
228             self._parse_alias(node)
229         elif isinstance(node, Member):
230             # FIXME: atk_misc_instance singletons
231             pass
232         elif isinstance(node, Union):
233             self._parse_union(node)
234         elif isinstance(node, Constant):
235             self._parse_constant(node)
236         else:
237             print 'GLIB Transformer: Unhandled node:', node
238
239     def _parse_alias(self, alias):
240         self._names.aliases[alias.name] = (None, alias)
241
242     def _parse_enum(self, enum):
243         self._add_attribute(enum)
244
245     def _parse_constant(self, constant):
246         self._add_attribute(constant)
247
248     def _parse_function(self, func):
249         if func.symbol in SYMBOL_BLACKLIST:
250             return
251         if func.symbol.startswith('_'):
252             return
253         for regexp in SYMBOL_BLACKLIST_RE:
254             if regexp.match(func.symbol):
255                 return
256         if self._parse_get_type_function(func):
257             return
258
259         self._add_attribute(func)
260
261     def _parse_get_type_function(self, func):
262         symbol = func.symbol
263         if not symbol.endswith('_get_type'):
264             return False
265         if self._namespace_name == 'GLib':
266             # No GObjects in GLib
267             return False
268         # GType *_get_type(void)
269         if func.retval.type.name not in ['Type',
270                                          'GType',
271                                          'GObject.Type',
272                                          'Gtk.Type']:
273             print ("Warning: *_get_type function returns '%r'"
274                    ", not GObject.Type") % (func.retval.type.name, )
275             return False
276         if func.parameters:
277             return False
278
279         if not self._libraries:
280             print "Warning: No libraries loaded, cannot call %s" % (symbol, )
281             return False
282
283         for library in self._libraries:
284             try:
285                 func = getattr(library, symbol)
286                 break
287             except AttributeError:
288                 continue
289         else:
290             print 'Warning: could not find symbol: %s' % symbol
291             name = symbol.replace('_get_type', '')
292             self._failed_types[name] = True
293             return False
294
295         func.restype = cgobject.GType
296         func.argtypes = []
297         type_id = func()
298         self._introspect_type(type_id, symbol)
299         return True
300
301     def _name_is_internal_gtype(self, giname):
302         try:
303             node = self._get_attribute(giname)
304             return isinstance(node, (GLibObject, GLibInterface,
305                                      GLibBoxed, GLibEnum, GLibFlags))
306         except KeyError, e:
307             return False
308
309     def _parse_method(self, func):
310         if not func.parameters:
311             return False
312         return self._parse_method_common(func, True)
313
314     def _parse_constructor(self, func):
315         return self._parse_method_common(func, False)
316
317     def _parse_method_common(self, func, is_method):
318         # Skip _get_type functions, we processed them
319         # already
320         if func.symbol.endswith('_get_type'):
321             return None
322         if self._namespace_name == 'GLib':
323             # No GObjects in GLib
324             return None
325
326         if not is_method:
327             target_arg = func.retval
328         else:
329             target_arg = func.parameters[0]
330
331         if is_method:
332             # Methods require their first arg to be a known class
333             # Look at the original C type (before namespace stripping), without
334             # pointers: GtkButton -> gtk_button_, so we can figure out the
335             # method name
336             argtype = target_arg.type.ctype.replace('*', '')
337             name = self._transformer.remove_prefix(argtype)
338             name_uscore = to_underscores_noprefix(name).lower()
339             name_offset = func.symbol.find(name_uscore)
340             if name_offset < 0:
341                 return None
342             prefix = func.symbol[:name_offset+len(name_uscore)]
343         else:
344             # Constructors must have _new
345             # Take everything before that as class name
346             new_idx = func.symbol.find('_new')
347             if new_idx < 0:
348                 return None
349             # Constructors don't return basic types
350             derefed = self._transformer.follow_aliases(target_arg.type.name,
351                                                        self._names)
352             if derefed in type_names:
353                 #print "NOTE: Rejecting constructor returning basic: %r" \
354                 #    % (func.symbol, )
355                 return None
356             prefix = func.symbol[:new_idx]
357
358         klass = None
359
360         def valid_matching_klass(tclass):
361             if tclass is None:
362                 return False
363             elif isinstance(klass, (GLibEnum, GLibFlags)):
364                 return False
365             elif not isinstance(tclass, (GLibObject, GLibBoxed,
366                                           GLibInterface)):
367                 return False
368             else:
369                 return True
370
371         klass = self._uscore_type_names.get(prefix)
372         if klass is None:
373             #print "NOTE: No valid matching class for likely "+\
374             #    "method or constructor: %r" % (func.symbol, )
375             return None
376         # Enums can't have ctors or methods
377         if isinstance(klass, (GLibEnum, GLibFlags)):
378             return None
379
380         # The _uscore_type_names member holds the plain GLibBoxed
381         # object; we want to actually use the struct/record associated
382         if isinstance(klass, GLibBoxed):
383             name = self._transformer.remove_prefix(klass.type_name)
384             klass = self._get_attribute(name)
385
386         if not is_method:
387             # Interfaces can't have constructors, punt to global scope
388             if isinstance(klass, GLibInterface):
389                 #print "NOTE: Rejecting constructor for"+\
390                 #    " interface type: %r" % (func.symbol, )
391                 return None
392             # TODO - check that the return type is a subclass of the
393             # class from the prefix
394             # But for now, ensure that constructor returns are always
395             # the most concrete class
396             name = self._transformer.remove_prefix(klass.type_name)
397             func.retval.type = Type(name, func.retval.type.ctype)
398
399         self._remove_attribute(func.name)
400         # Strip namespace and object prefix: gtk_window_new -> new
401         func.name = func.symbol[len(prefix)+1:]
402         if is_method:
403             # We don't need the "this" parameter
404             del func.parameters[0]
405             klass.methods.append(func)
406         else:
407             klass.constructors.append(func)
408         return func
409
410     def _parse_struct(self, struct):
411         # This is a hack, but GObject is a rather fundamental piece so.
412         internal_names = ["Object", 'InitiallyUnowned']
413         g_internal_names = ["G" + x for x in internal_names]
414         if (self._namespace_name == 'GObject' and
415             struct.name in internal_names):
416             self._create_gobject(struct)
417             return
418         elif struct.name in g_internal_names:
419             # Avoid duplicates
420             return
421         node = self._names.names.get(struct.name)
422         if node is None:
423             self._add_attribute(struct, replace=True)
424             return
425         (ns, node) = node
426         node.fields = struct.fields[:]
427
428     def _parse_union(self, union):
429         node = self._names.names.get(union.name)
430         if node is None:
431             self._add_attribute(union, replace=True)
432             return
433         (ns, node) = node
434         node.fields = union.fields[:]
435
436     def _parse_callback(self, callback):
437         self._add_attribute(callback)
438
439     def _strip_class_suffix(self, name):
440         if (name.endswith('Class') or
441             name.endswith('Iface')):
442             return name[:-5]
443         elif name.endswith('Interface'):
444             return name[:-9]
445         else:
446             return name
447
448     def _arg_is_failed(self, param):
449         ctype = self._transformer.ctype_of(param).replace('*', '')
450         uscored = to_underscores(self._strip_class_suffix(ctype)).lower()
451         if uscored in self._failed_types:
452             print "Warning: failed type: %r" % (param, )
453             return True
454         return False
455
456     def _pair_class_struct(self, maybe_class):
457         name = self._strip_class_suffix(maybe_class.name)
458         if name == maybe_class.name:
459             return
460
461         if self._arg_is_failed(maybe_class):
462             print "WARNING: deleting no-type %r" % (maybe_class.name, )
463             del self._names.names[maybe_class.name]
464             return
465
466         # Object class fields are assumed to be read-only
467         # (see also _introspect_object and transformer.py)
468         for field in maybe_class.fields:
469             if isinstance(field, Field):
470                 field.writable = False
471
472         name = self._resolve_type_name(name)
473         resolved = self._transformer.remove_prefix(name)
474         pair_class = self._get_attribute(resolved)
475         if pair_class and isinstance(pair_class,
476                                      (GLibObject, GLibInterface)):
477             for field in maybe_class.fields[1:]:
478                 pair_class.fields.append(field)
479             return
480         name = self._transformer.remove_prefix(maybe_class.name)
481         pair_class = self._get_attribute(name)
482         if pair_class and isinstance(pair_class,
483                                      (GLibObject, GLibInterface)):
484
485             del self._names.names[maybe_class.name]
486
487     # Introspection
488
489     def _introspect_type(self, type_id, symbol):
490         fundamental_type_id = cgobject.type_fundamental(type_id)
491         if (fundamental_type_id == cgobject.TYPE_ENUM or
492             fundamental_type_id == cgobject.TYPE_FLAGS):
493             self._introspect_enum(fundamental_type_id, type_id, symbol)
494         elif fundamental_type_id == cgobject.TYPE_OBJECT:
495             self._introspect_object(type_id, symbol)
496         elif fundamental_type_id == cgobject.TYPE_INTERFACE:
497             self._introspect_interface(type_id, symbol)
498         elif fundamental_type_id == cgobject.TYPE_BOXED:
499             self._introspect_boxed(type_id, symbol)
500         elif fundamental_type_id == cgobject.TYPE_BOXED:
501             self._introspect_boxed(type_id, symbol)
502         elif fundamental_type_id == cgobject.TYPE_POINTER:
503             # FIXME: Should we do something about these?
504             #        GHashTable, GValue and a few other fundamentals are
505             #        covered here
506             return
507         else:
508             print 'unhandled GType: %s(%d)' % (cgobject.type_name(type_id),
509                                                type_id)
510
511     def _introspect_enum(self, ftype_id, type_id, symbol):
512         type_class = cgobject.type_class_ref(type_id)
513         if type_class is None:
514             return
515
516         members = []
517         for enum_value in type_class.get_values():
518             members.append(GLibEnumMember(enum_value.value_nick,
519                                           enum_value.value,
520                                           enum_value.value_name,
521                                           enum_value.value_nick))
522
523         klass = (GLibFlags if ftype_id == cgobject.TYPE_FLAGS else GLibEnum)
524         type_name = cgobject.type_name(type_id)
525         enum_name = self._transformer.remove_prefix(type_name)
526         node = klass(enum_name, type_name, members, symbol)
527         self._add_attribute(node, replace=True)
528         self._register_internal_type(type_name, node)
529
530     def _introspect_object(self, type_id, symbol):
531         type_name = cgobject.type_name(type_id)
532         # We handle this specially above; in 2.16 and below there
533         # was no g_object_get_type, for later versions we need
534         # to skip it
535         if type_name == 'GObject':
536             return
537         parent_type_name = cgobject.type_name(cgobject.type_parent(type_id))
538         parent_gitype = self._resolve_gtypename(parent_type_name)
539         is_abstract = cgobject.type_is_abstract(type_id)
540         node = GLibObject(
541             self._transformer.remove_prefix(type_name),
542             parent_gitype,
543             type_name,
544             symbol, is_abstract)
545         self._introspect_properties(node, type_id)
546         self._introspect_signals(node, type_id)
547         self._introspect_implemented_interfaces(node, type_id)
548
549         # add struct fields
550         struct = self._get_attribute(node.name)
551         if struct is not None:
552             node.fields = struct.fields
553             for field in node.fields:
554                 if isinstance(field, Field):
555                     # Object instance fields are assumed to be read-only
556                     # (see also _pair_class_struct and transformer.py)
557                     field.writable = False
558
559         self._add_attribute(node, replace=True)
560         self._register_internal_type(type_name, node)
561
562     def _introspect_interface(self, type_id, symbol):
563         type_name = cgobject.type_name(type_id)
564         parent_type_name = cgobject.type_name(cgobject.type_parent(type_id))
565         if parent_type_name == 'GInterface':
566             parent_gitype = None
567         else:
568             parent_gitype = self._resolve_gtypename(parent_type_name)
569         node = GLibInterface(
570             self._transformer.remove_prefix(type_name),
571             parent_gitype,
572             type_name, symbol)
573         self._introspect_properties(node, type_id)
574         self._introspect_signals(node, type_id)
575         # GtkFileChooserEmbed is an example of a private interface, we
576         # just filter them out
577         if symbol.startswith('_'):
578             print "NOTICE: Marking %s as internal type" % (type_name, )
579             self._private_internal_types[type_name] = node
580         else:
581             self._add_attribute(node, replace=True)
582             self._register_internal_type(type_name, node)
583
584     def _introspect_boxed(self, type_id, symbol):
585         type_name = cgobject.type_name(type_id)
586         # This one doesn't go in the main namespace; we associate it with
587         # the struct or union
588         node = GLibBoxed(type_name, symbol)
589         self._boxed_types[node.type_name] = node
590         self._register_internal_type(type_name, node)
591
592     def _introspect_implemented_interfaces(self, node, type_id):
593         fundamental_type_id = cgobject.type_fundamental(type_id)
594         if fundamental_type_id != cgobject.TYPE_OBJECT:
595             raise AssertionError
596         interfaces = cgobject.type_interfaces(type_id)
597         gt_interfaces = []
598         for interface_typeid in interfaces:
599             iname = cgobject.type_name(interface_typeid)
600             gitype = self._resolve_gtypename(iname)
601             gt_interfaces.append(gitype)
602         node.interfaces = gt_interfaces
603
604     def _introspect_properties(self, node, type_id):
605         fundamental_type_id = cgobject.type_fundamental(type_id)
606         if fundamental_type_id == cgobject.TYPE_OBJECT:
607             pspecs = cgobject.object_class_list_properties(type_id)
608         elif fundamental_type_id == cgobject.TYPE_INTERFACE:
609             pspecs = cgobject.object_interface_list_properties(type_id)
610         else:
611             raise AssertionError
612
613         for pspec in pspecs:
614             if pspec.owner_type != type_id:
615                 continue
616             ctype = cgobject.type_name(pspec.value_type)
617             readable = (pspec.flags & 1) != 0
618             writable = (pspec.flags & 2) != 0
619             construct = (pspec.flags & 4) != 0
620             construct_only = (pspec.flags & 8) != 0
621             node.properties.append(Property(
622                 pspec.name,
623                 type_name_from_ctype(ctype),
624                 readable, writable, construct, construct_only,
625                 ctype,
626                 ))
627
628     def _introspect_signals(self, node, type_id):
629         for signal_info in cgobject.signal_list(type_id):
630             rtype = self._type_from_gtype(signal_info.return_type)
631             return_ = Return(rtype)
632             signal = GLibSignal(signal_info.signal_name, return_)
633             for i, parameter in enumerate(signal_info.get_params()):
634                 if i == 0:
635                     name = 'object'
636                 else:
637                     name = 'p%s' % (i-1, )
638                 ptype = self._type_from_gtype(parameter)
639                 param = Parameter(name, ptype)
640                 signal.parameters.append(param)
641             node.signals.append(signal)
642
643     # Resolver
644
645     def _resolve_type_name(self, type_name, ctype=None):
646         # Workaround glib bug #548689, to be included in 2.18.0
647         if type_name == "GParam":
648             type_name = "GObject.ParamSpec"
649
650         res = self._transformer.resolve_type_name_full
651         try:
652             return res(type_name, ctype, self._names)
653         except KeyError, e:
654             return self._transformer.resolve_type_name(type_name, ctype)
655
656     def _resolve_param_type(self, ptype, **kwargs):
657         return self._transformer.resolve_param_type_full(ptype,
658                                                          self._names,
659                                                          **kwargs)
660
661     def _resolve_node(self, node):
662         if isinstance(node, Function):
663             self._resolve_function_toplevel(node)
664
665         elif isinstance(node, Callback):
666             self._resolve_function(node)
667         elif isinstance(node, GLibObject):
668             self._resolve_glib_object(node)
669         elif isinstance(node, GLibInterface):
670             self._resolve_glib_interface(node)
671         elif isinstance(node, Struct):
672             self._resolve_struct(node)
673         elif isinstance(node, Union):
674             self._resolve_union(node)
675         elif isinstance(node, Alias):
676             self._resolve_alias(node)
677
678     def _resolve_function_toplevel(self, func):
679         newfunc = self._parse_constructor(func)
680         if not newfunc:
681             newfunc = self._parse_method(func)
682             if not newfunc:
683                 self._resolve_function(func)
684                 return
685         self._resolve_function(newfunc)
686
687     def _pair_boxed_type(self, boxed):
688         name = self._transformer.remove_prefix(boxed.type_name)
689         pair_node = self._get_attribute(name)
690         if not pair_node:
691             boxed_item = GLibBoxedOther(name, boxed.type_name,
692                                         boxed.get_type)
693         elif isinstance(pair_node, Struct):
694             boxed_item = GLibBoxedStruct(pair_node.name, boxed.type_name,
695                                          boxed.get_type)
696             boxed_item.fields = pair_node.fields
697         elif isinstance(pair_node, Union):
698             boxed_item = GLibBoxedUnion(pair_node.name, boxed.type_name,
699                                          boxed.get_type)
700             boxed_item.fields = pair_node.fields
701         else:
702             return False
703         self._add_attribute(boxed_item, replace=True)
704
705     def _resolve_struct(self, node):
706         for field in node.fields:
707             self._resolve_field(field)
708
709     def _resolve_union(self, node):
710         for field in node.fields:
711             self._resolve_field(field)
712
713     def _force_resolve(self, item, allow_unknown=False):
714         if isinstance(item, Unresolved):
715             if item.target in self._private_internal_types:
716                 return None
717             try:
718                 return self._transformer.gtypename_to_giname(item.target,
719                                                              self._names)
720             except KeyError, e:
721                 if allow_unknown:
722                     print "WARNING: Skipping unknown interface %s" % \
723                         (item.target, )
724                     return None
725                 else:
726                     raise
727         if item in self._private_internal_types:
728             return None
729         return item
730
731     def _resolve_glib_interface(self, node):
732         node.parent = self._force_resolve(node.parent)
733         self._resolve_methods(node.methods)
734         self._resolve_properties(node.properties, node)
735         self._resolve_signals(node.signals)
736
737     def _resolve_glib_object(self, node):
738         node.parent = self._force_resolve(node.parent)
739         node.interfaces = filter(None,
740             [self._force_resolve(x, allow_unknown=True)
741                                     for x in node.interfaces])
742         self._resolve_constructors(node.constructors)
743         self._resolve_methods(node.methods)
744         self._resolve_properties(node.properties, node)
745         self._resolve_signals(node.signals)
746         for field in node.fields:
747             self._resolve_field(field)
748
749     def _resolve_glib_boxed(self, node):
750         self._resolve_constructors(node.constructors)
751         self._resolve_methods(node.methods)
752
753     def _resolve_constructors(self, constructors):
754         for ctor in constructors:
755             self._resolve_function(ctor)
756
757     def _resolve_methods(self, methods):
758         for method in methods:
759             self._resolve_function(method)
760
761     def _resolve_signals(self, signals):
762         for signal in signals:
763             self._resolve_function(signal)
764
765     def _resolve_properties(self, properties, context):
766         failed = []
767         for prop in properties:
768             try:
769                 self._resolve_property(prop)
770             except KeyError, e:
771                 failed.append(prop)
772         for fail in failed:
773             print ("WARNING: Deleting object property %r (of %r)" +\
774                        "with unknown type") % (fail, context)
775             properties.remove(fail)
776
777     def _resolve_property(self, prop):
778         prop.type = self._resolve_param_type(prop.type, allow_invalid=False)
779
780     def _adjust_transfer(self, param):
781         # Do GLib/GObject-specific type transformations here
782
783         transfer = None
784         is_object = None
785         if hasattr(param.type, '_gtype'):
786             ftype = cgobject.type_fundamental(param.type._gtype)
787             assert ftype != cgobject.TYPE_INVALID, param.type._gtype
788
789             is_object = ftype in [cgobject.TYPE_OBJECT,
790                                   cgobject.TYPE_INTERFACE]
791
792             if ftype in [cgobject.TYPE_OBJECT,
793                          cgobject.TYPE_INTERFACE,
794                          cgobject.TYPE_STRING,
795                          cgobject.TYPE_BOXED,
796                          cgobject.TYPE_PARAM]:
797                 transfer = 'full'
798             else:
799                 # if type is a cgobject.TYPE_POINTER we could require direction
800                 # and transfer-ownership annotations
801                 transfer = 'none'
802
803         if is_object is None:
804             is_object = (param.type.name == 'GObject.Object' or
805                          (self._namespace_name == 'GObject' and
806                           param.type.name == 'Object'))
807
808         # Default to full transfer for GObjects
809         if isinstance(param, Parameter):
810             is_out = (param.direction != PARAM_DIRECTION_IN)
811         else:
812             is_out = True
813         if param.transfer is None or param.transfer_inferred:
814             if is_out and is_object:
815                 param.transfer = 'full'
816             elif transfer is not None:
817                 param.transfer = transfer
818
819     def _adjust_throws(self, func):
820         if func.parameters == []:
821             return
822
823         last_param = func.parameters.pop()
824
825         if (last_param.type.name == 'GLib.Error' or
826             (self._namespace_name == 'GLib' and
827              last_param.type.name == 'Error')):
828             func.throws = True
829         else:
830             func.parameters.append(last_param)
831
832     def _resolve_function(self, func):
833         self._resolve_parameters(func.parameters)
834         func.retval.type = self._resolve_param_type(func.retval.type)
835         self._adjust_throws(func)
836         self._adjust_transfer(func.retval)
837
838     def _resolve_parameters(self, parameters):
839         for parameter in parameters:
840             parameter.type = self._resolve_param_type(parameter.type)
841             self._adjust_transfer(parameter)
842
843     def _resolve_field(self, field):
844         if isinstance(field, Callback):
845             self._resolve_function(field)
846             return
847         field.type = self._resolve_param_type(field.type)
848
849     def _resolve_alias(self, alias):
850         alias.target = self._resolve_type_name(alias.target, alias.target)
851
852     # Validation
853
854     def _validate(self, nodes):
855         nodes = list(self._names.names.itervalues())
856         i = 0
857         self._validating = True
858         while True:
859             initlen = len(nodes)
860
861             print "Type resolution; pass=%d" % (i, )
862             nodes = list(self._names.names.itervalues())
863             for node in nodes:
864                 try:
865                     self._resolve_node(node)
866                 except UnknownTypeError, e:
867                     print "WARNING: %s: Deleting %r" % (e, node)
868                     self._remove_attribute(node.name)
869             if len(nodes) == initlen:
870                 break
871             i += 1
872             self._print_statistics()
873         self._validating = False