Add gobject-introspection.changes file
[profile/ivi/gobject-introspection.git] / giscanner / maintransformer.py
1 # -*- Mode: Python -*-
2 # Copyright (C) 2010 Red Hat, Inc.
3 #
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2 of the License, or (at your option) any later version.
8 #
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 # Lesser General Public License for more details.
13 #
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the
16 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 # Boston, MA 02111-1307, USA.
18 #
19
20 import re
21
22 from . import ast
23 from . import message
24 from .annotationparser import (TAG_VFUNC, TAG_SINCE, TAG_DEPRECATED, TAG_RETURNS,
25                                TAG_ATTRIBUTES, TAG_RENAME_TO, TAG_TYPE,
26                                TAG_UNREF_FUNC, TAG_REF_FUNC, TAG_SET_VALUE_FUNC,
27                                TAG_GET_VALUE_FUNC, TAG_VALUE)
28 from .annotationparser import (OPT_ALLOW_NONE, OPT_ARRAY, OPT_ATTRIBUTE,
29                                OPT_ELEMENT_TYPE, OPT_IN, OPT_INOUT,
30                                OPT_INOUT_ALT, OPT_OUT, OPT_SCOPE,
31                                OPT_OUT_CALLER_ALLOCATES, OPT_OUT_CALLEE_ALLOCATES,
32                                OPT_TYPE, OPT_CLOSURE, OPT_DESTROY, OPT_TRANSFER, OPT_SKIP,
33                                OPT_FOREIGN, OPT_ARRAY_FIXED_SIZE,
34                                OPT_ARRAY_LENGTH, OPT_ARRAY_ZERO_TERMINATED,
35                                OPT_CONSTRUCTOR, OPT_METHOD,
36                                OPT_TRANSFER_NONE, OPT_TRANSFER_FLOATING)
37 from .annotationparser import AnnotationParser
38 from .transformer import TransformerException
39 from .utils import to_underscores, to_underscores_noprefix
40
41 class MainTransformer(object):
42
43     def __init__(self, transformer, blocks):
44         self._transformer = transformer
45         self._blocks = blocks
46         self._namespace = transformer.namespace
47         self._uscore_type_names = {}
48
49     # Public API
50
51     def transform(self):
52         contents = list(self._namespace.itervalues())
53         if len(contents) == 0:
54             message.fatal("""Namespace is empty; likely causes are:
55 * Not including .h files to be scanned
56 * Broken --identifier-prefix
57 """)
58
59         # Some initial namespace surgery
60         self._namespace.walk(self._pass_fixup_hidden_fields)
61
62         # We have a rough tree which should have most of of the types
63         # we know about.  Let's attempt closure; walk over all of the
64         # Type() types and see if they match up with something.
65         self._namespace.walk(self._pass_type_resolution)
66
67         # Read in annotations needed early
68         self._namespace.walk(self._pass_read_annotations_early)
69
70         # Determine some default values for transfer etc.
71         # based on the current tree.
72         self._namespace.walk(self._pass_callable_defaults)
73
74         # Read in most annotations now.
75         self._namespace.walk(self._pass_read_annotations)
76
77         # Now that we've possibly seen more types from annotations,
78         # do another type resolution pass.
79         self._namespace.walk(self._pass_type_resolution)
80
81         # Generate a reverse mapping "bar_baz" -> BarBaz
82         for node in self._namespace.itervalues():
83             if isinstance(node, ast.Registered) and node.get_type is not None:
84                 self._uscore_type_names[node.c_symbol_prefix] = node
85             elif isinstance(node, (ast.Record, ast.Union)):
86                 uscored = to_underscores_noprefix(node.name).lower()
87                 self._uscore_type_names[uscored] = node
88
89         for node in list(self._namespace.itervalues()):
90             if isinstance(node, ast.Function):
91                 # Discover which toplevel functions are actually methods
92                 self._pair_function(node)
93             if isinstance(node, (ast.Class, ast.Interface)):
94                 self._pair_class_virtuals(node)
95
96         # Some annotations need to be post function pairing
97         self._namespace.walk(self._pass_read_annotations2)
98
99         # Another type resolution pass after we've parsed virtuals, etc.
100         self._namespace.walk(self._pass_type_resolution)
101
102         self._namespace.walk(self._pass3)
103
104         # TODO - merge into pass3
105         self._pair_quarks_with_enums()
106
107     # Private
108
109     def _pass_fixup_hidden_fields(self, node, chain):
110         """Hide all callbacks starting with _; the typical
111 usage is void (*_gtk_reserved1)(void);"""
112         if not isinstance(node, (ast.Class, ast.Interface,
113                                  ast.Record, ast.Union)):
114             return True
115         for field in node.fields:
116             if field is None:
117                 continue
118             if (field.name.startswith('_')
119                 and field.anonymous_node is not None
120                 and isinstance(field.anonymous_node, ast.Callback)):
121                 field.introspectable = False
122         return True
123
124     def _get_validate_parameter_name(self, parent, param_name, origin):
125         try:
126             param = parent.get_parameter(param_name)
127         except ValueError, e:
128             param = None
129         if param is None:
130             if isinstance(origin, ast.Parameter):
131                 origin_name = 'parameter %s' % (origin.argname, )
132             else:
133                 origin_name = 'return value'
134             message.log_node(
135                 message.FATAL, parent,
136                 "can't find parameter %s referenced by %s of %r"
137                 % (param_name, origin_name, parent.name))
138
139         return param.argname
140
141     def _apply_annotation_rename_to(self, node, chain, block):
142         if not block:
143             return
144         rename_to = block.get(TAG_RENAME_TO)
145         if not rename_to:
146             return
147         rename_to = rename_to.value
148         target = self._namespace.get_by_symbol(rename_to)
149         if not target:
150             message.warn_node(node,
151                 "Can't find symbol %r referenced by Rename annotation" % (
152                 rename_to, ))
153         elif target.shadowed_by:
154             message.warn_node(node,
155                 "Function %r already shadowed by %r, can't overwrite with %r" % (
156                 target.symbol,
157                 target.shadowed_by,
158                 rename_to))
159         elif target.shadows:
160             message.warn_node(node,
161                 "Function %r already shadows %r, can't multiply shadow with %r" % (
162                 target.symbol,
163                 target.shadows,
164                 rename_to))
165         else:
166             target.shadowed_by = node.name
167             node.shadows = target.name
168
169     def _apply_annotations_function(self, node, chain):
170         block = self._blocks.get(node.symbol)
171         self._apply_annotations_callable(node, chain, block)
172
173     def _pass_read_annotations_early(self, node, chain):
174         if isinstance(node, ast.Record):
175             if node.ctype is not None:
176                 block = self._blocks.get(node.ctype)
177             else:
178                 block = self._blocks.get(node.c_name)
179             self._apply_annotations_annotated(node, block)
180         return True
181
182     def _pass_callable_defaults(self, node, chain):
183         if isinstance(node, (ast.Callable, ast.Signal)):
184             for param in node.parameters:
185                 if param.transfer is None:
186                     param.transfer = self._get_transfer_default(node, param)
187             if node.retval.transfer is None:
188                 node.retval.transfer = self._get_transfer_default(node, node.retval)
189         return True
190
191     def _get_annotation_name(self, node):
192         if isinstance(node, (ast.Class, ast.Interface, ast.Record,
193                              ast.Union, ast.Enum, ast.Bitfield,
194                              ast.Callback, ast.Alias)):
195             if node.ctype is not None:
196                 return node.ctype
197             elif isinstance(node, ast.Registered) and node.gtype_name is not None:
198                 return node.gtype_name
199             return node.c_name
200         raise AssertionError("Unhandled node %r" % (node, ))
201
202     def _get_block(self, node):
203         return self._blocks.get(self._get_annotation_name(node))
204
205     def _pass_read_annotations(self, node, chain):
206         if not node.namespace:
207             return False
208         if isinstance(node, ast.Alias):
209             self._apply_annotations_alias(node, chain)
210         if isinstance(node, ast.Function):
211             self._apply_annotations_function(node, chain)
212         if isinstance(node, ast.Callback):
213             self._apply_annotations_callable(node, chain, block = self._get_block(node))
214         if isinstance(node, (ast.Class, ast.Interface, ast.Union, ast.Enum,
215                              ast.Bitfield, ast.Callback)):
216             self._apply_annotations_annotated(node, self._get_block(node))
217         if isinstance(node, (ast.Class, ast.Interface, ast.Record, ast.Union)):
218             block = self._get_block(node)
219             for field in node.fields:
220                 self._apply_annotations_field(node, block, field)
221             name = self._get_annotation_name(node)
222             section_name = 'SECTION:' + name.lower()
223             block = self._blocks.get(section_name)
224             if block:
225                 node.doc = block.comment
226         if isinstance(node, (ast.Class, ast.Interface)):
227             for prop in node.properties:
228                 self._apply_annotations_property(node, prop)
229             for sig in node.signals:
230                 self._apply_annotations_signal(node, sig)
231         if isinstance(node, ast.Class):
232             block = self._get_block(node)
233             if block:
234                 tag = block.get(TAG_UNREF_FUNC)
235                 node.unref_func = tag.value if tag else None
236                 tag = block.get(TAG_REF_FUNC)
237                 node.ref_func = tag.value if tag else None
238                 tag = block.get(TAG_SET_VALUE_FUNC)
239                 node.set_value_func = tag.value if tag else None
240                 tag = block.get(TAG_GET_VALUE_FUNC)
241                 node.get_value_func = tag.value if tag else None
242         if isinstance(node, ast.Constant):
243             self._apply_annotations_constant(node)
244         return True
245
246     def _adjust_container_type(self, parent, node, options):
247         has_element_type = OPT_ELEMENT_TYPE in options
248         has_array = OPT_ARRAY in options
249
250         if has_array:
251             self._apply_annotations_array(parent, node, options)
252         elif has_element_type:
253             self._apply_annotations_element_type(parent, node, options)
254
255         if isinstance(node.type, ast.Array):
256             self._check_array_element_type(node.type, options)
257
258     def _resolve(self, type_str, type_node=None, node=None, parent=None):
259         def grab_one(type_str, resolver, top_combiner, combiner):
260             """Return a complete type, and the trailing string part after it.
261             Use resolver() on each identifier, and combiner() on the parts of
262             each complete type. (top_combiner is used on the top-most type.)"""
263             bits = re.split(r'([,<>()])', type_str, 1)
264             first, sep, rest = [bits[0], '', ''] if (len(bits)==1) else bits
265             args = [resolver(first)]
266             if sep == '<' or sep == '(':
267                 lastsep = '>' if (sep == '<') else ')'
268                 while sep != lastsep:
269                     next, rest = grab_one(rest, resolver, combiner, combiner)
270                     args.append(next)
271                     sep, rest = rest[0], rest[1:]
272             else:
273                 rest = sep + rest
274             return top_combiner(*args), rest
275         def resolver(ident):
276             res = self._transformer.create_type_from_user_string(ident)
277             return res
278         def combiner(base, *rest):
279             if not rest:
280                 return base
281             if isinstance(base, ast.List) and len(rest) == 1:
282                 return ast.List(base.name, *rest)
283             if isinstance(base, ast.Map) and len(rest) == 2:
284                 return ast.Map(*rest)
285             message.warn(
286                 "Too many parameters in type specification %r" % (type_str, ))
287             return base
288         def top_combiner(base, *rest):
289             if type_node is not None and isinstance(type_node, ast.Type):
290                 base.is_const = type_node.is_const
291             return combiner(base, *rest)
292
293         result, rest = grab_one(type_str, resolver, top_combiner, combiner)
294         if rest:
295             message.warn("Trailing components in type specification %r" % (
296                 type_str, ))
297
298         if not result.resolved:
299             position = None
300             if parent is not None and isinstance(parent, ast.Function):
301                 text = parent.symbol
302                 position = self._get_position(parent, node)
303             else:
304                 text = type_str
305             message.warn_node(parent, "%s: Unknown type: %r" %
306                               (text, result.ctype), positions=position)
307         return result
308
309     def _resolve_toplevel(self, type_str, type_node=None, node=None, parent=None):
310         """Like _resolve(), but attempt to preserve more attributes of original type."""
311         result = self._resolve(type_str, type_node=type_node, node=node, parent=parent)
312         # If we replace a node with a new type (such as an annotated) we
313         # might lose the ctype from the original node.
314         if type_node is not None:
315             result.ctype = type_node.ctype
316         return result
317
318     def _get_position(self, func, param):
319         block = self._blocks.get(func.symbol)
320         if block:
321             if isinstance(param, ast.Parameter):
322                 tag = block.tags.get(param.argname)
323             elif isinstance(param, ast.Return):
324                 tag = block.tags.get(TAG_RETURNS)
325             else:
326                 tag = None
327
328             if tag.position:
329                 return tag.position
330
331         return block.position
332
333     def _check_array_element_type(self, array, options):
334         # GPtrArrays are allowed to contain non basic types
335         # (except enums and flags) or basic types that are
336         # as big as a gpointer
337         if array.array_type == ast.Array.GLIB_PTRARRAY and \
338            ((array.element_type in ast.BASIC_GIR_TYPES
339              and not array.element_type in ast.POINTER_TYPES) or
340             isinstance(array.element_type, ast.Enum) or
341             isinstance(array.element_type, ast.Bitfield)):
342             message.warn("invalid (element-type) for a GPtrArray, "
343                         "must be a pointer", options.position)
344
345         # GByteArrays have (element-type) guint8 by default
346         if array.array_type == ast.Array.GLIB_BYTEARRAY:
347             if array.element_type == ast.TYPE_ANY:
348                 array.element_type = ast.TYPE_UINT8
349             elif not array.element_type in [ast.TYPE_UINT8,
350                                             ast.TYPE_INT8,
351                                             ast.TYPE_CHAR]:
352                 message.warn("invalid (element-type) for a GByteArray, "
353                              "must be one of guint8, gint8 or gchar",
354                              options.position)
355
356     def _apply_annotations_array(self, parent, node, options):
357         array_opt = options.get(OPT_ARRAY)
358         if array_opt:
359             array_values = array_opt.all()
360         else:
361             array_values = {}
362
363         element_type = options.get(OPT_ELEMENT_TYPE)
364         if element_type is not None:
365             element_type_node = self._resolve(element_type.one(),
366                                               node.type, node, parent)
367         elif isinstance(node.type, ast.Array):
368             element_type_node = node.type.element_type
369         else:
370             # We're assuming here that Foo* with an (array) annotation
371             # and no (element-type) means array of Foo
372             element_type_node = node.type.clone()
373             # The element's ctype is the array's dereferenced
374             if element_type_node.ctype is not None and \
375                     element_type_node.ctype.endswith('*'):
376                 element_type_node.ctype = element_type_node.ctype[:-1]
377
378         if isinstance(node.type, ast.Array):
379             array_type = node.type.array_type
380         else:
381             array_type = None
382         container_type = ast.Array(array_type, element_type_node,
383                                ctype=node.type.ctype,
384                                is_const=node.type.is_const)
385         if OPT_ARRAY_ZERO_TERMINATED in array_values:
386             container_type.zeroterminated = array_values.get(
387                 OPT_ARRAY_ZERO_TERMINATED) == '1'
388         else:
389             container_type.zeroterminated = False
390         length = array_values.get(OPT_ARRAY_LENGTH)
391         if length is not None:
392             paramname = self._get_validate_parameter_name(parent, length, node)
393             if paramname:
394                 param = parent.get_parameter(paramname)
395                 param.direction = node.direction
396                 if param.direction == ast.PARAM_DIRECTION_OUT:
397                     param.transfer = ast.PARAM_TRANSFER_FULL
398                 container_type.length_param_name = param.argname
399         fixed = array_values.get(OPT_ARRAY_FIXED_SIZE)
400         if fixed:
401             try:
402                 container_type.size = int(fixed)
403             except ValueError:
404                 # Already warned in annotationparser.py
405                 return
406         node.type = container_type
407
408     def _apply_annotations_element_type(self, parent, node, options):
409         element_type_opt = options.get(OPT_ELEMENT_TYPE)
410         if element_type_opt is None:
411             message.warn(
412                 'element-type annotation takes at least one option, '
413                 'none given',
414                 options.position)
415             return
416
417         if isinstance(node.type, ast.List):
418             if element_type_opt.length() != 1:
419                 message.warn(
420                     'element-type annotation for a list must have exactly '
421                     'one option, not %d options' % (element_type_opt.length(), ),
422                     options.position)
423                 return
424             node.type.element_type = self._resolve(element_type_opt.one(),
425                                                    node.type, node, parent)
426         elif isinstance(node.type, ast.Map):
427             if element_type_opt.length() != 2:
428                 message.warn(
429                     'element-type annotation for a hash table must have exactly '
430                     'two options, not %d option(s)' % (element_type_opt.length(), ),
431                     options.position)
432                 return
433             element_type = element_type_opt.flat()
434             node.type.key_type = self._resolve(element_type[0],
435                                                node.type, node, parent)
436             node.type.value_type = self._resolve(element_type[1],
437                                                  node.type, node, parent)
438         elif isinstance(node.type, ast.Array):
439             if element_type_opt.length() != 1:
440                 message.warn(
441                     'element-type annotation for an array must have exactly '
442                     'one option, not %d options' % (element_type_opt.length(), ),
443                     options.position)
444                 return
445             node.type.element_type = self._resolve(element_type_opt.one(),
446                                                    node.type, node, parent)
447         else:
448             message.warn_node(parent,
449                 "Unknown container %r for element-type annotation" % (node.type, ))
450
451     def _get_transfer_default_param(self, parent, node):
452         if node.direction in [ast.PARAM_DIRECTION_INOUT,
453                               ast.PARAM_DIRECTION_OUT]:
454             if node.caller_allocates:
455                 return ast.PARAM_TRANSFER_NONE
456             return ast.PARAM_TRANSFER_FULL
457         return ast.PARAM_TRANSFER_NONE
458
459     def _get_transfer_default_returntype_basic(self, typeval):
460         if (typeval.is_equiv(ast.BASIC_GIR_TYPES)
461             or typeval.is_const
462             or typeval.is_equiv(ast.TYPE_NONE)):
463             return ast.PARAM_TRANSFER_NONE
464         elif typeval.is_equiv(ast.TYPE_STRING):
465             # Non-const strings default to FULL
466             return ast.PARAM_TRANSFER_FULL
467         elif typeval.target_fundamental:
468             # This looks like just GType right now
469             return None
470         return None
471
472     def _is_gi_subclass(self, typeval, supercls_type):
473         cls = self._transformer.lookup_typenode(typeval)
474         assert cls, str(typeval)
475         supercls = self._transformer.lookup_typenode(supercls_type)
476         assert supercls
477         if cls is supercls:
478             return True
479         if cls.parent and cls.parent.target_giname != 'GObject.Object':
480             return self._is_gi_subclass(cls.parent, supercls_type)
481         return False
482
483     def _get_transfer_default_return(self, parent, node):
484         typeval = node.type
485         basic = self._get_transfer_default_returntype_basic(typeval)
486         if basic:
487             return basic
488         if not typeval.target_giname:
489             return None
490         target = self._transformer.lookup_typenode(typeval)
491         if isinstance(target, ast.Alias):
492             return self._get_transfer_default_returntype_basic(target.target)
493         elif (isinstance(target, ast.Boxed)
494               or (isinstance(target, (ast.Record, ast.Union))
495                   and (target.gtype_name is not None or target.foreign))):
496             return ast.PARAM_TRANSFER_FULL
497         elif isinstance(target, (ast.Enum, ast.Bitfield)):
498             return ast.PARAM_TRANSFER_NONE
499         # Handle constructors specially here
500         elif isinstance(parent, ast.Function) and parent.is_constructor:
501             if isinstance(target, ast.Class):
502                 initially_unowned_type = ast.Type(target_giname='GObject.InitiallyUnowned')
503                 initially_unowned = self._transformer.lookup_typenode(initially_unowned_type)
504                 if initially_unowned and self._is_gi_subclass(typeval, initially_unowned_type):
505                     return ast.PARAM_TRANSFER_NONE
506                 else:
507                     return ast.PARAM_TRANSFER_FULL
508             elif isinstance(target, (ast.Record, ast.Union)):
509                 return ast.PARAM_TRANSFER_FULL
510             else:
511                 raise AssertionError("Invalid constructor")
512         elif isinstance(target, (ast.Class, ast.Record, ast.Union)):
513             # Explicitly no default for these
514             return None
515         else:
516             return None
517
518     def _get_transfer_default(self, parent, node):
519         if node.type.is_equiv(ast.TYPE_NONE) or isinstance(node.type, ast.Varargs):
520             return ast.PARAM_TRANSFER_NONE
521         elif isinstance(node, ast.Parameter):
522             return self._get_transfer_default_param(parent, node)
523         elif isinstance(node, ast.Return):
524             return self._get_transfer_default_return(parent, node)
525         elif isinstance(node, ast.Field):
526             return ast.PARAM_TRANSFER_NONE
527         elif isinstance(node, ast.Property):
528             return ast.PARAM_TRANSFER_NONE
529         else:
530             raise AssertionError(node)
531
532     def _apply_annotations_param_ret_common(self, parent, node, tag):
533         options = getattr(tag, 'options', {})
534
535         param_type = options.get(OPT_TYPE)
536         if param_type:
537             node.type = self._resolve_toplevel(param_type.one(),
538                                                node.type, node, parent)
539
540         caller_allocates = False
541         annotated_direction = None
542         if (OPT_INOUT in options or
543             OPT_INOUT_ALT in options):
544             annotated_direction = ast.PARAM_DIRECTION_INOUT
545         elif OPT_OUT in options:
546             subtype = options[OPT_OUT]
547             if subtype is not None:
548                 subtype = subtype.one()
549             annotated_direction = ast.PARAM_DIRECTION_OUT
550             if subtype in (None, ''):
551                 if node.type.target_giname and node.type.ctype:
552                     target = self._transformer.lookup_giname(node.type.target_giname)
553                     target = self._transformer.resolve_aliases(target)
554                     has_double_indirection = '**' in node.type.ctype
555                     is_structure_or_union = isinstance(target, (ast.Record, ast.Union))
556                     caller_allocates = (not has_double_indirection and is_structure_or_union)
557                 else:
558                     caller_allocates = False
559             elif subtype == OPT_OUT_CALLER_ALLOCATES:
560                 caller_allocates = True
561             elif subtype == OPT_OUT_CALLEE_ALLOCATES:
562                 caller_allocates = False
563         elif OPT_IN in options:
564             annotated_direction = ast.PARAM_DIRECTION_IN
565
566         if (annotated_direction is not None) and (annotated_direction != node.direction):
567             node.direction = annotated_direction
568             node.caller_allocates = caller_allocates
569             # Also reset the transfer default if we're toggling direction
570             node.transfer = self._get_transfer_default(parent, node)
571
572         transfer_tag = options.get(OPT_TRANSFER)
573         if transfer_tag and transfer_tag.length() == 1:
574             transfer = transfer_tag.one()
575             if transfer == OPT_TRANSFER_FLOATING:
576                 transfer = OPT_TRANSFER_NONE
577             node.transfer = transfer
578
579         self._adjust_container_type(parent, node, options)
580
581         if (OPT_ALLOW_NONE in options or
582             node.type.target_giname == 'Gio.AsyncReadyCallback' or
583             node.type.target_giname == 'Gio.Cancellable'):
584             node.allow_none = True
585
586         if tag is not None and tag.comment is not None:
587             node.doc = tag.comment
588
589         if OPT_SKIP in options:
590             node.skip = True
591
592         if options:
593             for attribute in options.getall(OPT_ATTRIBUTE):
594                 node.attributes.append(attribute.flat())
595
596     def _apply_annotations_annotated(self, node, block):
597         if block is None:
598             return
599
600         node.doc = block.comment
601
602         since_tag = block.get(TAG_SINCE)
603         if since_tag is not None:
604             node.version = since_tag.value
605
606         deprecated_tag = block.get(TAG_DEPRECATED)
607         if deprecated_tag is not None:
608             value = deprecated_tag.value
609             if ': ' in value:
610                 version, desc = value.split(': ')
611             else:
612                 desc = value
613                 version = None
614             node.deprecated = desc
615             if version is not None:
616                 node.deprecated_version = version
617
618         annos_tag = block.get(TAG_ATTRIBUTES)
619         if annos_tag is not None:
620             options = AnnotationParser.parse_options(annos_tag, annos_tag.value)
621             for key, value in options.iteritems():
622                 if value:
623                     node.attributes.append((key, value.one()))
624
625         if OPT_SKIP in block.options:
626             node.skip = True
627
628         if OPT_FOREIGN in block.options:
629             node.foreign = True
630
631         if OPT_CONSTRUCTOR in block.options and isinstance(node, ast.Function):
632             node.is_constructor = True
633
634         if OPT_METHOD in block.options:
635             node.is_method = True
636
637     def _apply_annotations_alias(self, node, chain):
638         block = self._get_block(node)
639         self._apply_annotations_annotated(node, block)
640
641     def _apply_annotations_param(self, parent, param, tag):
642         if tag:
643             options = tag.options
644         else:
645             options = {}
646         if isinstance(parent, (ast.Function, ast.VFunction)):
647             scope = options.get(OPT_SCOPE)
648             if scope and scope.length() == 1:
649                 param.scope = scope.one()
650                 param.transfer = ast.PARAM_TRANSFER_NONE
651
652             destroy = options.get(OPT_DESTROY)
653             if destroy:
654                 param.destroy_name = self._get_validate_parameter_name(parent,
655                                                                        destroy.one(),
656                                                                        param)
657                 if param.destroy_name is not None:
658                     param.scope = ast.PARAM_SCOPE_NOTIFIED
659                     destroy_param = parent.get_parameter(param.destroy_name)
660                     # This is technically bogus; we're setting the scope on the destroy
661                     # itself.  But this helps avoid tripping a warning from finaltransformer,
662                     # since we don't have a way right now to flag this callback a destroy.
663                     destroy_param.scope = ast.PARAM_SCOPE_NOTIFIED
664             closure = options.get(OPT_CLOSURE)
665             if closure and closure.length() == 1:
666                 param.closure_name = self._get_validate_parameter_name(parent,
667                                                                        closure.one(),
668                                                                        param)
669         elif isinstance(parent, ast.Callback):
670             if OPT_CLOSURE in options:
671                 # For callbacks, (closure) appears without an
672                 # argument, and tags a parameter that is a closure. We
673                 # represent it (weirdly) in the gir and typelib by
674                 # setting param.closure_name to itself.
675                 param.closure_name = param.argname
676
677         self._apply_annotations_param_ret_common(parent, param, tag)
678
679     def _apply_annotations_return(self, parent, return_, block):
680         if block:
681             tag = block.get(TAG_RETURNS)
682         else:
683             tag = None
684         self._apply_annotations_param_ret_common(parent, return_, tag)
685
686     def _apply_annotations_params(self, parent, params, block):
687         declparams = set([])
688         if parent.instance_parameter:
689             declparams.add(parent.instance_parameter.argname)
690         for param in params:
691             if block:
692                 tag = block.get(param.argname)
693             else:
694                 tag = None
695             self._apply_annotations_param(parent, param, tag)
696             declparams.add(param.argname)
697
698         if not block:
699             return
700         docparams = set(block.params)
701
702         unknown = docparams - declparams
703         unused = declparams - docparams
704
705         for doc_name in unknown:
706             # Skip varargs, see #629759
707             if doc_name.lower() in ['...', 'varargs', TAG_RETURNS]:
708                 continue
709             if len(unused) == 0:
710                 text = ''
711             elif len(unused) == 1:
712                 (param, ) = unused
713                 text = ', should be %r' % (param, )
714             else:
715                 text = ', should be one of %s' % (
716                 ', '.join(repr(p) for p in unused), )
717
718             tag = block.get(doc_name)
719             message.warn(
720                 '%s: unknown parameter %r in documentation comment%s' % (
721                 block.name, doc_name, text),
722                 tag.position)
723
724     def _apply_annotations_callable(self, node, chain, block):
725         self._apply_annotations_annotated(node, block)
726         self._apply_annotations_params(node, node.parameters, block)
727         self._apply_annotations_return(node, node.retval, block)
728
729     def _check_arg_annotations(self, parent, params, block):
730         if block is None:
731             return
732         for tag in block.tags.keys():
733             if tag == TAG_RETURNS:
734                 continue
735             for param in params:
736                 if param.argname == tag:
737                     break
738             else:
739                 message.warn(
740                     "Annotation for '%s' refers to unknown argument '%s'"
741                     % (parent.name, tag))
742
743     def _apply_annotations_field(self, parent, block, field):
744         if not block:
745             return
746         tag = block.get(field.name)
747         if not tag:
748             return
749         t = tag.options.get(OPT_TYPE)
750         if t:
751             field.type = self._transformer.create_type_from_user_string(t.one())
752
753         try:
754             self._adjust_container_type(parent, field, tag.options)
755         except AttributeError:
756             pass
757
758     def _apply_annotations_property(self, parent, prop):
759         prefix = self._get_annotation_name(parent)
760         block = self._blocks.get('%s:%s' % (prefix, prop.name))
761         self._apply_annotations_annotated(prop, block)
762         if not block:
763             return
764         transfer_tag = block.get(OPT_TRANSFER)
765         if transfer_tag is not None:
766             transfer = transfer_tag.value
767             if transfer == OPT_TRANSFER_FLOATING:
768                 transfer = OPT_TRANSFER_NONE
769             prop.transfer = transfer
770         else:
771             prop.transfer = self._get_transfer_default(parent, prop)
772         type_tag = block.get(TAG_TYPE)
773         if type_tag:
774             prop.type = self._resolve_toplevel(type_tag.value, prop.type, prop, parent)
775
776     def _apply_annotations_signal(self, parent, signal):
777         prefix = self._get_annotation_name(parent)
778         block = self._blocks.get('%s::%s' % (prefix, signal.name))
779         self._apply_annotations_annotated(signal, block)
780         # We're only attempting to name the signal parameters if
781         # the number of parameter tags (@foo) is the same or greater
782         # than the number of signal parameters
783         if block and len(block.tags) > len(signal.parameters):
784             names = block.tags.items()
785             # Resolve real parameter names early, so that in later
786             # phase we can refer to them while resolving annotations.
787             for i, param in enumerate(signal.parameters):
788                 param.argname, tag = names[i+1]
789         else:
790             names = []
791         for i, param in enumerate(signal.parameters):
792             if names:
793                 name, tag = names[i+1]
794                 options = getattr(tag, 'options', {})
795                 param_type = options.get(OPT_TYPE)
796                 if param_type:
797                     param.type = self._resolve_toplevel(param_type.one(), param.type,
798                                                         param, parent)
799             else:
800                 tag = None
801             self._apply_annotations_param(signal, param, tag)
802         self._apply_annotations_return(signal, signal.retval, block)
803
804     def _apply_annotations_constant(self, node):
805         block = self._blocks.get(node.ctype)
806         if not block:
807             return
808         tag = block.get(TAG_VALUE)
809         if tag:
810             node.value = tag.value
811
812     def _pass_read_annotations2(self, node, chain):
813         if isinstance(node, ast.Function):
814             self._apply_annotations2_function(node, chain)
815         return True
816
817     def _apply_annotations2_function(self, node, chain):
818         block = self._blocks.get(node.symbol)
819
820         self._apply_annotation_rename_to(node, chain, block)
821
822         # Handle virtual invokers
823         parent = chain[-1] if chain else None
824         if not (block and parent):
825             return
826         virtual = block.get(TAG_VFUNC)
827         if not virtual:
828             return
829         invoker_name = virtual.value
830         matched = False
831         for vfunc in parent.virtual_methods:
832             if vfunc.name == invoker_name:
833                 matched = True
834                 vfunc.invoker = node.name
835                 # Also merge in annotations
836                 self._apply_annotations_callable(vfunc, [parent], block)
837                 break
838         if not matched:
839             message.warn_node(node,
840                 "Virtual slot %r not found for %r annotation" % (invoker_name, TAG_VFUNC))
841
842     def _resolve_and_filter_type_list(self, typelist):
843         """Given a list of Type instances, return a new list of types with
844 the ones that failed to resolve removed."""
845         # Create a copy we'll modify
846         new_typelist = list(typelist)
847         for typeval in typelist:
848             resolved = self._transformer.resolve_type(typeval)
849             if not resolved:
850                 new_typelist.remove(typeval)
851         return new_typelist
852
853     def _pass_type_resolution(self, node, chain):
854         if isinstance(node, ast.Alias):
855             self._transformer.resolve_type(node.target)
856         if isinstance(node, ast.Callable):
857             for parameter in node.parameters:
858                 self._transformer.resolve_type(parameter.type)
859             self._transformer.resolve_type(node.retval.type)
860         if isinstance(node, ast.Constant):
861             self._transformer.resolve_type(node.value_type)
862         if isinstance(node, (ast.Class, ast.Interface, ast.Record, ast.Union)):
863             for field in node.fields:
864                 if field.anonymous_node:
865                     pass
866                 else:
867                     self._transformer.resolve_type(field.type)
868         if isinstance(node, (ast.Class, ast.Interface)):
869             resolved_parent = None
870             for parent in node.parent_chain:
871                 try:
872                     self._transformer.resolve_type(parent)
873                 except ValueError, e:
874                     continue
875                 target = self._transformer.lookup_typenode(parent)
876                 if target:
877                     node.parent = parent
878                     break
879             else:
880                 if isinstance(node, ast.Interface):
881                     node.parent = ast.Type(target_giname='GObject.Object')
882             for prop in node.properties:
883                 self._transformer.resolve_type(prop.type)
884             for sig in node.signals:
885                 for param in sig.parameters:
886                     self._transformer.resolve_type(param.type)
887         if isinstance(node, ast.Class):
888             node.interfaces = self._resolve_and_filter_type_list(node.interfaces)
889         if isinstance(node, ast.Interface):
890             node.prerequisites = self._resolve_and_filter_type_list(node.prerequisites)
891         return True
892
893     def _pair_quarks_with_enums(self):
894         # self._uscore_type_names is an authoritative mapping of types
895         # to underscored versions, since it is based on get_type() methods;
896         # but only covers enums that are registered as GObject enums.
897         # Create a fallback mapping based on all known enums in this module.
898         uscore_enums = {}
899         for enum in self._namespace.itervalues():
900             if not isinstance(enum, ast.Enum):
901                 continue
902             type_name = enum.ctype
903             uscored = to_underscores(type_name).lower()
904
905             uscore_enums[uscored] = enum
906
907             try:
908                 no_uscore_prefixed = self._transformer.strip_identifier(type_name)
909             except TransformerException, e:
910                 message.warn(e)
911                 no_uscore_prefixed = None
912
913             if no_uscore_prefixed not in uscore_enums:
914                 uscore_enums[no_uscore_prefixed] = enum
915
916         for node in self._namespace.itervalues():
917             if not isinstance(node, ast.ErrorQuarkFunction):
918                 continue
919             short = node.symbol[:-len('_quark')]
920             if short == "g_io_error":
921                 # Special case; GIOError was already taken forcing GIOErrorEnum
922                 assert self._namespace.name == 'Gio'
923                 enum = self._namespace.get('IOErrorEnum')
924             else:
925                 enum = self._uscore_type_names.get(short)
926                 if enum is None:
927                     enum = uscore_enums.get(short)
928             if enum is not None:
929                 enum.error_domain = node.error_domain
930             else:
931                 message.warn_node(node,
932                     """%s: Couldn't find corresponding enumeration""" % (node.symbol, ))
933
934     def _split_uscored_by_type(self, uscored):
935         """'uscored' should be an un-prefixed uscore string.  This
936 function searches through the namespace for the longest type which
937 prefixes uscored, and returns (type, suffix).  Example, assuming
938 namespace Gtk, type is TextBuffer:
939
940 _split_uscored_by_type(text_buffer_try_new) -> (ast.Class(TextBuffer), 'try_new')"""
941         node = None
942         count = 0
943         prev_split_count = -1
944         while True:
945             components = uscored.rsplit('_', count)
946             if len(components) == prev_split_count:
947                 return None
948             prev_split_count = len(components)
949             type_string = components[0]
950             node = self._uscore_type_names.get(type_string)
951             if node:
952                 return (node, '_'.join(components[1:]))
953             count += 1
954
955     def _pair_function(self, func):
956         """Check to see whether a toplevel function should be a
957 method or constructor of some type."""
958
959         # Ignore internal symbols and type metadata functions
960         if func.symbol.startswith('_') or func.is_type_meta_function():
961             return
962
963         (ns, subsymbol) = self._transformer.split_csymbol(func.symbol)
964         assert ns == self._namespace
965         if self._is_constructor(func, subsymbol):
966             self._set_up_constructor(func, subsymbol)
967             return
968         elif self._is_method(func, subsymbol):
969             self._setup_method(func, subsymbol)
970             return
971         elif self._pair_static_method(func, subsymbol):
972             return
973
974     def _uscored_identifier_for_type(self, typeval):
975         """Given a Type(target_giname='Foo.BarBaz'), return 'bar_baz'."""
976         name = typeval.get_giname()
977         return to_underscores_noprefix(name).lower()
978
979     def _is_method(self, func, subsymbol):
980         if not func.parameters:
981             if func.is_method:
982                 message.warn_node(func,
983                     '%s: Methods must have parameters' % (func.symbol, ))
984             return False
985         first = func.parameters[0]
986         target = self._transformer.lookup_typenode(first.type)
987         if not isinstance(target, (ast.Class, ast.Interface,
988                                    ast.Record, ast.Union,
989                                    ast.Boxed)):
990             if func.is_method:
991                 message.warn_node(func,
992                     '%s: Methods must have a pointer as their first '
993                     'parameter' % (func.symbol, ))
994             return False
995         if target.namespace != self._namespace:
996             if func.is_method:
997                 message.warn_node(func,
998                     '%s: Methods must belong to the same namespace as the '
999                     'class they belong to' % (func.symbol, ))
1000             return False
1001
1002         # A quick hack here...in the future we should catch C signature/GI signature
1003         # mismatches in a general way in finaltransformer
1004         if first.type.ctype is not None and first.type.ctype.count('*') > 1:
1005             return False
1006
1007         if not func.is_method:
1008             uscored_prefix = self._get_uscored_prefix(func, subsymbol)
1009             if not subsymbol.startswith(uscored_prefix):
1010                 return False
1011
1012         return True
1013
1014     def _setup_method(self, func, subsymbol):
1015         uscored_prefix = self._get_uscored_prefix(func, subsymbol)
1016         target = self._transformer.lookup_typenode(func.parameters[0].type)
1017
1018         func.instance_parameter = func.parameters.pop(0)
1019         self._namespace.float(func)
1020
1021         if not func.is_method:
1022             subsym_idx = func.symbol.find(subsymbol)
1023             func.name = func.symbol[(subsym_idx + len(uscored_prefix) + 1):]
1024             func.is_method = True
1025
1026         target.methods.append(func)
1027
1028     def _get_uscored_prefix(self, func, subsymbol):
1029         # Here we check both the c_symbol_prefix and (if that fails),
1030         # attempt to do a default uscoring of the type.  The reason we
1031         # look at a default underscore transformation is for
1032         # gdk_window_object_get_type(), which says to us that the
1033         # prefix is "gdk_window_object", when really it's just
1034         # "gdk_window".  Possibly need an annotation to override this.
1035         prefix_matches = False
1036         uscored_prefix = None
1037         first_arg = func.parameters[0]
1038         target = self._transformer.lookup_typenode(first_arg.type)
1039         if hasattr(target, 'c_symbol_prefix') and target.c_symbol_prefix is not None:
1040             prefix_matches = subsymbol.startswith(target.c_symbol_prefix)
1041             if prefix_matches:
1042                 uscored_prefix = target.c_symbol_prefix
1043         if not prefix_matches:
1044             uscored_prefix = self._uscored_identifier_for_type(first_arg.type)
1045
1046         return uscored_prefix
1047
1048     def _pair_static_method(self, func, subsymbol):
1049         split = self._split_uscored_by_type(subsymbol)
1050         if split is None:
1051             return False
1052         (node, funcname) = split
1053         if funcname == '':
1054             return False
1055
1056         if isinstance(node, ast.Class):
1057             self._namespace.float(func)
1058             func.name = funcname
1059             node.static_methods.append(func)
1060             return True
1061         elif isinstance(node, (ast.Interface, ast.Record, ast.Union,
1062                                ast.Boxed, ast.Enum, ast.Bitfield)):
1063             # prior to the introduction of this part of the code, only
1064             # ast.Class could have static methods.  so for backwards
1065             # compatibility, instead of removing the func from the namespace,
1066             # leave it there and get a copy instead.  modify the copy and push
1067             # it onto static_methods.  we need to copy the parameters list
1068             # separately, because in the third pass functions are flagged as
1069             # 'throws' depending on the presence of a GError parameter which is
1070             # then removed from the parameters list.  without the explicit
1071             # copy, only one of the two functions would thus get flagged as
1072             # 'throws'.  clone() does this for us.
1073             new_func = func.clone()
1074             new_func.name = funcname
1075             node.static_methods.append(new_func)
1076             # flag the func as a backwards-comptability kludge (thus it will
1077             # get pruned in the introspectable pass if introspectable=0).
1078             func.moved_to = node.name + '.' + new_func.name
1079             return True
1080
1081         return False
1082
1083     def _set_up_constructor(self, func, subsymbol):
1084         self._namespace.float(func)
1085
1086         func.name = self._get_constructor_name(func, subsymbol)
1087
1088         origin_node = self._get_constructor_class(func, subsymbol)
1089         origin_node.constructors.append(func)
1090
1091         func.is_constructor = True
1092
1093         # Constructors have default return semantics
1094         if not func.retval.transfer:
1095             func.retval.transfer = self._get_transfer_default_return(func,
1096                     func.retval)
1097
1098     def _get_constructor_class(self, func, subsymbol):
1099         origin_node = None
1100         split = self._split_uscored_by_type(subsymbol)
1101         if split is None:
1102             if func.is_constructor:
1103                 origin_node = self._transformer.lookup_typenode(func.retval.type)
1104         else:
1105             origin_node, _ = split
1106
1107         return origin_node
1108
1109     def _get_constructor_name(self, func, subsymbol):
1110         name = None
1111         split = self._split_uscored_by_type(subsymbol)
1112         if split is None:
1113             if func.is_constructor:
1114                 name = func.name
1115         else:
1116             _, name = split
1117
1118         return name
1119
1120     def _guess_constructor_by_name(self, symbol):
1121         # Normal constructors, gtk_button_new etc
1122         if symbol.endswith('_new'):
1123             return True
1124         # Alternative constructor, gtk_button_new_with_label
1125         if '_new_' in symbol:
1126             return True
1127         # gtk_list_store_newv,gtk_tree_store_newv etc
1128         if symbol.endswith('_newv'):
1129             return True
1130         return False
1131
1132     def _is_constructor(self, func, subsymbol):
1133         # func.is_constructor will be True if we have a (constructor) annotation
1134         if not func.is_constructor:
1135             if not self._guess_constructor_by_name(func.symbol):
1136                 return False
1137         target = self._transformer.lookup_typenode(func.retval.type)
1138         if not (isinstance(target, ast.Class)
1139                 or (isinstance(target, (ast.Record, ast.Union, ast.Boxed))
1140                     and (target.get_type is not None or target.foreign))):
1141             if func.is_constructor:
1142                 message.warn_node(func,
1143                     '%s: Constructors must return an instance of their class'
1144                     % (func.symbol, ))
1145             return False
1146
1147         origin_node = self._get_constructor_class(func, subsymbol)
1148         if origin_node is None:
1149             message.warn_node(func,
1150                 "Can't find matching type for constructor; symbol=%r" \
1151                 % (func.symbol, ))
1152             return False
1153
1154         # Some sanity checks; only objects and boxeds can have ctors
1155         if not (isinstance(origin_node, ast.Class)
1156                 or (isinstance(origin_node, (ast.Record, ast.Union, ast.Boxed))
1157                     and (origin_node.get_type is not None or origin_node.foreign))):
1158             return False
1159         # Verify the namespace - don't want to append to foreign namespaces!
1160         if origin_node.namespace != self._namespace:
1161             if func.is_constructor:
1162                 message.warn_node(func,
1163                     '%s: Constructors must belong to the same namespace as the '
1164                     'class they belong to' % (func.symbol, ))
1165             return False
1166         # If it takes the object as a first arg, guess it's not a constructor
1167         if not func.is_constructor and len(func.parameters) > 0:
1168             first_arg = self._transformer.lookup_typenode(func.parameters[0].type)
1169             if (first_arg is not None) and first_arg.gi_name == origin_node.gi_name:
1170                 return False
1171
1172         if isinstance(target, ast.Class):
1173             parent = origin_node
1174             while parent and (not parent.gi_name == 'GObject.Object'):
1175                 if parent == target:
1176                     break
1177                 if parent.parent:
1178                     parent = self._transformer.lookup_typenode(parent.parent)
1179                 else:
1180                     parent = None
1181                 if parent is None:
1182                     message.warn_node(func,
1183                         "Return value is not superclass for constructor; "
1184                         "symbol=%r constructed=%r return=%r" % (
1185                         func.symbol,
1186                         str(origin_node.create_type()),
1187                         str(func.retval.type)))
1188                     return False
1189         else:
1190             if origin_node != target:
1191                 message.warn_node(func,
1192                     "Constructor return type mismatch symbol=%r "
1193                     "constructed=%r return=%r" % (
1194                     func.symbol,
1195                     str(origin_node.create_type()),
1196                     str(func.retval.type)))
1197                 return False
1198
1199         return True
1200
1201     def _pair_class_virtuals(self, node):
1202         """Look for virtual methods from the class structure."""
1203         if not node.glib_type_struct:
1204             # https://bugzilla.gnome.org/show_bug.cgi?id=629080
1205             #message.warn_node(node,
1206             #    "Failed to find class structure for %r" % (node.name, ))
1207             return
1208
1209         node_type = node.create_type()
1210         class_struct = self._transformer.lookup_typenode(node.glib_type_struct)
1211
1212         # Object class fields are assumed to be read-only
1213         # (see also _introspect_object and transformer.py)
1214         for field in class_struct.fields:
1215             if isinstance(field, ast.Field):
1216                 field.writable = False
1217
1218         for field in class_struct.fields:
1219             if not isinstance(field.anonymous_node, ast.Callback):
1220                 continue
1221             callback = field.anonymous_node
1222             # Check the first parameter is the object
1223             if len(callback.parameters) == 0:
1224                 continue
1225             firstparam_type = callback.parameters[0].type
1226             if firstparam_type != node_type:
1227                 continue
1228             vfunc = ast.VFunction.from_callback(callback)
1229             vfunc.instance_parameter = callback.parameters[0]
1230             vfunc.inherit_file_positions(callback)
1231
1232             prefix = self._get_annotation_name(class_struct)
1233             block = self._blocks.get('%s::%s' % (prefix, vfunc.name))
1234             self._apply_annotations_callable(vfunc, [node], block)
1235             node.virtual_methods.append(vfunc)
1236
1237         # Take the set of virtual methods we found, and try
1238         # to pair up with any matching methods using the
1239         # name+signature.
1240         for vfunc in node.virtual_methods:
1241             for method in node.methods:
1242                 if method.name != vfunc.name:
1243                     continue
1244                 if method.retval.type != vfunc.retval.type:
1245                     continue
1246                 if len(method.parameters) != len(vfunc.parameters):
1247                     continue
1248                 for i in xrange(len(method.parameters)):
1249                     m_type = method.parameters[i].type
1250                     v_type = vfunc.parameters[i].type
1251                     if m_type != v_type:
1252                         continue
1253                 vfunc.invoker = method.name
1254                 # Apply any annotations we have from the invoker to
1255                 # the vfunc
1256                 block = self._blocks.get(method.symbol)
1257                 self._apply_annotations_callable(vfunc, [], block)
1258                 break
1259
1260     def _pass3(self, node, chain):
1261         """Pass 3 is after we've loaded GType data and performed type
1262         closure."""
1263         if isinstance(node, ast.Callable):
1264             self._pass3_callable_callbacks(node)
1265             self._pass3_callable_throws(node)
1266         return True
1267
1268     def _pass3_callable_callbacks(self, node):
1269         """Check to see if we have anything that looks like a
1270         callback+user_data+GDestroyNotify set."""
1271
1272         params = node.parameters
1273
1274         # First, do defaults for well-known callback types
1275         for i, param in enumerate(params):
1276             argnode = self._transformer.lookup_typenode(param.type)
1277             if isinstance(argnode, ast.Callback):
1278                 if param.type.target_giname in ('Gio.AsyncReadyCallback',
1279                                                 'GLib.DestroyNotify'):
1280                     param.scope = ast.PARAM_SCOPE_ASYNC
1281                     param.transfer = ast.PARAM_TRANSFER_NONE
1282
1283         callback_param = None
1284         for i, param in enumerate(params):
1285             argnode = self._transformer.lookup_typenode(param.type)
1286             is_destroynotify = False
1287             if isinstance(argnode, ast.Callback):
1288                 if param.type.target_giname == 'GLib.DestroyNotify':
1289                     is_destroynotify = True
1290                 else:
1291                     callback_param = param
1292                     continue
1293             if callback_param is None:
1294                 continue
1295             if is_destroynotify:
1296                 callback_param.destroy_name = param.argname
1297                 callback_param.scope = ast.PARAM_SCOPE_NOTIFIED
1298                 callback_param.transfer = ast.PARAM_TRANSFER_NONE
1299             elif (param.type.is_equiv(ast.TYPE_ANY) and
1300                   param.argname is not None and
1301                   param.argname.endswith('data')):
1302                 callback_param.closure_name = param.argname
1303
1304     def _pass3_callable_throws(self, node):
1305         """Check to see if we have anything that looks like a
1306         callback+user_data+GDestroyNotify set."""
1307         if not node.parameters:
1308             return
1309         last_param = node.parameters[-1]
1310         # Checking type.name=='GLib.Error' generates false positives
1311         # on methods that take a 'GError *'
1312         if last_param.type.ctype == 'GError**':
1313             node.parameters.pop()
1314             node.throws = True