Blacklist marshaling functions
[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, Enum, Function, Member, Namespace, Parameter,
28                   Sequence, Property, Return, Struct, Type, Alias,
29                   Union, type_name_from_ctype)
30 from .transformer import Names
31 from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember, GLibFlags,
32                       GLibInterface, GLibObject, GLibSignal, type_names)
33 from .utils import extract_libtool, to_underscores
34
35
36 SYMBOL_BLACKLIST = [
37     # These ones break GError conventions
38     'g_simple_async_result_new_from_error',
39     'g_simple_async_result_set_from_error',
40     'g_simple_async_result_propagate_error',
41     'g_simple_async_result_report_error_in_idle',
42     'gtk_print_operation_get_error',
43 ]
44
45 SYMBOL_BLACKLIST_RE = [re.compile(x) for x in \
46                            [r'\w+_marshal_[A-Z]+__', ]]
47
48
49 class Unresolved(object):
50
51     def __init__(self, target):
52         self.target = target
53
54
55 class UnknownTypeError(Exception):
56     pass
57
58
59 class GLibTransformer(object):
60
61     def __init__(self, transformer, noclosure=False):
62         self._transformer = transformer
63         self._namespace_name = None
64         self._names = Names()
65         self._uscore_type_names = {}
66         self._libraries = []
67         self._failed_types = {}
68         self._private_internal_types = {}
69         self._noclosure = noclosure
70         self._validating = False
71
72     # Public API
73
74     def add_library(self, libname):
75         # For testing mainly.
76         libtool_libname = 'lib' + libname + '.la'
77         if os.path.exists(libtool_libname):
78             found_libname = extract_libtool(libtool_libname)
79         elif libname.endswith('.la'):
80             found_libname = extract_libtool(libname)
81         else:
82             found_libname = find_library(libname)
83         if not found_libname:
84             raise ValueError("Failed to find library: %r" % (libname, ))
85         self._libraries.append(ctypes.cdll.LoadLibrary(found_libname))
86
87     def _print_statistics(self):
88         nodes = list(self._names.names.itervalues())
89
90         def count_type(otype):
91             return len([x for x in nodes
92                         if isinstance(x[1], otype)])
93         objectcount = count_type(GLibObject)
94         ifacecount = count_type(GLibInterface)
95         enumcount = count_type(GLibEnum)
96         boxedcount = count_type(GLibBoxed)
97         print " %d nodes; %d objects, %d interfaces, %d enums, %d boxed" \
98             % (len(nodes), objectcount, ifacecount, enumcount, boxedcount)
99
100     def parse(self):
101         namespace = self._transformer.parse()
102         self._namespace_name = namespace.name
103
104         # First pass, parsing
105         for node in namespace.nodes:
106             self._parse_node(node)
107
108         # Introspection is done from within parsing
109
110         # Second pass, delete class structures, resolve
111         # all types we now know about
112         nodes = list(self._names.names.itervalues())
113         for (ns, node) in nodes:
114             try:
115                 self._resolve_node(node)
116             except KeyError, e:
117                 print "WARNING: DELETING node %s: %s" % (node.name, e)
118                 self._remove_attribute(node.name)
119             # associate GtkButtonClass with GtkButton
120             if isinstance(node, Struct):
121                 self._pair_class_struct(node)
122         for (ns, alias) in self._names.aliases.itervalues():
123             self._resolve_alias(alias)
124
125         self._print_statistics()
126         # Third pass; ensure all types are known
127         if not self._noclosure:
128             self._validate(nodes)
129
130         # Create a new namespace with what we found
131         namespace = Namespace(namespace.name)
132         namespace.nodes = map(lambda x: x[1], self._names.aliases.itervalues())
133         for (ns, x) in self._names.names.itervalues():
134             namespace.nodes.append(x)
135         print "Scan complete."
136         return namespace
137
138     # Private
139
140     def _add_attribute(self, node, replace=False):
141         node_name = node.name
142         if (not replace) and node_name in self._names.names:
143             return
144         self._names.names[node_name] = (None, node)
145
146     def _remove_attribute(self, name):
147         del self._names.names[name]
148
149     def _get_attribute(self, name):
150         node = self._names.names.get(name)
151         if node:
152             return node[1]
153         return None
154
155     def _register_internal_type(self, type_name, node):
156         self._names.type_names[type_name] = (None, node)
157         self._uscore_type_names[to_underscores(type_name).lower()] = node
158         # Besides the straight underscore conversion, we also try
159         # removing the underscores from the namespace as a possible C
160         # mapping; e.g. it's webkit_web_view, not web_kit_web_view
161         suffix = self._transformer.strip_namespace_object(type_name)
162         prefix = type_name[:-len(suffix)]
163         no_uscore_prefixed = (prefix + '_' + to_underscores(suffix)).lower()
164         self._uscore_type_names[no_uscore_prefixed] = node
165
166     # Helper functions
167
168     def _create_type(self, type_id):
169         ctype = cgobject.type_name(type_id)
170         type_name = type_name_from_ctype(ctype)
171         type_name = type_name.replace('*', '')
172         type_name = self._resolve_type_name(type_name)
173         return Type(type_name, ctype)
174
175     def _resolve_gtypename(self, gtype_name):
176         try:
177             return self._transformer.gtypename_to_giname(gtype_name,
178                                                          self._names)
179         except KeyError, e:
180             return Unresolved(gtype_name)
181
182     def _create_gobject(self, node):
183         type_name = 'G' + node.name
184         if type_name == 'GObject':
185             parent_gitype = None
186             symbol = 'intern'
187         else:
188             type_id = cgobject.type_from_name(type_name)
189             parent_type_name = cgobject.type_name(
190                 cgobject.type_parent(type_id))
191             parent_gitype = self._resolve_gtypename(parent_type_name)
192             symbol = to_underscores(type_name).lower() + '_get_type'
193         node = GLibObject(node.name, parent_gitype, type_name, symbol)
194         type_id = cgobject.TYPE_OBJECT
195         self._introspect_properties(node, type_id)
196         self._introspect_signals(node, type_id)
197         self._add_attribute(node)
198         self._register_internal_type(type_name, node)
199
200     # Parser
201
202     def _parse_node(self, node):
203         if isinstance(node, Enum):
204             self._parse_enum(node)
205         elif isinstance(node, Function):
206             self._parse_function(node)
207         elif isinstance(node, Struct):
208             self._parse_struct(node)
209         elif isinstance(node, Callback):
210             self._parse_callback(node)
211         elif isinstance(node, Alias):
212             self._parse_alias(node)
213         elif isinstance(node, Member):
214             # FIXME: atk_misc_instance singletons
215             pass
216         elif isinstance(node, Union):
217             self._parse_union(node)
218         else:
219             print 'GLIB Transformer: Unhandled node:', node
220
221     def _parse_alias(self, alias):
222         self._names.aliases[alias.name] = (None, alias)
223
224     def _parse_enum(self, enum):
225         self._add_attribute(enum)
226
227     def _parse_function(self, func):
228         if func.symbol in SYMBOL_BLACKLIST:
229             return
230         for regexp in SYMBOL_BLACKLIST_RE:
231             if regexp.match(func.symbol):
232                 return
233         if self._parse_get_type_function(func):
234             return
235
236         self._add_attribute(func)
237
238     def _parse_get_type_function(self, func):
239         symbol = func.symbol
240         if not symbol.endswith('_get_type'):
241             return False
242         if self._namespace_name == 'GLib':
243             # No GObjects in GLib
244             return False
245         # GType *_get_type(void)
246         # This is a bit fishy, why do we need all these aliases?
247         if func.retval.type.name not in ['Type',
248                                          'GType',
249                                          'Object.Type',
250                                          'GObject.Type',
251                                          'GObject.GType']:
252             print ("Warning: *_get_type function returns '%r'"
253                    ", not GObject.Type") % (func.retval.type.name, )
254             return False
255         if func.parameters:
256             return False
257
258         if not self._libraries:
259             print "Warning: No libraries loaded, cannot call %s" % (symbol, )
260             return False
261
262         for library in self._libraries:
263             try:
264                 func = getattr(library, symbol)
265                 break
266             except AttributeError:
267                 continue
268         else:
269             print 'Warning: could not find symbol: %s' % symbol
270             name = symbol.replace('_get_type', '')
271             self._failed_types[name] = True
272             return False
273
274         func.restype = cgobject.GType
275         func.argtypes = []
276         type_id = func()
277         self._introspect_type(type_id, symbol)
278         return True
279
280     def _name_is_internal_gtype(self, giname):
281         try:
282             node = self._get_attribute(giname)
283             return isinstance(node, (GLibObject, GLibInterface, GLibBoxed,
284                                      GLibEnum, GLibFlags))
285         except KeyError, e:
286             return False
287
288     def _parse_method(self, func):
289         if not func.parameters:
290             return False
291         return self._parse_method_common(func, True)
292
293     def _parse_constructor(self, func):
294         return self._parse_method_common(func, False)
295
296     def _parse_method_common(self, func, is_method):
297         # Skip _get_type functions, we processed them
298         # already
299         if func.symbol.endswith('_get_type'):
300             return None
301         if self._namespace_name == 'GLib':
302             # No GObjects in GLib
303             return None
304
305         if not is_method:
306             target_arg = func.retval
307         else:
308             target_arg = func.parameters[0]
309         target_arg.type = self._resolve_param_type(target_arg.type)
310
311         if is_method:
312             # Methods require their first arg to be a known class
313             # Look at the original C type (before namespace stripping), without
314             # pointers: GtkButton -> gtk_button_, so we can figure out the
315             # method name
316             argtype = target_arg.type.ctype.replace('*', '')
317             name = self._transformer.strip_namespace_object(argtype)
318             name_uscore = to_underscores(name).lower()
319             name_offset = func.symbol.find(name_uscore)
320             if name_offset < 0:
321                 return None
322             prefix = func.symbol[:name_offset+len(name_uscore)]
323         else:
324             # Constructors must have _new
325             # Take everything before that as class name
326             new_idx = func.symbol.find('_new')
327             if new_idx < 0:
328                 return None
329             # Constructors don't return basic types
330             derefed = self._transformer.follow_aliases(target_arg.type.name,
331                                                        self._names)
332             if derefed in type_names:
333                 #print "NOTE: Rejecting constructor returning basic: %r" \
334                 #    % (func.symbol, )
335                 return None
336             prefix = func.symbol[:new_idx]
337
338         klass = None
339
340         def valid_matching_klass(tclass):
341             if tclass is None:
342                 return False
343             elif isinstance(klass, (GLibEnum, GLibFlags)):
344                 return False
345             elif not isinstance(tclass, (GLibObject, GLibBoxed,
346                                          GLibInterface)):
347                 return False
348             else:
349                 return True
350
351         # First look for an exact match;
352         klass = self._uscore_type_names.get(prefix)
353         # Now try searching for a prefix as a last resort
354         if klass is None or not valid_matching_klass(klass):
355             for key in self._uscore_type_names:
356                 klass = None
357                 if key.startswith(prefix):
358                     klass = self._uscore_type_names.get(key)
359                     if valid_matching_klass(klass):
360                         break
361         if klass is None:
362             #print "NOTE: No valid matching class for likely "+\
363             #    "method or constructor: %r" % (func.symbol, )
364             return None
365         # Enums can't have ctors or methods
366         if isinstance(klass, (GLibEnum, GLibFlags)):
367             return None
368
369         if not is_method:
370             # Interfaces can't have constructors, punt to global scope
371             if isinstance(klass, GLibInterface):
372                 #print "NOTE: Rejecting constructor for"+\
373                 #    " interface type: %r" % (func.symbol, )
374                 return None
375             # TODO - check that the return type is a subclass of the
376             # class from the prefix
377
378         self._remove_attribute(func.name)
379         # Strip namespace and object prefix: gtk_window_new -> new
380         func.name = func.symbol[len(prefix)+1:]
381         if is_method:
382             klass.methods.append(func)
383         else:
384             klass.constructors.append(func)
385         return func
386
387     def _parse_struct(self, struct):
388         # This is a hack, but GObject is a rather fundamental piece so.
389         internal_names = ["Object", 'InitiallyUnowned']
390         g_internal_names = ["G" + x for x in internal_names]
391         if (self._namespace_name == 'GObject' and
392             struct.name in internal_names):
393             self._create_gobject(struct)
394             return
395         elif struct.name in g_internal_names:
396             # Avoid duplicates
397             return
398         node = self._names.names.get(struct.name)
399         if node is None:
400             self._add_attribute(struct, replace=True)
401             return
402         (ns, node) = node
403         node.fields = struct.fields[:]
404
405     def _parse_union(self, union):
406         node = self._names.names.get(union.name)
407         if node is None:
408             self._add_attribute(union, replace=True)
409             return
410         (ns, node) = node
411         node.fields = union.fields[:]
412
413     def _parse_callback(self, callback):
414         self._add_attribute(callback)
415
416     def _strip_class_suffix(self, name):
417         if (name.endswith('Class') or
418             name.endswith('Iface')):
419             return name[:-5]
420         elif name.endswith('Interface'):
421             return name[:-9]
422         else:
423             return name
424
425     def _arg_is_failed(self, param):
426         ctype = self._transformer.ctype_of(param).replace('*', '')
427         uscored = to_underscores(self._strip_class_suffix(ctype)).lower()
428         if uscored in self._failed_types:
429             print "Warning: failed type: %r" % (param, )
430             return True
431         return False
432
433     def _pair_class_struct(self, maybe_class):
434         name = self._strip_class_suffix(maybe_class.name)
435         if name == maybe_class.name:
436             return
437
438         if self._arg_is_failed(maybe_class):
439             print "WARNING: deleting no-type %r" % (maybe_class.name, )
440             del self._names.names[maybe_class.name]
441             return
442
443         name = self._resolve_type_name(name)
444         resolved = self._transformer.strip_namespace_object(name)
445         pair_class = self._get_attribute(resolved)
446         if pair_class and isinstance(pair_class,
447                                      (GLibObject, GLibBoxed, GLibInterface)):
448             for field in maybe_class.fields[1:]:
449                 pair_class.fields.append(field)
450             return
451         name = self._transformer.strip_namespace_object(maybe_class.name)
452         pair_class = self._get_attribute(name)
453         if pair_class and isinstance(pair_class,
454                                      (GLibObject, GLibBoxed, GLibInterface)):
455
456             del self._names.names[maybe_class.name]
457
458     # Introspection
459
460     def _introspect_type(self, type_id, symbol):
461         fundamental_type_id = cgobject.type_fundamental(type_id)
462         if (fundamental_type_id == cgobject.TYPE_ENUM or
463             fundamental_type_id == cgobject.TYPE_FLAGS):
464             self._introspect_enum(fundamental_type_id, type_id, symbol)
465         elif fundamental_type_id == cgobject.TYPE_OBJECT:
466             self._introspect_object(type_id, symbol)
467         elif fundamental_type_id == cgobject.TYPE_INTERFACE:
468             self._introspect_interface(type_id, symbol)
469         elif fundamental_type_id == cgobject.TYPE_BOXED:
470             self._introspect_boxed(type_id, symbol)
471         elif fundamental_type_id == cgobject.TYPE_BOXED:
472             self._introspect_boxed(type_id, symbol)
473         elif fundamental_type_id == cgobject.TYPE_POINTER:
474             # FIXME: Should we do something about these?
475             #        GHashTable, GValue and a few other fundamentals are
476             #        covered here
477             return
478         else:
479             print 'unhandled GType: %s(%d)' % (cgobject.type_name(type_id),
480                                                type_id)
481
482     def _introspect_enum(self, ftype_id, type_id, symbol):
483         type_class = cgobject.type_class_ref(type_id)
484         if type_class is None:
485             return
486
487         members = []
488         for enum_value in type_class.get_values():
489             members.append(GLibEnumMember(enum_value.value_nick,
490                                           enum_value.value,
491                                           enum_value.value_name,
492                                           enum_value.value_nick))
493
494         klass = (GLibFlags if ftype_id == cgobject.TYPE_FLAGS else GLibEnum)
495         type_name = cgobject.type_name(type_id)
496         enum_name = self._transformer.strip_namespace_object(type_name)
497         node = klass(enum_name, type_name, members, symbol)
498         self._add_attribute(node, replace=True)
499         self._register_internal_type(type_name, node)
500
501     def _introspect_object(self, type_id, symbol):
502         type_name = cgobject.type_name(type_id)
503         # We handle this specially above; in 2.16 and below there
504         # was no g_object_get_type, for later versions we need
505         # to skip it
506         if type_name == 'GObject':
507             return
508         parent_type_name = cgobject.type_name(cgobject.type_parent(type_id))
509         parent_gitype = self._resolve_gtypename(parent_type_name)
510         node = GLibObject(
511             self._transformer.strip_namespace_object(type_name),
512             parent_gitype,
513             type_name, symbol)
514         self._introspect_properties(node, type_id)
515         self._introspect_signals(node, type_id)
516         self._introspect_implemented_interfaces(node, type_id)
517         self._add_attribute(node, replace=True)
518         self._register_internal_type(type_name, node)
519
520     def _introspect_interface(self, type_id, symbol):
521         type_name = cgobject.type_name(type_id)
522         parent_type_name = cgobject.type_name(cgobject.type_parent(type_id))
523         if parent_type_name == 'GInterface':
524             parent_gitype = None
525         else:
526             parent_gitype = self._resolve_gtypename(parent_type_name)
527         node = GLibInterface(
528             self._transformer.strip_namespace_object(type_name),
529             parent_gitype,
530             type_name, symbol)
531         self._introspect_properties(node, type_id)
532         self._introspect_signals(node, type_id)
533         # GtkFileChooserEmbed is an example of a private interface, we
534         # just filter them out
535         if symbol.startswith('_'):
536             print "NOTICE: Marking %s as internal type" % (type_name, )
537             self._private_internal_types[type_name] = node
538         else:
539             self._add_attribute(node, replace=True)
540             self._register_internal_type(type_name, node)
541
542     def _introspect_boxed(self, type_id, symbol):
543         type_name = cgobject.type_name(type_id)
544         node = GLibBoxed(self._transformer.strip_namespace_object(type_name),
545                          type_name, symbol)
546         self._add_attribute(node, replace=True)
547         self._register_internal_type(type_name, node)
548
549     def _introspect_implemented_interfaces(self, node, type_id):
550         fundamental_type_id = cgobject.type_fundamental(type_id)
551         if fundamental_type_id != cgobject.TYPE_OBJECT:
552             raise AssertionError
553         interfaces = cgobject.type_interfaces(type_id)
554         gt_interfaces = []
555         for interface_typeid in interfaces:
556             iname = cgobject.type_name(interface_typeid)
557             gitype = self._resolve_gtypename(iname)
558             gt_interfaces.append(gitype)
559         node.interfaces = gt_interfaces
560
561     def _introspect_properties(self, node, type_id):
562         fundamental_type_id = cgobject.type_fundamental(type_id)
563         if fundamental_type_id == cgobject.TYPE_OBJECT:
564             pspecs = cgobject.object_class_list_properties(type_id)
565         elif fundamental_type_id == cgobject.TYPE_INTERFACE:
566             pspecs = cgobject.object_interface_list_properties(type_id)
567         else:
568             raise AssertionError
569
570         for pspec in pspecs:
571             if pspec.owner_type != type_id:
572                 continue
573             ctype = cgobject.type_name(pspec.value_type)
574             node.properties.append(Property(
575                 pspec.name,
576                 type_name_from_ctype(ctype),
577                 ctype,
578                 ))
579
580     def _introspect_signals(self, node, type_id):
581         for signal_info in cgobject.signal_list(type_id):
582             rtype = self._create_type(signal_info.return_type)
583             return_ = Return(rtype)
584             signal = GLibSignal(signal_info.signal_name, return_)
585             for i, parameter in enumerate(signal_info.get_params()):
586                 if i == 0:
587                     name = 'object'
588                 else:
589                     name = 'p%s' % (i-1, )
590                 ptype = self._create_type(parameter)
591                 param = Parameter(name, ptype)
592                 signal.parameters.append(param)
593             node.signals.append(signal)
594
595     # Resolver
596
597     def _resolve_type_name(self, type_name, ctype=None):
598         # Workaround glib bug #548689, to be included in 2.18.0
599         if type_name == "GParam":
600             type_name = "GObject.ParamSpec"
601
602         res = self._transformer.resolve_type_name_full
603         try:
604             return res(type_name, ctype, self._names)
605         except KeyError, e:
606             return self._transformer.resolve_type_name(type_name, ctype)
607
608     def _validate_type_name(self, name):
609         if name in type_names:
610             return True
611         if name.find('.') >= 0:
612             return True
613         if name in self._names.aliases:
614             return True
615         if name in self._names.names:
616             return True
617         return False
618
619     def _validate_type(self, ptype):
620         if isinstance(ptype, Sequence):
621             etype = ptype.element_type
622             if isinstance(etype, Sequence):
623                 return self._validate_type(etype)
624             return self._validate_type_name(etype)
625         return self._validate_type_name(ptype.name)
626
627     def _resolve_param_type_validate(self, ptype):
628         ptype = self._resolve_param_type(ptype)
629         if self._validating and not self._validate_type(ptype):
630             raise UnknownTypeError("Unknown type %r" % (ptype, ))
631         return ptype
632
633     def _resolve_param_type(self, ptype):
634         try:
635             return self._transformer.resolve_param_type_full(ptype,
636                                                              self._names)
637         except KeyError, e:
638             return self._transformer.resolve_param_type(ptype)
639         return ptype
640
641     def _resolve_node(self, node):
642         if isinstance(node, Function):
643             self._resolve_function_toplevel(node)
644
645         elif isinstance(node, Callback):
646             self._resolve_function(node)
647         elif isinstance(node, GLibObject):
648             self._resolve_glib_object(node)
649         elif isinstance(node, GLibInterface):
650             self._resolve_glib_interface(node)
651         elif isinstance(node, GLibBoxed):
652             self._resolve_glib_boxed(node)
653         elif isinstance(node, Struct):
654             self._resolve_struct(node)
655         elif isinstance(node, Union):
656             self._resolve_union(node)
657         elif isinstance(node, Alias):
658             self._resolve_alias(node)
659
660     def _resolve_function_toplevel(self, func):
661         newfunc = self._parse_constructor(func)
662         if not newfunc:
663             newfunc = self._parse_method(func)
664             if not newfunc:
665                 self._resolve_function(func)
666                 return
667         self._resolve_function(newfunc)
668
669     def _resolve_struct(self, node):
670         for field in node.fields:
671             self._resolve_field(field)
672
673     def _resolve_union(self, node):
674         for field in node.fields:
675             self._resolve_field(field)
676
677     def _force_resolve(self, item, allow_unknown=False):
678         if isinstance(item, Unresolved):
679             if item.target in self._private_internal_types:
680                 return None
681             try:
682                 return self._transformer.gtypename_to_giname(item.target,
683                                                              self._names)
684             except KeyError, e:
685                 if allow_unknown:
686                     print "WARNING: Skipping unknown interface %s" % \
687                         (item.target, )
688                     return None
689                 else:
690                     raise
691         if item in self._private_internal_types:
692             return None
693         return item
694
695     def _resolve_glib_interface(self, node):
696         node.parent = self._force_resolve(node.parent)
697         self._resolve_methods(node.methods)
698         self._resolve_properties(node.properties)
699         self._resolve_signals(node.signals)
700
701     def _resolve_glib_object(self, node):
702         node.parent = self._force_resolve(node.parent)
703         node.interfaces = filter(None,
704             [self._force_resolve(x, allow_unknown=True)
705                                     for x in node.interfaces])
706         self._resolve_constructors(node.constructors)
707         self._resolve_methods(node.methods)
708         self._resolve_properties(node.properties)
709         self._resolve_signals(node.signals)
710
711     def _resolve_glib_boxed(self, node):
712         self._resolve_constructors(node.constructors)
713         self._resolve_methods(node.methods)
714
715     def _resolve_constructors(self, constructors):
716         for ctor in constructors:
717             self._resolve_function(ctor)
718
719     def _resolve_methods(self, methods):
720         for method in methods:
721             self._resolve_function(method)
722
723     def _resolve_signals(self, signals):
724         for signal in signals:
725             self._resolve_function(signal)
726
727     def _resolve_properties(self, properties):
728         for prop in properties:
729             self._resolve_property(prop)
730
731     def _resolve_property(self, prop):
732         prop.type = self._resolve_param_type(prop.type)
733
734     def _resolve_function(self, func):
735         self._resolve_parameters(func.parameters)
736         func.retval.type = self._resolve_param_type(func.retval.type)
737
738     def _resolve_parameters(self, parameters):
739         for parameter in parameters:
740             parameter.type = self._resolve_param_type(parameter.type)
741
742     def _resolve_field(self, field):
743         if isinstance(field, Callback):
744             self._resolve_function(field)
745             return
746         field.type = self._resolve_param_type(field.type)
747
748     def _resolve_alias(self, alias):
749         alias.target = self._resolve_type_name(alias.target, alias.target)
750
751     # Validation
752
753     def _validate(self, nodes):
754         nodes = list(self._names.names.itervalues())
755         i = 0
756         self._validating = True
757         while True:
758             initlen = len(nodes)
759
760             print "Type resolution; pass=%d" % (i, )
761             nodes = list(self._names.names.itervalues())
762             for node in nodes:
763                 try:
764                     self._resolve_node(node)
765                 except UnknownTypeError, e:
766                     print "WARNING: %s: Deleting %r" % (e, node)
767                     self._remove_attribute(node.name)
768             if len(nodes) == initlen:
769                 break
770             i += 1
771             self._print_statistics()
772         self._validating = False