Change license name
[platform/upstream/gobject-introspection.git] / giscanner / transformer.py
1 # -*- Mode: Python -*-
2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008  Johan Dahlin
4 #
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2 of the License, or (at your option) any later version.
9 #
10 # This library 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 GNU
13 # Lesser General Public License for more details.
14 #
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the
17 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 # Boston, MA 02111-1307, USA.
19 #
20
21 import os
22 import sys
23 import subprocess
24
25 from . import ast
26 from . import message
27 from . import utils
28 from .cachestore import CacheStore
29 from .girparser import GIRParser
30 from .sourcescanner import (
31     SourceSymbol, ctype_name, CTYPE_POINTER,
32     CTYPE_BASIC_TYPE, CTYPE_UNION, CTYPE_ARRAY, CTYPE_TYPEDEF,
33     CTYPE_VOID, CTYPE_ENUM, CTYPE_FUNCTION, CTYPE_STRUCT,
34     CSYMBOL_TYPE_FUNCTION, CSYMBOL_TYPE_FUNCTION_MACRO, CSYMBOL_TYPE_TYPEDEF, CSYMBOL_TYPE_STRUCT,
35     CSYMBOL_TYPE_ENUM, CSYMBOL_TYPE_UNION, CSYMBOL_TYPE_OBJECT,
36     CSYMBOL_TYPE_MEMBER, CSYMBOL_TYPE_ELLIPSIS, CSYMBOL_TYPE_CONST,
37     TYPE_QUALIFIER_CONST, TYPE_QUALIFIER_VOLATILE)
38
39
40 class TransformerException(Exception):
41     pass
42
43
44 class Transformer(object):
45     namespace = property(lambda self: self._namespace)
46
47     def __init__(self, namespace, accept_unprefixed=False,
48                  identifier_filter_cmd=None, symbol_filter_cmd=None):
49         self._cachestore = CacheStore()
50         self._accept_unprefixed = accept_unprefixed
51         self._namespace = namespace
52         self._pkg_config_packages = set()
53         self._typedefs_ns = {}
54         self._parsed_includes = {}  # <string namespace -> Namespace>
55         self._includepaths = []
56         self._passthrough_mode = False
57         self._identifier_filter_cmd = identifier_filter_cmd
58         self._symbol_filter_cmd = symbol_filter_cmd
59
60         # Cache a list of struct/unions in C's "tag namespace". This helps
61         # manage various orderings of typedefs and structs. See:
62         # https://bugzilla.gnome.org/show_bug.cgi?id=581525
63         self._tag_ns = {}
64
65     def get_pkgconfig_packages(self):
66         return self._pkg_config_packages
67
68     def disable_cache(self):
69         self._cachestore = None
70
71     def set_passthrough_mode(self):
72         self._passthrough_mode = True
73
74     def _append_new_node(self, node):
75         original = self._namespace.get(node.name)
76         # Special case constants here; we allow duplication to sort-of
77         # handle #ifdef.  But this introduces an arch-dependency in the .gir
78         # file.  So far this has only come up scanning glib - in theory, other
79         # modules will just depend on that.
80         if original and\
81                 (isinstance(original, ast.FunctionMacro) or isinstance(node,
82                     ast.FunctionMacro)):
83             pass
84         elif isinstance(original, ast.Constant) and isinstance(node, ast.Constant):
85             pass
86         elif original is node:
87             # Ignore attempts to add the same node to the namespace. This can
88             # happen when parsing typedefs and structs in particular orderings:
89             #   typedef struct _Foo Foo;
90             #   struct _Foo {...};
91             pass
92         elif original:
93             positions = set()
94             positions.update(original.file_positions)
95             positions.update(node.file_positions)
96             message.fatal("Namespace conflict for '%s'" % (node.name, ),
97                           positions)
98         else:
99             self._namespace.append(node)
100
101     def parse(self, symbols):
102         for symbol in symbols:
103             # WORKAROUND
104             # https://bugzilla.gnome.org/show_bug.cgi?id=550616
105             if symbol.ident in ['gst_g_error_get_type']:
106                 continue
107
108             try:
109                 node = self._traverse_one(symbol)
110             except TransformerException as e:
111                 message.warn_symbol(symbol, e)
112                 continue
113
114             if node and node.name:
115                 self._append_new_node(node)
116             if isinstance(node, ast.Compound) and node.tag_name and \
117                     node.tag_name not in self._tag_ns:
118                 self._tag_ns[node.tag_name] = node
119
120         # Run through the tag namespace looking for structs that have not been
121         # promoted into the main namespace. In this case we simply promote them
122         # with their struct tag.
123         for tag_name, struct in self._tag_ns.items():
124             if not struct.name:
125                 try:
126                     name = self.strip_identifier(tag_name)
127                     struct.name = name
128                     self._append_new_node(struct)
129                 except TransformerException as e:
130                     message.warn_node(node, e)
131
132     def set_include_paths(self, paths):
133         self._includepaths = list(paths)
134
135     def register_include(self, include):
136         if include in self._namespace.includes:
137             return
138         self._namespace.includes.add(include)
139         filename = self._find_include(include)
140         self._parse_include(filename)
141
142     def register_include_uninstalled(self, include_path):
143         basename = os.path.basename(include_path)
144         if not basename.endswith('.gir'):
145             raise SystemExit("Include path '%s' must be a filename path "
146                              "ending in .gir" % (include_path, ))
147         girname = basename[:-4]
148         include = ast.Include.from_string(girname)
149         if include in self._namespace.includes:
150             return
151         self._namespace.includes.add(include)
152         self._parse_include(include_path, uninstalled=True)
153
154     def lookup_giname(self, name):
155         """Given a name of the form Foo or Bar.Foo,
156 return the corresponding ast.Node, or None if none
157 available.  Will throw KeyError however for unknown
158 namespaces."""
159         if '.' not in name:
160             return self._namespace.get(name)
161         else:
162             (ns, giname) = name.split('.', 1)
163             if ns == self._namespace.name:
164                 return self._namespace.get(giname)
165             # Fallback to the main namespace if not a dependency and matches a prefix
166             if ns in self._namespace.identifier_prefixes and ns not in self._parsed_includes:
167                 message.warn(("Deprecated reference to identifier " +
168                               "prefix %s in GIName %s") % (ns, name))
169                 return self._namespace.get(giname)
170             include = self._parsed_includes[ns]
171             return include.get(giname)
172
173     def lookup_typenode(self, typeobj):
174         """Given a Type object, if it points to a giname,
175 calls lookup_giname() on the name.  Otherwise return
176 None."""
177         if typeobj.target_giname:
178             return self.lookup_giname(typeobj.target_giname)
179         return None
180
181     # Private
182
183     def _get_gi_data_dirs(self):
184         data_dirs = utils.get_system_data_dirs()
185         data_dirs.append(DATADIR)
186         if os.name != 'nt':
187             # For backwards compatibility, was always unconditionally added to the list.
188             data_dirs.append('/usr/share')
189         return data_dirs
190
191     def _find_include(self, include):
192         searchdirs = self._includepaths[:]
193         searchdirs.extend(GIRDIR)
194         for path in self._get_gi_data_dirs():
195             searchdirs.append(os.path.join(path, 'gir-1.0'))
196
197         girname = '%s-%s.gir' % (include.name, include.version)
198         for d in searchdirs:
199             path = os.path.join(d, girname)
200             if os.path.exists(path):
201                 return path
202         sys.stderr.write("Couldn't find include '%s' (search path: '%s')\n" %
203                          (girname, searchdirs))
204         sys.exit(1)
205
206     @classmethod
207     def parse_from_gir(cls, filename, extra_include_dirs=None):
208         self = cls(None)
209         if extra_include_dirs is not None:
210             self.set_include_paths(extra_include_dirs)
211         self.set_passthrough_mode()
212         parser = self._parse_include(filename)
213         self._namespace = parser.get_namespace()
214         del self._parsed_includes[self._namespace.name]
215         return self
216
217     def _parse_include(self, filename, uninstalled=False):
218         parser = None
219         if self._cachestore is not None:
220             parser = self._cachestore.load(filename)
221         if parser is None:
222             parser = GIRParser(types_only=not self._passthrough_mode)
223             parser.parse(filename)
224             if self._cachestore is not None:
225                 self._cachestore.store(filename, parser)
226
227         for include in parser.get_namespace().includes:
228             if include.name not in self._parsed_includes:
229                 dep_filename = self._find_include(include)
230                 self._parse_include(dep_filename)
231
232         if not uninstalled:
233             for pkg in parser.get_namespace().exported_packages:
234                 self._pkg_config_packages.add(pkg)
235         namespace = parser.get_namespace()
236         self._parsed_includes[namespace.name] = namespace
237         return parser
238
239     def _iter_namespaces(self):
240         """Return an iterator over all included namespaces; the
241 currently-scanned namespace is first."""
242         yield self._namespace
243         for ns in self._parsed_includes.values():
244             yield ns
245
246     def _sort_matches(self, val):
247         """Key sort which ensures items in self._namespace are last by returning
248         a tuple key starting with 1 for self._namespace entries and 0 for
249         everythin else.
250         """
251         if val[0] == self._namespace:
252             return 1, val[2]
253         else:
254             return 0, val[2]
255
256     def _split_c_string_for_namespace_matches(self, name, is_identifier=False):
257         if not is_identifier and self._symbol_filter_cmd:
258             proc = subprocess.Popen(self._symbol_filter_cmd,
259                                     stdin=subprocess.PIPE,
260                                     stdout=subprocess.PIPE,
261                                     stderr=subprocess.PIPE)
262             proc_name, err = proc.communicate(name.encode())
263             proc_name = proc_name.strip()
264             if proc.returncode:
265                 raise ValueError('filter: %r exited: %d with error: %s' %
266                                  (self._symbol_filter_cmd, proc.returncode, err))
267             name = proc_name.decode('ascii')
268             name = name.strip()
269
270         matches = []  # Namespaces which might contain this name
271         unprefixed_namespaces = []  # Namespaces with no prefix, last resort
272         for ns in self._iter_namespaces():
273             if is_identifier:
274                 prefixes = ns.identifier_prefixes
275             elif name[0].isupper():
276                 prefixes = ns._ucase_symbol_prefixes
277             else:
278                 prefixes = ns.symbol_prefixes
279             if prefixes:
280                 for prefix in prefixes:
281                     if (not is_identifier) and (not prefix.endswith('_')):
282                         prefix = prefix + '_'
283                     if name.startswith(prefix):
284                         matches.append((ns, name[len(prefix):], len(prefix)))
285                         break
286             else:
287                 unprefixed_namespaces.append(ns)
288         if matches:
289             matches.sort(key=self._sort_matches)
290             return list(map(lambda x: (x[0], x[1]), matches))
291         elif self._accept_unprefixed:
292             return [(self._namespace, name)]
293         elif unprefixed_namespaces:
294             # A bit of a hack; this function ideally shouldn't look through the
295             # contents of namespaces; but since we aren't scanning anything
296             # without a prefix, it's not too bad.
297             for ns in unprefixed_namespaces:
298                 if name in ns:
299                     return [(ns, name)]
300         raise ValueError("Unknown namespace for %s '%s'"
301                          % ('identifier' if is_identifier else 'symbol', name, ))
302
303     def split_ctype_namespaces(self, ident):
304         """Given a StudlyCaps string identifier like FooBar, return a
305 list of (namespace, stripped_identifier) sorted by namespace length,
306 or raise ValueError.  As a special case, if the current namespace matches,
307 it is always biggest (i.e. last)."""
308         return self._split_c_string_for_namespace_matches(ident, is_identifier=True)
309
310     def split_csymbol_namespaces(self, symbol):
311         """Given a C symbol like foo_bar_do_baz, return a list of
312 (namespace, stripped_symbol) sorted by namespace match probablity, or
313 raise ValueError."""
314         return self._split_c_string_for_namespace_matches(symbol, is_identifier=False)
315
316     def split_csymbol(self, symbol):
317         """Given a C symbol like foo_bar_do_baz, return the most probable
318 (namespace, stripped_symbol) match, or raise ValueError."""
319         matches = self._split_c_string_for_namespace_matches(symbol, is_identifier=False)
320         return matches[-1]
321
322     def strip_identifier(self, ident):
323         if self._identifier_filter_cmd:
324             proc = subprocess.Popen(self._identifier_filter_cmd,
325                                     stdin=subprocess.PIPE,
326                                     stdout=subprocess.PIPE,
327                                     stderr=subprocess.PIPE)
328             proc_ident, err = proc.communicate(ident.encode())
329             if proc.returncode:
330                 raise ValueError('filter: %r exited: %d with error: %s' %
331                                  (self._identifier_filter_cmd, proc.returncode, err))
332             ident = proc_ident.decode('ascii').strip()
333
334         hidden = ident.startswith('_')
335         if hidden:
336             ident = ident[1:]
337         try:
338             matches = self.split_ctype_namespaces(ident)
339         except ValueError as e:
340             raise TransformerException(str(e))
341         for ns, name in matches:
342             if ns is self._namespace:
343                 if hidden:
344                     return '_' + name
345                 return name
346         (ns, name) = matches[-1]
347         raise TransformerException(
348             "Skipping foreign identifier '%s' from namespace %s" % (ident, ns.name, ))
349         return None
350
351     def _strip_symbol(self, symbol):
352         ident = symbol.ident
353         hidden = ident.startswith('_')
354         if hidden:
355             ident = ident[1:]
356         try:
357             (ns, name) = self.split_csymbol(ident)
358         except ValueError as e:
359             raise TransformerException(str(e))
360         if ns != self._namespace:
361             raise TransformerException(
362                 "Skipping foreign symbol from namespace %s" % (ns.name, ))
363         if hidden:
364             return '_' + name
365         return name
366
367     def _traverse_one(self, symbol, stype=None, parent_symbol=None):
368         assert isinstance(symbol, SourceSymbol), symbol
369
370         if stype is None:
371             stype = symbol.type
372         if stype == CSYMBOL_TYPE_FUNCTION:
373             return self._create_function(symbol)
374         elif stype == CSYMBOL_TYPE_FUNCTION_MACRO:
375             return self._create_function_macro(symbol)
376         elif stype == CSYMBOL_TYPE_TYPEDEF:
377             return self._create_typedef(symbol)
378         elif stype == CSYMBOL_TYPE_STRUCT:
379             return self._create_tag_ns_compound(ast.Record, symbol)
380         elif stype == CSYMBOL_TYPE_ENUM:
381             return self._create_enum(symbol)
382         elif stype == CSYMBOL_TYPE_MEMBER:
383             return self._create_member(symbol, parent_symbol)
384         elif stype == CSYMBOL_TYPE_UNION:
385             return self._create_tag_ns_compound(ast.Union, symbol)
386         elif stype == CSYMBOL_TYPE_CONST:
387             return self._create_const(symbol)
388         # Ignore variable declarations in the header
389         elif stype == CSYMBOL_TYPE_OBJECT:
390             pass
391         else:
392             print("transformer: unhandled symbol: '%s'" % (symbol, ))
393
394     def _enum_common_prefix(self, symbol):
395         def common_prefix(a, b):
396             commonparts = []
397             for aword, bword in zip(a.split('_'), b.split('_')):
398                 if aword != bword:
399                     return '_'.join(commonparts) + '_'
400                 commonparts.append(aword)
401             return min(a, b)
402
403         # Nothing less than 2 has a common prefix
404         if len(list(symbol.base_type.child_list)) < 2:
405             return None
406         prefix = None
407         for child in symbol.base_type.child_list:
408             if prefix is None:
409                 prefix = child.ident
410             else:
411                 prefix = common_prefix(prefix, child.ident)
412                 if prefix == '':
413                     return None
414         return prefix
415
416     def _create_enum(self, symbol):
417         prefix = self._enum_common_prefix(symbol)
418         if prefix:
419             prefixlen = len(prefix)
420         else:
421             prefixlen = 0
422         members = []
423         for child in symbol.base_type.child_list:
424             if child.private:
425                 continue
426             if prefixlen > 0:
427                 name = child.ident[prefixlen:]
428             else:
429                 # Ok, the enum members don't have a consistent prefix
430                 # among them, so let's just remove the global namespace
431                 # prefix.
432                 name = self._strip_symbol(child)
433             members.append(ast.Member(name.lower(),
434                                       child.const_int,
435                                       child.ident))
436         enum_name = self.strip_identifier(symbol.ident)
437         if symbol.base_type.is_bitfield:
438             klass = ast.Bitfield
439         else:
440             klass = ast.Enum
441         node = klass(enum_name, symbol.ident, members=members)
442         node.add_symbol_reference(symbol)
443         return node
444
445     def _create_function(self, symbol):
446         # Drop functions that start with _ very early on here
447         if symbol.ident.startswith('_'):
448             return None
449         parameters = list(self._create_parameters(symbol, symbol.base_type))
450         return_ = self._create_return(symbol.base_type.base_type)
451         name = self._strip_symbol(symbol)
452         func = ast.Function(name, return_, parameters, False, symbol.ident)
453         func.add_symbol_reference(symbol)
454         return func
455
456     def _create_function_macro(self, symbol):
457         if symbol.ident.startswith('_'):
458             return None
459
460         if (symbol.source_filename is None or not symbol.source_filename.endswith('.h')):
461             return None
462
463         parameters = list(self._create_parameters(symbol, symbol.base_type))
464         name = self._strip_symbol(symbol)
465         macro = ast.FunctionMacro(name, parameters, symbol.ident)
466         macro.add_symbol_reference(symbol)
467         return macro
468
469     def _create_source_type(self, source_type, is_parameter=False):
470         assert source_type is not None
471         if source_type.type == CTYPE_VOID:
472             value = 'void'
473         elif source_type.type == CTYPE_BASIC_TYPE:
474             value = source_type.name
475         elif source_type.type == CTYPE_TYPEDEF:
476             value = source_type.name
477         elif (source_type.type == CTYPE_POINTER or
478                 # Array to pointer adjustment as per 6.7.6.3.
479                 # This is performed only on the outermost array,
480                 # so we don't forward is_parameter.
481                 (source_type.type == CTYPE_ARRAY and is_parameter)):
482             value = self._create_source_type(source_type.base_type) + '*'
483         elif source_type.type == CTYPE_ARRAY:
484             return self._create_source_type(source_type.base_type)
485         else:
486             value = 'gpointer'
487         return value
488
489     def _create_complete_source_type(self, source_type, is_parameter=False):
490         assert source_type is not None
491
492         const = (source_type.type_qualifier & TYPE_QUALIFIER_CONST)
493         volatile = (source_type.type_qualifier & TYPE_QUALIFIER_VOLATILE)
494
495         if source_type.type == CTYPE_VOID:
496             return 'void'
497         elif source_type.type in [CTYPE_BASIC_TYPE,
498                                   CTYPE_TYPEDEF,
499                                   CTYPE_STRUCT,
500                                   CTYPE_UNION,
501                                   CTYPE_ENUM]:
502             value = source_type.name
503             if const:
504                 value = 'const ' + value
505             if volatile:
506                 value = 'volatile ' + value
507             return value
508         elif (source_type.type == CTYPE_POINTER or
509                 # Array to pointer adjustment as per 6.7.6.3.
510                 # This is performed only on the outermost array,
511                 # so we don't forward is_parameter.
512                 (source_type.type == CTYPE_ARRAY and is_parameter)):
513             value = self._create_complete_source_type(source_type.base_type) + '*'
514             # TODO: handle pointer to function as a special case?
515             if const:
516                 value += ' const'
517             if volatile:
518                 value += ' volatile'
519             return value
520         elif source_type.type == CTYPE_ARRAY:
521             return self._create_complete_source_type(source_type.base_type)
522         else:
523             if const:
524                 value = 'gconstpointer'
525             else:
526                 value = 'gpointer'
527             if volatile:
528                 value = 'volatile ' + value
529             return value
530
531     def _create_parameters(self, symbol, base_type):
532         for i, child in enumerate(base_type.child_list):
533             yield self._create_parameter(symbol, i, child)
534
535     def _synthesize_union_type(self, symbol, parent_symbol):
536         # Synthesize a named union so that it can be referenced.
537         parent_ident = parent_symbol.ident
538         # FIXME: Should split_ctype_namespaces handle the hidden case?
539         hidden = parent_ident.startswith('_')
540         if hidden:
541             parent_ident = parent_ident[1:]
542         matches = self.split_ctype_namespaces(parent_ident)
543         (namespace, parent_name) = matches[-1]
544         assert namespace and parent_name
545         if hidden:
546             parent_name = '_' + parent_name
547         fake_union = ast.Union("%s__%s__union" % (parent_name, symbol.ident))
548         # _parse_fields accesses <type>.base_type.child_list, so we have to
549         # pass symbol.base_type even though that refers to the array, not the
550         # union.
551         self._parse_fields(symbol.base_type, fake_union)
552         self._append_new_node(fake_union)
553         fake_type = ast.Type(
554             target_giname="%s.%s" % (namespace.name, fake_union.name))
555         return fake_type
556
557     def _create_member(self, symbol, parent_symbol=None):
558         source_type = symbol.base_type
559         if (source_type.type == CTYPE_POINTER
560         and symbol.base_type.base_type.type == CTYPE_FUNCTION):
561             node = self._create_callback(symbol, member=True)
562         elif source_type.type == CTYPE_STRUCT and source_type.name is None:
563             node = self._create_member_compound(ast.Record, symbol)
564         elif source_type.type == CTYPE_UNION and source_type.name is None:
565             node = self._create_member_compound(ast.Union, symbol)
566         else:
567             # Special handling for fields; we don't have annotations on them
568             # to apply later, yet.
569             if source_type.type == CTYPE_ARRAY:
570                 # Determine flattened array size and its element type.
571                 flattened_size = 1
572                 while source_type.type == CTYPE_ARRAY:
573                     for child in source_type.child_list:
574                         if flattened_size is not None:
575                             flattened_size *= child.const_int
576                         break
577                     else:
578                         flattened_size = None
579                     source_type = source_type.base_type
580
581                 # If the array contains anonymous unions, like in the GValue
582                 # struct, we need to handle this specially.  This is necessary
583                 # to be able to properly calculate the size of the compound
584                 # type (e.g. GValue) that contains this array, see
585                 # <https://bugzilla.gnome.org/show_bug.cgi?id=657040>.
586                 if source_type.type == CTYPE_UNION and source_type.name is None:
587                     element_type = self._synthesize_union_type(symbol, parent_symbol)
588                 else:
589                     ctype = self._create_source_type(source_type)
590                     complete_ctype = self._create_complete_source_type(source_type)
591                     element_type = self.create_type_from_ctype_string(ctype,
592                                                                       complete_ctype=complete_ctype)
593                 ftype = ast.Array(None, element_type)
594                 ftype.zeroterminated = False
595                 ftype.size = flattened_size
596             else:
597                 ftype = self._create_type_from_base(symbol.base_type)
598             # ast.Fields are assumed to be read-write
599             # (except for Objects, see also glibtransformer.py)
600             node = ast.Field(symbol.ident, ftype,
601                              readable=True, writable=True,
602                              bits=symbol.const_int)
603             if symbol.private:
604                 node.readable = False
605                 node.writable = False
606                 node.private = True
607         return node
608
609     def _create_typedef(self, symbol):
610         ctype = symbol.base_type.type
611         if (ctype == CTYPE_POINTER and symbol.base_type.base_type.type == CTYPE_FUNCTION):
612             node = self._create_typedef_callback(symbol)
613         elif (ctype == CTYPE_FUNCTION):
614             node = self._create_typedef_callback(symbol)
615         elif (ctype == CTYPE_POINTER and symbol.base_type.base_type.type == CTYPE_STRUCT):
616             node = self._create_typedef_compound(ast.Record, symbol, disguised=True)
617         elif ctype == CTYPE_STRUCT:
618             node = self._create_typedef_compound(ast.Record, symbol)
619         elif ctype == CTYPE_UNION:
620             node = self._create_typedef_compound(ast.Union, symbol)
621         elif ctype == CTYPE_ENUM:
622             return self._create_enum(symbol)
623         elif ctype in (CTYPE_TYPEDEF,
624                        CTYPE_POINTER,
625                        CTYPE_BASIC_TYPE,
626                        CTYPE_VOID):
627             name = self.strip_identifier(symbol.ident)
628             target = self._create_type_from_base(symbol.base_type)
629             if name in ast.type_names:
630                 return None
631             # https://bugzilla.gnome.org/show_bug.cgi?id=755882
632             if name.endswith('_autoptr'):
633                 return None
634             node = ast.Alias(name, target, ctype=symbol.ident)
635             node.add_symbol_reference(symbol)
636         else:
637             raise NotImplementedError(
638                 "symbol '%s' of type %s" % (symbol.ident, ctype_name(ctype)))
639         return node
640
641     def _canonicalize_ctype(self, ctype):
642         # First look up the ctype including any pointers;
643         # a few type names like 'char*' have their own aliases
644         # and we need pointer information for those.
645         firstpass = ast.type_names.get(ctype)
646
647         # If we have a particular alias for this, skip deep
648         # canonicalization to prevent changing
649         # e.g. char* -> int8*
650         if firstpass:
651             return firstpass.target_fundamental
652
653         if not ctype.endswith('*'):
654             return ctype
655
656         # We have a pointer type.
657         # Strip the end pointer, canonicalize our base type
658         base = ctype[:-1]
659         canonical_base = self._canonicalize_ctype(base)
660
661         # Append the pointer again
662         canonical = canonical_base + '*'
663
664         return canonical
665
666     def _create_type_from_base(self, source_type, is_parameter=False, is_return=False):
667         ctype = self._create_source_type(source_type, is_parameter=is_parameter)
668         complete_ctype = self._create_complete_source_type(source_type, is_parameter=is_parameter)
669         const = ((source_type.type == CTYPE_POINTER) and
670                  (source_type.base_type.type_qualifier & TYPE_QUALIFIER_CONST))
671         return self.create_type_from_ctype_string(ctype, is_const=const,
672                                                   is_parameter=is_parameter, is_return=is_return,
673                                                   complete_ctype=complete_ctype)
674
675     def _create_bare_container_type(self, base, ctype=None,
676                                     is_const=False, complete_ctype=None):
677         if base in ('GList', 'GSList', 'GLib.List', 'GLib.SList'):
678             if base in ('GList', 'GSList'):
679                 name = 'GLib.' + base[1:]
680             else:
681                 name = base
682             return ast.List(name, ast.TYPE_ANY, ctype=ctype,
683                         is_const=is_const, complete_ctype=complete_ctype)
684         elif base in ('GByteArray', 'GLib.ByteArray', 'GObject.ByteArray'):
685             return ast.Array('GLib.ByteArray', ast.TYPE_UINT8, ctype=ctype,
686                          is_const=is_const, complete_ctype=complete_ctype)
687         elif base in ('GArray', 'GPtrArray',
688                       'GLib.Array', 'GLib.PtrArray',
689                       'GObject.Array', 'GObject.PtrArray'):
690             if '.' in base:
691                 name = 'GLib.' + base.split('.', 1)[1]
692             else:
693                 name = 'GLib.' + base[1:]
694             return ast.Array(name, ast.TYPE_ANY, ctype=ctype,
695                          is_const=is_const, complete_ctype=complete_ctype)
696         elif base in ('GHashTable', 'GLib.HashTable', 'GObject.HashTable'):
697             return ast.Map(ast.TYPE_ANY, ast.TYPE_ANY, ctype=ctype, is_const=is_const,
698                            complete_ctype=complete_ctype)
699         return None
700
701     def create_type_from_ctype_string(self, ctype, is_const=False,
702                                       is_parameter=False, is_return=False,
703                                       complete_ctype=None):
704         canonical = self._canonicalize_ctype(ctype)
705         base = canonical.replace('*', '')
706
707         # While gboolean and _Bool are distinct types, they used to be treated
708         # by scanner as exactly the same one. In general this is incorrect
709         # because of different ABI, but this usually works fine,
710         # so for backward compatibility lets continue for now:
711         # https://gitlab.gnome.org/GNOME/gobject-introspection/merge_requests/24#note_92792
712         if canonical in ('_Bool', 'bool'):
713             canonical = 'gboolean'
714             base = canonical
715
716         # Special default: char ** -> ast.Array, same for GStrv
717         if (is_return and canonical == 'utf8*') or base == 'GStrv':
718             bare_utf8 = ast.TYPE_STRING.clone()
719             bare_utf8.ctype = None
720             return ast.Array(None, bare_utf8, ctype=ctype,
721                              is_const=is_const, complete_ctype=complete_ctype)
722
723         fundamental = ast.type_names.get(base)
724         if fundamental is not None:
725             return ast.Type(target_fundamental=fundamental.target_fundamental,
726                         ctype=ctype,
727                         is_const=is_const, complete_ctype=complete_ctype)
728         container = self._create_bare_container_type(base, ctype=ctype, is_const=is_const,
729                                                      complete_ctype=complete_ctype)
730         if container:
731             return container
732         return ast.Type(ctype=ctype, is_const=is_const, complete_ctype=complete_ctype)
733
734     def _create_parameter(self, parent_symbol, index, symbol):
735         if symbol.type == CSYMBOL_TYPE_ELLIPSIS:
736             return ast.Parameter('...', ast.Varargs())
737         else:
738             if symbol.base_type:
739                 ptype = self._create_type_from_base(symbol.base_type, is_parameter=True)
740             else:
741                 ptype = None
742
743             if symbol.ident is None:
744                 if symbol.base_type and symbol.base_type.type != CTYPE_VOID:
745                     message.warn_symbol(parent_symbol, "missing parameter name; undocumentable")
746                 ident = 'arg%d' % (index, )
747             else:
748                 ident = symbol.ident
749
750             return ast.Parameter(ident, ptype)
751
752     def _create_return(self, source_type):
753         typeval = self._create_type_from_base(source_type, is_return=True)
754         return ast.Return(typeval)
755
756     def _create_const(self, symbol):
757         if symbol.ident.startswith('_'):
758             return None
759
760         # Don't create constants for non-public things
761         # http://bugzilla.gnome.org/show_bug.cgi?id=572790
762         if (symbol.source_filename is None or not symbol.source_filename.endswith('.h')):
763             return None
764         name = self._strip_symbol(symbol)
765         if symbol.const_string is not None:
766             typeval = ast.TYPE_STRING
767             value = symbol.const_string
768         elif symbol.const_int is not None:
769             if symbol.base_type is not None:
770                 typeval = self._create_type_from_base(symbol.base_type)
771             else:
772                 typeval = ast.TYPE_INT
773             unaliased = typeval
774             self._resolve_type_from_ctype(unaliased)
775             if typeval.target_giname and typeval.ctype:
776                 target = self.lookup_giname(typeval.target_giname)
777                 target = self.resolve_aliases(target)
778                 if isinstance(target, ast.Type):
779                     unaliased = target
780             if unaliased == ast.TYPE_UINT64:
781                 value = str(symbol.const_int % 2 ** 64)
782             elif unaliased == ast.TYPE_UINT32:
783                 value = str(symbol.const_int % 2 ** 32)
784             elif unaliased == ast.TYPE_UINT16:
785                 value = str(symbol.const_int % 2 ** 16)
786             elif unaliased == ast.TYPE_UINT8:
787                 value = str(symbol.const_int % 2 ** 16)
788             else:
789                 value = str(symbol.const_int)
790         elif symbol.const_boolean is not None:
791             typeval = ast.TYPE_BOOLEAN
792             value = "true" if symbol.const_boolean else "false"
793         elif symbol.const_double is not None:
794             typeval = ast.TYPE_DOUBLE
795             value = '%f' % (symbol.const_double, )
796         else:
797             raise AssertionError()
798
799         const = ast.Constant(name, typeval, value,
800                              symbol.ident)
801         const.add_symbol_reference(symbol)
802         return const
803
804     def _create_typedef_compound(self, compound_class, symbol, disguised=False):
805         name = self.strip_identifier(symbol.ident)
806         assert symbol.base_type
807         if symbol.base_type.name:
808             tag_name = symbol.base_type.name
809         else:
810             tag_name = None
811
812         # If the struct already exists in the tag namespace, use it.
813         if tag_name in self._tag_ns:
814             compound = self._tag_ns[tag_name]
815             if compound.name:
816                 # If the struct name is set it means the struct has already been
817                 # promoted from the tag namespace to the main namespace by a
818                 # prior typedef struct. If we get here it means this is another
819                 # typedef of that struct. Instead of creating an alias to the
820                 # primary typedef that has been promoted, we create a new Record
821                 # with shared fields. This handles the case where we want to
822                 # give structs like GInitiallyUnowned its own Record:
823                 #    typedef struct _GObject GObject;
824                 #    typedef struct _GObject GInitiallyUnowned;
825                 # See: http://bugzilla.gnome.org/show_bug.cgi?id=569408
826                 new_compound = compound_class(name, symbol.ident, tag_name=tag_name)
827                 new_compound.fields = compound.fields
828                 new_compound.add_symbol_reference(symbol)
829                 return new_compound
830             else:
831                 # If the struct does not have its name set, it exists only in
832                 # the tag namespace. Set it here and return it which will
833                 # promote it to the main namespace. Essentially the first
834                 # typedef for a struct clobbers its name and ctype which is what
835                 # will be visible to GI.
836                 compound.name = name
837                 compound.ctype = symbol.ident
838         else:
839             # Create a new struct with a typedef name and tag name when available.
840             # Structs with a typedef name are promoted into the main namespace
841             # by it being returned to the "parse" function and are also added to
842             # the tag namespace if it has a tag_name set.
843             compound = compound_class(name, symbol.ident, disguised=disguised, tag_name=tag_name)
844             if tag_name:
845                 # Force the struct as disguised for now since we do not yet know
846                 # if it has fields that will be parsed. Note that this is using
847                 # an erroneous definition of disguised and we should eventually
848                 # only look at the field count when needed.
849                 compound.disguised = True
850             else:
851                 # Case where we have an anonymous struct which is typedef'd:
852                 #   typedef struct {...} Struct;
853                 # we need to parse the fields because we never get a struct
854                 # in the tag namespace which is normally where fields are parsed.
855                 self._parse_fields(symbol, compound)
856
857         compound.add_symbol_reference(symbol)
858         return compound
859
860     def _create_tag_ns_compound(self, compound_class, symbol):
861         # Get or create a struct from C's tag namespace
862         if symbol.ident in self._tag_ns:
863             compound = self._tag_ns[symbol.ident]
864         else:
865             compound = compound_class(None, symbol.ident, tag_name=symbol.ident)
866
867         # Make sure disguised is False as we are now about to parse the
868         # fields of the real struct.
869         compound.disguised = False
870         # Fields may need to be parsed in either of the above cases because the
871         # Record can be created with a typedef prior to the struct definition.
872         self._parse_fields(symbol, compound)
873         compound.add_symbol_reference(symbol)
874         return compound
875
876     def _create_member_compound(self, compound_class, symbol):
877         compound = compound_class(symbol.ident, symbol.ident)
878         self._parse_fields(symbol, compound)
879         compound.add_symbol_reference(symbol)
880         return compound
881
882     def _create_typedef_callback(self, symbol):
883         callback = self._create_callback(symbol)
884         if not callback:
885             return None
886         return callback
887
888     def _parse_fields(self, symbol, compound):
889         for child in symbol.base_type.child_list:
890             child_node = self._traverse_one(child, parent_symbol=symbol)
891             if not child_node:
892                 continue
893             if isinstance(child_node, ast.Field):
894                 field = child_node
895             else:
896                 field = ast.Field(child.ident, None, True, False,
897                               anonymous_node=child_node)
898             compound.fields.append(field)
899
900     def _create_callback(self, symbol, member=False):
901         if (symbol.base_type.type == CTYPE_FUNCTION):  # function
902             paramtype = symbol.base_type
903             retvaltype = symbol.base_type.base_type
904         elif (symbol.base_type.type == CTYPE_POINTER):  # function pointer
905             paramtype = symbol.base_type.base_type
906             retvaltype = symbol.base_type.base_type.base_type
907         parameters = list(self._create_parameters(symbol, paramtype))
908         retval = self._create_return(retvaltype)
909
910         # Mark the 'user_data' arguments
911         for i, param in enumerate(parameters):
912             if (param.type.target_fundamental == 'gpointer' and param.argname == 'user_data'):
913                 param.closure_name = param.argname
914
915         if member:
916             name = symbol.ident
917         elif symbol.ident.find('_') > 0:
918             name = self._strip_symbol(symbol)
919         else:
920             name = self.strip_identifier(symbol.ident)
921         callback = ast.Callback(name, retval, parameters, False,
922                                 ctype=symbol.ident)
923         callback.add_symbol_reference(symbol)
924
925         return callback
926
927     def create_type_from_user_string(self, typestr):
928         """Parse a C type string (as might be given from an
929         annotation) and resolve it.  For compatibility, we can consume
930 both GI type string (utf8, Foo.Bar) style, as well as C (char *, FooBar) style.
931
932 Note that type resolution may not succeed."""
933         if '.' in typestr:
934             container = self._create_bare_container_type(typestr)
935             if container:
936                 typeval = container
937             else:
938                 typeval = self._namespace.type_from_name(typestr)
939         else:
940             typeval = self.create_type_from_ctype_string(typestr)
941
942         self.resolve_type(typeval)
943         if typeval.resolved:
944             # Explicitly clear out the c_type; there isn't one in this case.
945             typeval.ctype = None
946         return typeval
947
948     def _resolve_type_from_ctype_all_namespaces(self, typeval, pointer_stripped):
949         # If we can't determine the namespace from the type name,
950         # fall back to trying all of our includes.  An example of this is mutter,
951         # which has nominal namespace of "Meta", but a few classes are
952         # "Mutter".  We don't export that data in introspection currently.
953         # Basically the library should be fixed, but we'll hack around it here.
954         for namespace in self._parsed_includes.values():
955             target = namespace.get_by_ctype(pointer_stripped)
956             if target:
957                 typeval.target_giname = '%s.%s' % (namespace.name, target.name)
958                 return True
959         return False
960
961     def _resolve_type_from_ctype(self, typeval):
962         assert typeval.ctype is not None
963         pointer_stripped = typeval.ctype.replace('*', '')
964         try:
965             matches = self.split_ctype_namespaces(pointer_stripped)
966         except ValueError:
967             return self._resolve_type_from_ctype_all_namespaces(typeval, pointer_stripped)
968         for namespace, name in matches:
969             target = namespace.get(name)
970             if not target:
971                 target = namespace.get_by_ctype(pointer_stripped)
972             if target:
973                 typeval.target_giname = '%s.%s' % (namespace.name, target.name)
974                 return True
975         return False
976
977     def _resolve_type_from_gtype_name(self, typeval):
978         assert typeval.gtype_name is not None
979         for ns in self._iter_namespaces():
980             node = ns.type_names.get(typeval.gtype_name, None)
981             if node is not None:
982                 typeval.target_giname = '%s.%s' % (ns.name, node.name)
983                 return True
984         return False
985
986     def _resolve_type_internal(self, typeval):
987         if isinstance(typeval, (ast.Array, ast.List)):
988             return self.resolve_type(typeval.element_type)
989         elif isinstance(typeval, ast.Map):
990             key_resolved = self.resolve_type(typeval.key_type)
991             value_resolved = self.resolve_type(typeval.value_type)
992             return key_resolved and value_resolved
993         elif typeval.resolved:
994             return True
995         elif typeval.ctype:
996             return self._resolve_type_from_ctype(typeval)
997         elif typeval.gtype_name:
998             return self._resolve_type_from_gtype_name(typeval)
999
1000     def resolve_type(self, typeval):
1001         if not self._resolve_type_internal(typeval):
1002             return False
1003
1004         if typeval.target_fundamental or typeval.target_foreign:
1005             return True
1006
1007         assert typeval.target_giname is not None
1008
1009         try:
1010             type_ = self.lookup_giname(typeval.target_giname)
1011         except KeyError:
1012             type_ = None
1013
1014         if type_ is None:
1015             typeval.target_giname = None
1016
1017         return typeval.resolved
1018
1019     def resolve_aliases(self, typenode):
1020         """Removes all aliases from typenode, returns first non-alias
1021         in the typenode alias chain.  Returns typenode argument if it
1022         is not an alias."""
1023         while isinstance(typenode, ast.Alias):
1024             if typenode.target.target_giname is not None:
1025                 typenode = self.lookup_giname(typenode.target.target_giname)
1026             elif typenode.target.target_fundamental is not None:
1027                 typenode = typenode.target
1028             else:
1029                 break
1030         return typenode