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