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