LCOV - code coverage report
Current view: top level - vala - valagirparser.vala (source / functions) Coverage Total Hit
Test: vala 0.57.0.298-a8cae1 Lines: 77.0 % 2807 2160
Test Date: 2024-04-25 11:34:36 Functions: - 0 0

            Line data    Source code
       1              : /* valagirparser.vala
       2              :  *
       3              :  * Copyright (C) 2008-2012  Jürg Billeter
       4              :  * Copyright (C) 2011-2014  Luca Bruno
       5              :  *
       6              :  * This library is free software; you can redistribute it and/or
       7              :  * modify it under the terms of the GNU Lesser General Public
       8              :  * License as published by the Free Software Foundation; either
       9              :  * version 2.1 of the License, or (at your option) any later version.
      10              : 
      11              :  * This library is distributed in the hope that it will be useful,
      12              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14              :  * Lesser General Public License for more details.
      15              : 
      16              :  * You should have received a copy of the GNU Lesser General Public
      17              :  * License along with this library; if not, write to the Free Software
      18              :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
      19              :  *
      20              :  * Author:
      21              :  *      Jürg Billeter <j@bitron.ch>
      22              :  *      Luca Bruno <lucabru@src.gnome.org>
      23              :  */
      24              : 
      25              : using GLib;
      26              : 
      27              : /**
      28              :  * Code visitor parsing all GIR source files.
      29              :  *
      30              :  * Pipeline:
      31              :  * 1) Parse metadata
      32              :  * 2) Parse GIR with metadata, track unresolved GIR symbols, create Vala symbols
      33              :  * 3) Reconciliate the tree by mapping tracked symbols
      34              :  * 4) Process the tree
      35              :  */
      36         7690 : public class Vala.GirParser : CodeVisitor {
      37              :         /*
      38              :          * Metadata parser
      39              :          */
      40              : 
      41              :         enum ArgumentType {
      42              :                 SKIP,
      43              :                 HIDDEN,
      44              :                 NEW,
      45              :                 TYPE,
      46              :                 TYPE_ARGUMENTS,
      47              :                 TYPE_PARAMETERS,
      48              :                 CHEADER_FILENAME,
      49              :                 NAME,
      50              :                 OWNED,
      51              :                 UNOWNED,
      52              :                 PARENT,
      53              :                 IMPLEMENTS,
      54              :                 PREREQUISITES,
      55              :                 NULLABLE,
      56              :                 DEPRECATED,
      57              :                 REPLACEMENT,
      58              :                 DEPRECATED_SINCE,
      59              :                 SINCE,
      60              :                 ARRAY,
      61              :                 ARRAY_LENGTH_IDX,
      62              :                 ARRAY_NULL_TERMINATED,
      63              :                 DEFAULT,
      64              :                 OUT,
      65              :                 REF,
      66              :                 VFUNC_NAME,
      67              :                 VIRTUAL,
      68              :                 ABSTRACT,
      69              :                 COMPACT,
      70              :                 SEALED,
      71              :                 SCOPE,
      72              :                 STRUCT,
      73              :                 THROWS,
      74              :                 PRINTF_FORMAT,
      75              :                 ARRAY_LENGTH_FIELD,
      76              :                 SENTINEL,
      77              :                 CLOSURE,
      78              :                 DESTROY,
      79              :                 CPREFIX,
      80              :                 LOWER_CASE_CPREFIX,
      81              :                 LOWER_CASE_CSUFFIX,
      82              :                 ERRORDOMAIN,
      83              :                 DESTROYS_INSTANCE,
      84              :                 BASE_TYPE,
      85              :                 FINISH_NAME,
      86              :                 FINISH_INSTANCE,
      87              :                 SYMBOL_TYPE,
      88              :                 INSTANCE_IDX,
      89              :                 EXPERIMENTAL,
      90              :                 FEATURE_TEST_MACRO,
      91              :                 FLOATING,
      92              :                 TYPE_ID,
      93              :                 TYPE_GET_FUNCTION,
      94              :                 COPY_FUNCTION,
      95              :                 FREE_FUNCTION,
      96              :                 REF_FUNCTION,
      97              :                 REF_SINK_FUNCTION,
      98              :                 UNREF_FUNCTION,
      99              :                 RETURN_VOID,
     100              :                 RETURNS_MODIFIED_POINTER,
     101              :                 DELEGATE_TARGET_CNAME,
     102              :                 DESTROY_NOTIFY_CNAME,
     103              :                 FINISH_VFUNC_NAME,
     104              :                 NO_ACCESSOR_METHOD,
     105              :                 NO_WRAPPER,
     106              :                 CNAME,
     107              :                 DELEGATE_TARGET,
     108              :                 CTYPE;
     109              : 
     110           24 :                 public static ArgumentType? from_string (string name) {
     111           24 :                         var enum_class = (EnumClass) typeof(ArgumentType).class_ref ();
     112           24 :                         var nick = name.replace ("_", "-");
     113           24 :                         unowned GLib.EnumValue? enum_value = enum_class.get_value_by_nick (nick);
     114           24 :                         if (enum_value != null) {
     115           24 :                                 ArgumentType value = (ArgumentType) enum_value.value;
     116           48 :                                 return value;
     117              :                         }
     118            0 :                         return null;
     119              :                 }
     120              :         }
     121              : 
     122          167 :         class Argument {
     123           22 :                 public Expression expression;
     124           22 :                 public SourceReference source_reference;
     125              : 
     126           24 :                 public bool used = false;
     127              : 
     128           48 :                 public Argument (Expression expression, SourceReference? source_reference = null) {
     129           24 :                         this.expression = expression;
     130         1661 :                         this.source_reference = source_reference;
     131              :                 }
     132              :         }
     133              : 
     134            1 :         class MetadataSet : Metadata {
     135            2 :                 public MetadataSet (string? selector = null) {
     136            2 :                         base ("", selector);
     137              :                 }
     138              : 
     139            4 :                 public void add_sibling (Metadata metadata) {
     140            4 :                         foreach (var child in metadata.children) {
     141            0 :                                 add_child (child);
     142              :                         }
     143              :                         // merge arguments and take precedence
     144           12 :                         foreach (var key in metadata.args.get_keys ()) {
     145            4 :                                 args[key] = metadata.args[key];
     146              :                         }
     147              :                 }
     148              :         }
     149              : 
     150         9928 :         class Metadata {
     151              :                 private static Metadata _empty = null;
     152              :                 public static Metadata empty {
     153              :                         get {
     154         3387 :                                 if (_empty == null) {
     155         1538 :                                         _empty = new Metadata ("");
     156              :                                 }
     157         3387 :                                 return _empty;
     158              :                         }
     159              :                 }
     160              : 
     161           28 :                 public PatternSpec pattern_spec;
     162           28 :                 public string? selector;
     163           28 :                 public SourceReference source_reference;
     164              : 
     165         1567 :                 public bool used = false;
     166         1595 :                 public Vala.Map<ArgumentType,Argument> args = new HashMap<ArgumentType,Argument> ();
     167         1595 :                 public ArrayList<Metadata> children = new ArrayList<Metadata> ();
     168              : 
     169         3132 :                 public Metadata (string pattern, string? selector = null, SourceReference? source_reference = null) {
     170         1567 :                         this.pattern_spec = new PatternSpec (pattern);
     171         3134 :                         this.selector = selector;
     172         1593 :                         this.source_reference = source_reference;
     173              :                 }
     174              : 
     175           26 :                 public void add_child (Metadata metadata) {
     176           26 :                         children.add (metadata);
     177              :                 }
     178              : 
     179         1037 :                 public Metadata match_child (string name, string? selector = null) {
     180         2074 :                         var result = Metadata.empty;
     181         4121 :                         foreach (var metadata in children) {
     182         1542 :                                 if ((selector == null || metadata.selector == null || metadata.selector == selector) && metadata.pattern_spec.match_string (name)) {
     183           54 :                                         metadata.used = true;
     184           56 :                                         if (result == Metadata.empty) {
     185              :                                                 // first match
     186           52 :                                                 result = metadata;
     187              :                                         } else {
     188            2 :                                                 var ms = result as MetadataSet;
     189            0 :                                                 if (ms == null) {
     190              :                                                         // second match
     191            2 :                                                         ms = new MetadataSet (selector);
     192            2 :                                                         ms.add_sibling (result);
     193              :                                                 }
     194            2 :                                                 ms.add_sibling (metadata);
     195            4 :                                                 result = ms;
     196              :                                         }
     197              :                                 }
     198              :                         }
     199              :                         return result;
     200              :                 }
     201              : 
     202           24 :                 public void add_argument (ArgumentType key, Argument value) {
     203           24 :                         args.set (key, value);
     204              :                 }
     205              : 
     206        19597 :                 public bool has_argument (ArgumentType key) {
     207        19597 :                         return args.contains (key);
     208              :                 }
     209              : 
     210         4377 :                 public Expression? get_expression (ArgumentType arg) {
     211         4377 :                         var val = args.get (arg);
     212         4377 :                         if (val != null) {
     213           56 :                                 val.used = true;
     214          112 :                                 return val.expression;
     215              :                         }
     216         4377 :                         return null;
     217              :                 }
     218              : 
     219         1101 :                 public string? get_string (ArgumentType arg) {
     220         1101 :                         var lit = get_expression (arg) as StringLiteral;
     221           12 :                         if (lit != null) {
     222           12 :                                 return lit.eval ();
     223              :                         }
     224         1101 :                         return null;
     225              :                 }
     226              : 
     227            0 :                 public int get_integer (ArgumentType arg) {
     228            0 :                         var unary = get_expression (arg) as UnaryExpression;
     229            0 :                         if (unary != null && unary.operator == UnaryOperator.MINUS) {
     230            0 :                                 var lit = unary.inner as IntegerLiteral;
     231            0 :                                 if (lit != null) {
     232            0 :                                         return -int.parse (lit.value);
     233              :                                 }
     234              :                         } else {
     235            0 :                                 var lit = get_expression (arg) as IntegerLiteral;
     236            0 :                                 if (lit != null) {
     237            0 :                                         return int.parse (lit.value);
     238              :                                 }
     239              :                         }
     240              : 
     241            0 :                         return 0;
     242              :                 }
     243              : 
     244         2558 :                 public bool get_bool (ArgumentType arg, bool default_value = false) {
     245         2558 :                         var lit = get_expression (arg) as BooleanLiteral;
     246           35 :                         if (lit != null) {
     247           35 :                                 return lit.value;
     248              :                         }
     249         2558 :                         return default_value;
     250              :                 }
     251              : 
     252           10 :                 public SourceReference? get_source_reference (ArgumentType arg) {
     253           10 :                         var val = args.get (arg);
     254           10 :                         if (val != null) {
     255           10 :                                 return val.source_reference;
     256              :                         }
     257           10 :                         return null;
     258              :                 }
     259              :         }
     260              : 
     261            4 :         class MetadataParser {
     262              :                 /**
     263              :                  * Grammar:
     264              :                  * metadata ::= [ rule [ '\n' relativerule ]* ]
     265              :                  * rule ::= pattern ' ' [ args ]
     266              :                  * relativerule ::= '.' rule
     267              :                  * pattern ::= glob [ '#' selector ] [ '.' pattern ]
     268              :                  */
     269            2 :                 private Metadata tree = new Metadata ("");
     270            1 :                 private Scanner scanner;
     271              :                 private SourceLocation begin;
     272              :                 private SourceLocation end;
     273              :                 private SourceLocation old_end;
     274              :                 private TokenType current;
     275            1 :                 private Metadata parent_metadata;
     276              : 
     277            1 :                 public MetadataParser () {
     278            1 :                         tree.used = true;
     279              :                 }
     280              : 
     281           20 :                 SourceReference get_current_src () {
     282           20 :                         return new SourceReference (scanner.source_file, begin, end);
     283              :                 }
     284              : 
     285           54 :                 SourceReference get_src (SourceLocation begin, SourceLocation? end = null) {
     286           54 :                         var e = this.end;
     287           54 :                         if (end != null) {
     288            0 :                                 e = end;
     289              :                         }
     290           54 :                         return new SourceReference (scanner.source_file, begin, e);
     291              :                 }
     292              : 
     293            1 :                 public Metadata parse_metadata (SourceFile metadata_file) {
     294            1 :                         scanner = new Scanner (metadata_file);
     295            1 :                         next ();
     296           27 :                         while (current != TokenType.EOF) {
     297           26 :                                 if (!parse_rule ()) {
     298            0 :                                         return Metadata.empty;
     299              :                                 }
     300              :                         }
     301            1 :                         return tree;
     302              :                 }
     303              : 
     304          114 :                 TokenType next () {
     305          114 :                         old_end = end;
     306          114 :                         current = scanner.read_token (out begin, out end);
     307          114 :                         return current;
     308              :                 }
     309              : 
     310          100 :                 bool has_space () {
     311          100 :                         return old_end.pos != begin.pos;
     312              :                 }
     313              : 
     314           45 :                 bool has_newline () {
     315           45 :                         return old_end.line != begin.line;
     316              :                 }
     317              : 
     318           61 :                 string get_string (SourceLocation? begin = null, SourceLocation? end = null) {
     319           61 :                         var b = this.begin;
     320           61 :                         var e = this.end;
     321           61 :                         if (begin != null) {
     322           52 :                                 b = begin;
     323              :                         }
     324           61 :                         if (end != null) {
     325           52 :                                 e = end;
     326              :                         }
     327           61 :                         return ((string) b.pos).substring (0, (int) (e.pos - b.pos));
     328              :                 }
     329              : 
     330           52 :                 string? parse_identifier (bool is_glob) {
     331           52 :                         var begin = this.begin;
     332              : 
     333           52 :                         if (current == TokenType.DOT || current == TokenType.HASH) {
     334            0 :                                 if (is_glob) {
     335            0 :                                         Report.error (get_src (begin), "expected glob-style pattern");
     336              :                                 } else {
     337            0 :                                         Report.error (get_src (begin), "expected identifier");
     338              :                                 }
     339            0 :                                 return null;
     340              :                         }
     341              : 
     342           52 :                         if (is_glob) {
     343           29 :                                 while (current != TokenType.EOF && current != TokenType.DOT && current != TokenType.HASH) {
     344           27 :                                         next ();
     345           27 :                                         if (has_space ()) {
     346              :                                                 break;
     347              :                                         }
     348              :                                 }
     349              :                         } else {
     350           26 :                                 next ();
     351              :                         }
     352              : 
     353           52 :                         return get_string (begin, old_end);
     354              :                 }
     355              : 
     356           26 :                 string? parse_selector () {
     357           26 :                         if (current != TokenType.HASH || has_space ()) {
     358           24 :                                 return null;
     359              :                         }
     360            2 :                         next ();
     361              : 
     362            2 :                         return parse_identifier (false);
     363              :                 }
     364              : 
     365           26 :                 Metadata? parse_pattern () {
     366              :                         Metadata metadata;
     367           26 :                         bool is_relative = false;
     368           26 :                         if (current == TokenType.IDENTIFIER || current == TokenType.STAR) {
     369              :                                 // absolute pattern
     370           16 :                                 parent_metadata = tree;
     371              :                         } else {
     372              :                                 // relative pattern
     373           18 :                                 if (current != TokenType.DOT) {
     374            0 :                                         Report.error (get_current_src (), "expected pattern or `.', got `%s'", current.to_string ());
     375            0 :                                         return null;
     376              :                                 }
     377           18 :                                 next ();
     378           18 :                                 is_relative = true;
     379              :                         }
     380              : 
     381           26 :                         if (parent_metadata == null) {
     382            0 :                                 Report.error (get_current_src (), "cannot determinate parent metadata");
     383            0 :                                 return null;
     384              :                         }
     385              : 
     386           26 :                         SourceLocation begin = this.begin;
     387           26 :                         var pattern = parse_identifier (true);
     388           26 :                         if (pattern == null) {
     389            0 :                                 return null;
     390              :                         }
     391           26 :                         metadata = new Metadata (pattern, parse_selector (), get_src (begin));
     392           26 :                         parent_metadata.add_child (metadata);
     393              : 
     394           26 :                         while (current != TokenType.EOF && !has_space ()) {
     395            0 :                                 if (current != TokenType.DOT) {
     396            0 :                                         Report.error (get_current_src (), "expected `.' got `%s'", current.to_string ());
     397              :                                         break;
     398              :                                 }
     399            0 :                                 next ();
     400              : 
     401            0 :                                 begin = this.begin;
     402            0 :                                 pattern = parse_identifier (true);
     403            0 :                                 if (pattern == null) {
     404            0 :                                         return null;
     405              :                                 }
     406            0 :                                 var child = new Metadata (pattern, parse_selector (), get_src (begin, old_end));
     407            0 :                                 metadata.add_child (child);
     408            0 :                                 metadata = child;
     409              :                         }
     410           26 :                         if (!is_relative) {
     411           16 :                                 parent_metadata = metadata;
     412              :                         }
     413              : 
     414           26 :                         return metadata;
     415              :                 }
     416              : 
     417           20 :                 Expression? parse_expression () {
     418           20 :                         var begin = this.begin;
     419           20 :                         var src = get_current_src ();
     420           20 :                         Expression expr = null;
     421           20 :                         switch (current) {
     422              :                         case TokenType.NULL:
     423            0 :                                 expr = new NullLiteral (src);
     424            0 :                                 break;
     425              :                         case TokenType.TRUE:
     426            0 :                                 expr = new BooleanLiteral (true, src);
     427            0 :                                 break;
     428              :                         case TokenType.FALSE:
     429           11 :                                 expr = new BooleanLiteral (false, src);
     430           11 :                                 break;
     431              :                         case TokenType.MINUS:
     432            0 :                                 next ();
     433            0 :                                 var inner = parse_expression ();
     434            0 :                                 if (inner == null) {
     435            0 :                                         Report.error (src, "expected expression after `-', got `%s'", current.to_string ());
     436              :                                 } else {
     437            0 :                                         expr = new UnaryExpression (UnaryOperator.MINUS, inner, get_src (begin));
     438              :                                 }
     439            0 :                                 return expr;
     440              :                         case TokenType.INTEGER_LITERAL:
     441            0 :                                 expr = new IntegerLiteral (get_string (), src);
     442            0 :                                 break;
     443              :                         case TokenType.REAL_LITERAL:
     444            0 :                                 expr = new RealLiteral (get_string (), src);
     445            0 :                                 break;
     446              :                         case TokenType.STRING_LITERAL:
     447            9 :                                 expr = new StringLiteral (get_string (), src);
     448            9 :                                 break;
     449              :                         case TokenType.IDENTIFIER:
     450            0 :                                 expr = new MemberAccess (null, get_string (), src);
     451            0 :                                 while (next () == TokenType.DOT) {
     452            0 :                                         if (next () != TokenType.IDENTIFIER) {
     453            0 :                                                 Report.error (get_current_src (), "expected identifier got `%s'", current.to_string ());
     454              :                                                 break;
     455              :                                         }
     456            0 :                                         expr = new MemberAccess (expr, get_string (), get_current_src ());
     457              :                                 }
     458            0 :                                 return expr;
     459              :                         case TokenType.OPEN_PARENS:
     460              :                                 // empty tuple => no expression
     461            0 :                                 if (next () != TokenType.CLOSE_PARENS) {
     462            0 :                                         Report.error (get_current_src (), "expected `)', got `%s'", current.to_string ());
     463              :                                         break;
     464              :                                 }
     465            0 :                                 expr = new Tuple (src);
     466            0 :                                 break;
     467              :                         default:
     468            0 :                                 Report.error (src, "expected literal or symbol got %s", current.to_string ());
     469            0 :                                 break;
     470              :                         }
     471           20 :                         next ();
     472           20 :                         return expr;
     473              :                 }
     474              : 
     475           22 :                 bool parse_args (Metadata metadata) {
     476           66 :                         while (current != TokenType.EOF && has_space () && !has_newline ()) {
     477           24 :                                 SourceLocation begin = this.begin;
     478           24 :                                 var id = parse_identifier (false);
     479           24 :                                 if (id == null) {
     480            0 :                                         return false;
     481              :                                 }
     482           24 :                                 var arg_type = ArgumentType.from_string (id);
     483           24 :                                 if (arg_type == null) {
     484            0 :                                         Report.warning (get_src (begin, old_end), "unknown argument `%s'", id);
     485            0 :                                         continue;
     486              :                                 }
     487              : 
     488           24 :                                 if (current != TokenType.ASSIGN) {
     489              :                                         // threat as `true'
     490            4 :                                         metadata.add_argument (arg_type, new Argument (new BooleanLiteral (true, get_src (begin)), get_src (begin)));
     491            4 :                                         continue;
     492              :                                 }
     493           20 :                                 next ();
     494              : 
     495           20 :                                 Expression expr = parse_expression ();
     496           20 :                                 if (expr == null) {
     497            0 :                                         return false;
     498              :                                 }
     499           20 :                                 metadata.add_argument (arg_type, new Argument (expr, get_src (begin)));
     500              :                         }
     501              : 
     502           22 :                         return true;
     503              :                 }
     504              : 
     505           26 :                 bool parse_rule () {
     506           26 :                         var old_end = end;
     507           26 :                         var metadata = parse_pattern ();
     508           26 :                         if (metadata == null) {
     509            0 :                                 return false;
     510              :                         }
     511              : 
     512           26 :                         if (current == TokenType.EOF || old_end.line != end.line) {
     513              :                                 // eof or new rule
     514            4 :                                 return true;
     515              :                         }
     516           22 :                         return parse_args (metadata);
     517              :                 }
     518              :         }
     519              : 
     520              :         /*
     521              :          * GIR parser
     522              :          */
     523              : 
     524        15038 :         class Node {
     525         1538 :                 public static ArrayList<Node> new_namespaces = new ArrayList<Node> ();
     526              : 
     527              :                 public weak Node parent;
     528         2097 :                 public string element_type;
     529         2097 :                 public string name;
     530         2097 :                 public Map<string,string> girdata = null;
     531         4196 :                 public Metadata metadata = Metadata.empty;
     532         2097 :                 public SourceReference source_reference = null;
     533         4196 :                 public ArrayList<Node> members = new ArrayList<Node> (); // guarantees fields order
     534         4196 :                 public HashMap<string, ArrayList<Node>> scope = new HashMap<string, ArrayList<Node>> (str_hash, str_equal);
     535              : 
     536         2097 :                 public GirComment comment;
     537         2097 :                 public Symbol symbol;
     538              :                 public bool new_symbol;
     539              :                 public bool merged;
     540              :                 public bool processed;
     541              : 
     542              :                 // function-specific
     543         2099 :                 public int return_array_length_idx = -1;
     544         2097 :                 public List<ParameterInfo> parameters;
     545         2097 :                 public ArrayList<int> array_length_parameters;
     546         2097 :                 public ArrayList<int> closure_parameters;
     547         2097 :                 public ArrayList<int> destroy_parameters;
     548              :                 // record-specific
     549         2097 :                 public UnresolvedSymbol gtype_struct_for;
     550              :                 // class-specific
     551         2097 :                 public UnresolvedSymbol type_struct;
     552              :                 // alias-specific
     553         2097 :                 public DataType base_type;
     554              :                 // struct-specific
     555         2099 :                 public int array_length_idx = -1;
     556              :                 // objecttypesymbol-specific
     557         2097 :                 public List<DataType> inherited_types;
     558              : 
     559         2099 :                 public bool deprecated = false;
     560         2099 :                 public uint64 deprecated_version = 0;
     561         2097 :                 public string? deprecated_since = null;
     562         2097 :                 public string? deprecated_replacement = null;
     563              : 
     564         4198 :                 public Node (string? name) {
     565         4198 :                         this.name = name;
     566              :                 }
     567              : 
     568         1124 :                 public void add_member (Node node) {
     569          562 :                         var nodes = scope[node.name];
     570          562 :                         if (nodes == null) {
     571          534 :                                 nodes = new ArrayList<Node> ();
     572          534 :                                 scope[node.name] = nodes;
     573              :                         }
     574          562 :                         nodes.add (node);
     575          562 :                         members.add (node);
     576          562 :                         node.parent = this;
     577              :                 }
     578              : 
     579            2 :                 public void remove_member (Node node) {
     580            1 :                         var nodes = scope[node.name];
     581            1 :                         nodes.remove (node);
     582            1 :                         if (nodes.size == 0) {
     583            1 :                                 scope.remove (node.name);
     584              :                         }
     585            1 :                         members.remove (node);
     586            1 :                         node.parent = null;
     587              :                 }
     588              : 
     589         1494 :                 public Node? lookup (string name, bool create_namespace = false, SourceReference? source_reference = null) {
     590         1494 :                         var nodes = scope[name];
     591         1494 :                         Node node = null;
     592         1494 :                         if (nodes != null) {
     593          357 :                                 node = nodes[0];
     594              :                         }
     595         1553 :                         if (node == null) {
     596         1137 :                                 Symbol sym = null;
     597         1137 :                                 if (symbol != null) {
     598         1101 :                                         sym = symbol.scope.lookup (name);
     599              :                                 }
     600         1137 :                                 if (sym != null || create_namespace) {
     601           60 :                                         node = new Node (name);
     602          119 :                                         node.symbol = sym;
     603           60 :                                         node.new_symbol = node.symbol == null;
     604          113 :                                         node.source_reference = source_reference;
     605           60 :                                         add_member (node);
     606              : 
     607           60 :                                         if (sym == null) {
     608            1 :                                                 new_namespaces.add (node);
     609              :                                         }
     610              :                                 }
     611              :                         }
     612         1494 :                         return node;
     613              :                 }
     614              : 
     615          336 :                 public ArrayList<Node>? lookup_all (string name) {
     616          336 :                         return scope[name];
     617              :                 }
     618              : 
     619          141 :                 public UnresolvedSymbol get_unresolved_symbol () {
     620          141 :                         if (parent.name == null) {
     621           47 :                                 return new UnresolvedSymbol (null, name);
     622              :                         } else {
     623           94 :                                 return new UnresolvedSymbol (parent.get_unresolved_symbol (), name);
     624              :                         }
     625              :                 }
     626              : 
     627            0 :                 public string get_full_name () {
     628            0 :                         if (parent == null) {
     629            0 :                                 return name;
     630              :                         }
     631              : 
     632            0 :                         if (name == null) {
     633              :                                 return parent.get_full_name ();
     634              :                         }
     635              : 
     636            0 :                         if (parent.get_full_name () == null) {
     637            0 :                                 return name;
     638              :                         }
     639              : 
     640            0 :                         return "%s.%s".printf (parent.get_full_name (), name);
     641              :                 }
     642              : 
     643          501 :                 public string get_default_gir_name () {
     644          501 :                         GLib.StringBuilder default_name = new GLib.StringBuilder ();
     645              : 
     646         1298 :                         for (unowned Node? node = this ; node != null ; node = node.parent) {
     647         1298 :                                 if (node.symbol is Namespace) {
     648          502 :                                         if (node.symbol.has_attribute_argument ("CCode", "gir_namespace")) {
     649              :                                                 break;
     650              :                                         }
     651              :                                 }
     652              : 
     653          797 :                                 default_name.prepend (node.name);
     654              :                         }
     655              : 
     656         1002 :                         return default_name.str;
     657              :                 }
     658              : 
     659         1002 :                 public string get_gir_name () {
     660         1002 :                         var gir_name = girdata["name"];
     661         1002 :                         if (gir_name == null) {
     662            0 :                                 gir_name = girdata["glib:name"];
     663              :                         }
     664              :                         return gir_name;
     665              :                 }
     666              : 
     667         2735 :                 public string get_lower_case_cprefix () {
     668         2735 :                         if (name == null) {
     669           46 :                                 return "";
     670              :                         }
     671              : 
     672         2689 :                         var prefix = symbol.get_attribute_string ("CCode", "lower_case_cprefix");
     673         2689 :                         if (prefix == null && (symbol is ObjectTypeSymbol || symbol is Struct)) {
     674         1100 :                                 if (metadata.has_argument (ArgumentType.LOWER_CASE_CPREFIX)) {
     675            0 :                                         prefix = metadata.get_string (ArgumentType.LOWER_CASE_CPREFIX);
     676         1100 :                                 } else if (metadata.has_argument (ArgumentType.CPREFIX)) {
     677            0 :                                         prefix = metadata.get_string (ArgumentType.CPREFIX);
     678              :                                 } else {
     679         1100 :                                         prefix = symbol.get_attribute_string ("CCode", "cprefix");
     680              :                                 }
     681              :                         }
     682              : 
     683         2689 :                         if (prefix == null && girdata != null && (girdata.contains ("c:symbol-prefix") || girdata.contains("c:symbol-prefixes"))) {
     684              :                                 /* Use the prefix in the gir. We look up prefixes up to the root.
     685              :                                    If some node does not have girdata, we ignore it as i might be
     686              :                                    a namespace created due to reparenting. */
     687              :                                 unowned Node cur = this;
     688         2632 :                                 do {
     689         1974 :                                         if (cur.girdata != null) {
     690         1316 :                                                 var p = cur.girdata["c:symbol-prefix"];
     691         1316 :                                                 if (p == null) {
     692          658 :                                                         p = cur.girdata["c:symbol-prefixes"];
     693          658 :                                                         if (p != null) {
     694          658 :                                                                 var idx = p.index_of (",");
     695          658 :                                                                 if (idx >= 0) {
     696            0 :                                                                         p = p.substring (0, idx);
     697              :                                                                 }
     698              :                                                         }
     699              :                                                 }
     700              : 
     701         2632 :                                                 if (p != null) {
     702         1316 :                                                         prefix = "%s_%s".printf (p, prefix ?? "");
     703              :                                                 }
     704              :                                         }
     705              : 
     706         1974 :                                         cur = cur.parent;
     707         1974 :                                 } while (cur != null);
     708              :                         }
     709              : 
     710         2689 :                         if (prefix == null) {
     711         1035 :                                 prefix = get_default_lower_case_cprefix ();
     712              :                         }
     713         2735 :                         return prefix;
     714              :                 }
     715              : 
     716         1536 :                 public string get_default_lower_case_cprefix () {
     717         1536 :                         return "%s%s_".printf (parent.get_lower_case_cprefix (), get_lower_case_csuffix ());
     718              :                 }
     719              : 
     720         2040 :                 public string get_lower_case_csuffix () {
     721         2040 :                         var suffix = symbol.get_attribute_string ("CCode", "lower_case_csuffix");
     722         2040 :                         if (metadata.has_argument (ArgumentType.LOWER_CASE_CSUFFIX)) {
     723            0 :                                 suffix = metadata.get_string (ArgumentType.LOWER_CASE_CSUFFIX);
     724              :                         }
     725              : 
     726              :                         // we can't rely on gir suffix if metadata changed the name
     727         2040 :                         if (suffix == null && girdata != null && girdata["c:symbol-prefix"] != null && !metadata.has_argument (ArgumentType.NAME)) {
     728           57 :                                 suffix = girdata["c:symbol-prefix"];
     729              :                         }
     730         2040 :                         if (suffix == null) {
     731         1983 :                                 suffix = get_default_lower_case_csuffix ();
     732              :                         }
     733              :                         return suffix;
     734              :                 }
     735              : 
     736         2484 :                 public string get_default_lower_case_csuffix () {
     737         2484 :                         var csuffix = Symbol.camel_case_to_lower_case (name);
     738              : 
     739              :                         // FIXME Code duplication with CCodeAttribute.get_default_lower_case_suffix()
     740              :                         // remove underscores in some cases to avoid conflicts of type macros
     741         2484 :                         if (csuffix.has_prefix ("type_")) {
     742           23 :                                 csuffix = "type" + csuffix.substring ("type_".length);
     743         2461 :                         } else if (csuffix.has_prefix ("is_")) {
     744            0 :                                 csuffix = "is" + csuffix.substring ("is_".length);
     745              :                         }
     746         2484 :                         if (csuffix.has_suffix ("_class")) {
     747          317 :                                 csuffix = csuffix.substring (0, csuffix.length - "_class".length) + "class";
     748              :                         }
     749              :                         return csuffix;
     750              :                 }
     751              : 
     752          316 :                 public string get_cprefix () {
     753          316 :                         if (name == null) {
     754           92 :                                 return "";
     755              :                         }
     756              :                         string prefix;
     757          224 :                         if (metadata.has_argument (ArgumentType.CPREFIX)) {
     758            0 :                                 prefix = metadata.get_string (ArgumentType.CPREFIX);
     759              :                         } else {
     760          224 :                                 prefix = symbol.get_attribute_string ("CCode", "cprefix");
     761              :                         }
     762          224 :                         if (prefix == null && girdata != null && girdata["c:identifier-prefixes"] != null) {
     763            0 :                                 prefix = girdata["c:identifier-prefixes"];
     764            0 :                                 int idx = prefix.index_of (",");
     765            0 :                                 if (idx != -1) {
     766            0 :                                         prefix = prefix.substring (0, idx);
     767              :                                 }
     768              :                         }
     769          224 :                         if (prefix == null) {
     770           79 :                                 if (symbol is Enum || symbol is ErrorDomain) {
     771            0 :                                         prefix = "%s%s".printf (parent.get_lower_case_cprefix ().ascii_up (), name);
     772              :                                 } else {
     773           79 :                                         prefix = get_cname ();
     774              :                                 }
     775              :                         }
     776          316 :                         return prefix;
     777              :                 }
     778              : 
     779          840 :                 public string get_cname () {
     780          840 :                         if (name == null) {
     781            0 :                                 return "";
     782              :                         }
     783              :                         string cname;
     784          840 :                         if (metadata.has_argument (ArgumentType.CNAME)) {
     785            0 :                                 cname = metadata.get_string (ArgumentType.CNAME);
     786              :                         } else {
     787          840 :                                 cname = symbol.get_attribute_string ("CCode", "cname");
     788              :                         }
     789          840 :                         if (girdata != null) {
     790          830 :                                 if (cname == null) {
     791          813 :                                         cname = girdata["c:identifier"];
     792              :                                 }
     793          813 :                                 if (cname == null) {
     794          517 :                                         cname = girdata["c:type"];
     795              :                                 }
     796          517 :                                 if (cname == null) {
     797          206 :                                         cname = girdata["glib:type-name"];
     798              :                                 }
     799              :                         }
     800          216 :                         if (cname == null) {
     801          206 :                                 cname = get_default_cname ();
     802              :                         }
     803          840 :                         return cname;
     804              :                 }
     805              : 
     806          707 :                 public string get_default_cname () {
     807          707 :                         if (name == null) {
     808            0 :                                 return "";
     809              :                         }
     810          707 :                         if (symbol is Field) {
     811          161 :                                 if (((Field) symbol).binding == MemberBinding.STATIC) {
     812            0 :                                         return parent.get_lower_case_cprefix () + name;
     813              :                                 } else {
     814          322 :                                         return name;
     815              :                                 }
     816          546 :                         } else if (symbol is Method) {
     817          230 :                                 return "%s%s".printf (parent.get_lower_case_cprefix (), name);
     818              :                         } else {
     819          316 :                                 return "%s%s".printf (parent.get_cprefix (), name);
     820              :                         }
     821              :                 }
     822              : 
     823            0 :                 public string get_finish_cname () {
     824            0 :                         var finish_cname = symbol.get_attribute_string ("CCode", "finish_name");
     825            0 :                         if (finish_cname == null) {
     826            0 :                                 finish_cname = get_cname ();
     827            0 :                                 if (finish_cname.has_suffix ("_async")) {
     828            0 :                                         finish_cname = finish_cname.substring (0, finish_cname.length - "_async".length);
     829              :                                 }
     830            0 :                                 finish_cname = "%s_finish".printf (finish_cname);
     831              :                         }
     832              :                         return finish_cname;
     833              :                 }
     834              : 
     835          343 :                 public string get_cheader_filename () {
     836          343 :                         if (metadata.has_argument (ArgumentType.CHEADER_FILENAME)) {
     837            0 :                                 return metadata.get_string (ArgumentType.CHEADER_FILENAME);
     838              :                         }
     839          343 :                         var cheader_filename = symbol.get_attribute_string ("CCode", "cheader_filename");
     840          343 :                         if (cheader_filename != null) {
     841          343 :                                 return cheader_filename;
     842              :                         }
     843          148 :                         if (parent.name != null) {
     844          148 :                                 return parent.get_cheader_filename ();
     845            0 :                         } else if (symbol.source_reference != null) {
     846            0 :                                 return symbol.source_reference.file.get_cinclude_filename ();
     847              :                         }
     848            0 :                         return "";
     849              :                 }
     850              : 
     851            1 :                 private static uint64 parse_version_string (string version) {
     852            1 :                         int64 res = 0;
     853            1 :                         int shift = 16;
     854            1 :                         string[] tokens = version.split (".", 3);
     855              : 
     856            4 :                         foreach (unowned string token in tokens) {
     857              :                                 int64 t;
     858              : 
     859            3 :                                 if (!int64.try_parse (token, out t))
     860            0 :                                         return 0;
     861            3 :                                 if (t > 0xffff)
     862            0 :                                         return 0;
     863              : 
     864            3 :                                 res |= (t << shift);
     865            3 :                                 shift -= 8;
     866              :                         }
     867              : 
     868            1 :                         return res;
     869              :                 }
     870              : 
     871           52 :                 static void move_class_methods (Node target, Node? source) {
     872           52 :                         if (source == null) {
     873              :                                 return;
     874              :                         }
     875              : 
     876              :                         var i = 0;
     877           89 :                         while (i < source.members.size) {
     878           45 :                                 var node = source.members[i];
     879           45 :                                 if (node.symbol is Method) {
     880            1 :                                         source.remove_member (node);
     881            1 :                                         target.add_member (node);
     882              : 
     883            1 :                                         ((Method) node.symbol).binding = MemberBinding.CLASS;
     884              :                                 } else {
     885           44 :                                         i++;
     886              :                                 }
     887              :                         }
     888              :                 }
     889              : 
     890         2123 :                 public void process (GirParser parser) {
     891         2123 :                         if (processed) {
     892              :                                 return;
     893              :                         }
     894              : 
     895         2041 :                         if (symbol is Namespace && parent == parser.root) {
     896              :                                 // first process aliases since they have no assigned symbol
     897          195 :                                 foreach (var node in members) {
     898          149 :                                         if (node.element_type == "alias") {
     899            5 :                                                 parser.process_alias (node);
     900              :                                         }
     901              :                                 }
     902              : 
     903              :                                 // auto reparent namespace methods, allowing node removals
     904          195 :                                 for (int i=0; i < members.size; i++) {
     905          149 :                                         var node = members[i];
     906          149 :                                         if (node.symbol is Method && node.new_symbol) {
     907           36 :                                                 parser.process_namespace_method (this, node);
     908           36 :                                                 if (i < members.size && members[i] != node) {
     909              :                                                         // node removed in the middle
     910            0 :                                                         i--;
     911              :                                                 }
     912              :                                         }
     913              :                                 }
     914              :                         }
     915              : 
     916         2072 :                         if (symbol is Class && girdata != null) {
     917           31 :                                 if (type_struct != null) {
     918           26 :                                         move_class_methods (this, parser.resolve_node (parent, type_struct));
     919              :                                 }
     920           31 :                                 var class_struct = girdata["glib:type-struct"];
     921           31 :                                 if (class_struct != null) {
     922           26 :                                         move_class_methods (this, parser.resolve_node (parent, parser.parse_symbol_from_string (class_struct, source_reference)));
     923              :                                 }
     924              :                         }
     925              : 
     926              :                         // process children
     927         3047 :                         foreach (var node in members) {
     928          503 :                                 node.process (parser);
     929              :                         }
     930              : 
     931         2542 :                         if (girdata != null) {
     932              :                                 // GIR node processing
     933          693 :                                 if (symbol is Method) {
     934          192 :                                         var m = (Method) symbol;
     935          192 :                                         parser.process_callable (this);
     936              : 
     937          192 :                                         var colliding = parent.lookup_all (name);
     938          435 :                                         foreach (var node in colliding) {
     939          243 :                                                 var sym = node.symbol;
     940          243 :                                                 if (sym is Field) {
     941            0 :                                                         if (m.return_type.compatible (((Field) sym).variable_type) && m.get_parameters ().size == 0) {
     942              :                                                                 // assume method is getter
     943            0 :                                                                 merged = true;
     944              :                                                         } else {
     945            0 :                                                                 Report.warning (symbol.source_reference, "Field `%s' conflicts with method of the same name", get_full_name ());
     946              :                                                         }
     947          246 :                                                 } else if (sym is Signal) {
     948            3 :                                                         node.process (parser);
     949            3 :                                                         var sig = (Signal) sym;
     950            3 :                                                         if (m.is_virtual || m.is_abstract) {
     951            2 :                                                                 sig.is_virtual = true;
     952              :                                                         } else {
     953            1 :                                                                 sig.set_attribute ("HasEmitter", true);
     954              :                                                         }
     955            3 :                                                         parser.assume_parameter_names (sig, m, false);
     956            3 :                                                         if (m.get_parameters().size != sig.get_parameters().size) {
     957            0 :                                                                 Report.warning (symbol.source_reference, "Signal `%s' conflicts with method of the same name", get_full_name ());
     958              :                                                         }
     959            3 :                                                         merged = true;
     960          240 :                                                 } else if (sym is Method && !(sym is CreationMethod) && node != this) {
     961           48 :                                                         if (m.is_virtual || m.is_abstract) {
     962           24 :                                                                 bool different_invoker = false;
     963           24 :                                                                 var no_wrapper = m.has_attribute ("NoWrapper");
     964           24 :                                                                 if (no_wrapper) {
     965              :                                                                         /* no invoker but this method has the same name,
     966              :                                                                            most probably the invoker has a different name
     967              :                                                                            and g-ir-scanner missed it */
     968            0 :                                                                         var invoker = parser.find_invoker (this);
     969            0 :                                                                         if (invoker != null) {
     970            0 :                                                                                 m.set_attribute_string ("CCode", "vfunc_name", m.name);
     971            0 :                                                                                 m.name = invoker.symbol.name;
     972            0 :                                                                                 m.set_attribute ("NoWrapper", false);
     973            0 :                                                                                 invoker.merged = true;
     974            0 :                                                                                 different_invoker = true;
     975              :                                                                         }
     976              :                                                                 }
     977            0 :                                                                 if (!different_invoker) {
     978           24 :                                                                         if (no_wrapper) {
     979            0 :                                                                                 Report.warning (symbol.source_reference, "Virtual method `%s' conflicts with method of the same name", get_full_name ());
     980              :                                                                         }
     981           24 :                                                                         node.merged = true;
     982              :                                                                 }
     983           24 :                                                         } else if (m.is_class_member ()) {
     984            0 :                                                                 Report.warning (symbol.source_reference, "Class method `%s' conflicts with method of the same name", get_full_name ());
     985            0 :                                                                 node.merged = true;
     986              :                                                         }
     987              :                                                 }
     988              :                                         }
     989          192 :                                         if (!(m is CreationMethod)) {
     990          164 :                                                 if (metadata.has_argument (ArgumentType.DESTROYS_INSTANCE)) {
     991            0 :                                                         m.set_attribute ("DestroysInstance", metadata.get_bool (ArgumentType.DESTROYS_INSTANCE));
     992              :                                                 }
     993          164 :                                                 if (metadata.has_argument (ArgumentType.RETURNS_MODIFIED_POINTER)) {
     994            0 :                                                         m.set_attribute ("ReturnsModifiedPointer", metadata.get_bool (ArgumentType.RETURNS_MODIFIED_POINTER));
     995              :                                                 }
     996              :                                                 // merge custom vfunc
     997          164 :                                                 if (metadata.has_argument (ArgumentType.VFUNC_NAME)) {
     998            0 :                                                         var vfunc = parent.lookup (metadata.get_string (ArgumentType.VFUNC_NAME));
     999            0 :                                                         if (vfunc != null && vfunc != this) {
    1000            0 :                                                                 vfunc.processed = true;
    1001            0 :                                                                 vfunc.merged = true;
    1002              :                                                         }
    1003              :                                                 }
    1004              :                                         }
    1005          192 :                                         if (metadata.has_argument (ArgumentType.DELEGATE_TARGET)) {
    1006            0 :                                                 m.set_attribute_bool ("CCode", "delegate_target", metadata.get_bool (ArgumentType.DELEGATE_TARGET));
    1007              :                                         }
    1008          192 :                                         if (m.coroutine) {
    1009           14 :                                                 parser.process_async_method (this);
    1010              :                                         }
    1011          325 :                                 } else if (symbol is Property) {
    1012           16 :                                         var colliding = parent.lookup_all (name);
    1013           32 :                                         foreach (var node in colliding) {
    1014           16 :                                                 if (node.symbol is Signal) {
    1015              :                                                         // properties take precedence
    1016            0 :                                                         node.processed = true;
    1017            0 :                                                         node.merged = true;
    1018            0 :                                                         Report.warning (symbol.source_reference, "Signal `%s' conflicts with property of the same name", get_full_name ());
    1019           16 :                                                 } else if (node.symbol is Method) {
    1020              :                                                         // getter in C, but not in Vala
    1021            0 :                                                         node.merged = true;
    1022              :                                                 }
    1023              :                                         }
    1024              : 
    1025           16 :                                         var prop = (Property) symbol;
    1026              : 
    1027              :                                         // add accessors, can't do this before gir symbol resolution
    1028           16 :                                         var readable = girdata["readable"];
    1029           16 :                                         var writable = girdata["writable"];
    1030           16 :                                         var construct_ = girdata["construct"];
    1031           16 :                                         var construct_only = girdata["construct-only"];
    1032           16 :                                         if (readable != "0") {
    1033           13 :                                                 prop.get_accessor = new PropertyAccessor (true, false, false, prop.property_type.copy (), null, null);
    1034              :                                         }
    1035           16 :                                         if (writable == "1" || construct_only == "1") {
    1036           16 :                                                 prop.set_accessor = new PropertyAccessor (false, (construct_only != "1") && (writable == "1"), (construct_only == "1") || (construct_ == "1"), prop.property_type.copy (), null, null);
    1037              :                                         }
    1038              : 
    1039              :                                         // there is no information about the internal ownership so assume `owned` as default
    1040           16 :                                         prop.property_type.value_owned = true;
    1041              : 
    1042              :                                         // find virtual/abstract accessors to handle abstract properties properly
    1043              : 
    1044           16 :                                         Node getter = null;
    1045           16 :                                         var getters = parent.lookup_all ("get_%s".printf (name));
    1046           16 :                                         if (getters != null) {
    1047           20 :                                                 foreach (var g in getters) {
    1048            7 :                                                         if ((getter == null || !g.merged) && g.get_cname () == "%sget_%s".printf (parent.get_lower_case_cprefix (), name)) {
    1049           12 :                                                                 getter = g;
    1050              :                                                         }
    1051              :                                                 }
    1052              :                                         }
    1053              : 
    1054           16 :                                         Node setter = null;
    1055           16 :                                         var setters = parent.lookup_all ("set_%s".printf (name));
    1056           16 :                                         if (setters != null) {
    1057           23 :                                                 foreach (var s in setters) {
    1058            8 :                                                         if ((setter == null || !s.merged) && s.get_cname () == "%sset_%s".printf (parent.get_lower_case_cprefix (), name)) {
    1059           14 :                                                                 setter = s;
    1060              :                                                         }
    1061              :                                                 }
    1062              :                                         }
    1063              : 
    1064           16 :                                         prop.set_attribute ("NoAccessorMethod", (readable == "0" && construct_only == "1"));
    1065           29 :                                         if (prop.get_accessor != null) {
    1066           13 :                                                 var m = getter != null ? getter.symbol as Method : null;
    1067              :                                                 // ensure getter vfunc if the property is abstract
    1068           13 :                                                 if (m != null) {
    1069            5 :                                                         getter.process (parser);
    1070            5 :                                                         if (m.return_type is VoidType || m.get_parameters().size != 0 || m.tree_can_fail) {
    1071            1 :                                                                 prop.set_attribute ("NoAccessorMethod", true);
    1072              :                                                         } else {
    1073            4 :                                                                 if (getter.name == name) {
    1074            0 :                                                                         foreach (var node in colliding) {
    1075            0 :                                                                                 if (node.symbol is Method) {
    1076            0 :                                                                                         node.merged = true;
    1077              :                                                                                 }
    1078              :                                                                         }
    1079              :                                                                 }
    1080              : 
    1081            4 :                                                                 prop.get_accessor.value_type.value_owned = m.return_type.value_owned;
    1082              : 
    1083            4 :                                                                 if (!m.is_abstract && !m.is_virtual && prop.is_abstract) {
    1084            0 :                                                                         prop.set_attribute ("ConcreteAccessor", true);
    1085              :                                                                 }
    1086              :                                                         }
    1087              :                                                 } else {
    1088            8 :                                                         prop.set_attribute ("NoAccessorMethod", true);
    1089              :                                                 }
    1090              :                                         }
    1091              : 
    1092           21 :                                         if (!prop.has_attribute ("NoAccessorMethod") && prop.set_accessor != null && prop.set_accessor.writable) {
    1093            5 :                                                 var m = setter != null ? setter.symbol as Method : null;
    1094              :                                                 // ensure setter vfunc if the property is abstract
    1095            5 :                                                 if (m != null) {
    1096            5 :                                                         setter.process (parser);
    1097            5 :                                                         if (!(m.return_type is VoidType || m.return_type is BooleanType) || m.get_parameters ().size != 1 || m.tree_can_fail) {
    1098            1 :                                                                 prop.set_attribute ("NoAccessorMethod", true);
    1099            1 :                                                                 prop.set_attribute ("ConcreteAccessor", false);
    1100              :                                                         } else {
    1101            4 :                                                                 prop.set_accessor.value_type.value_owned = m.get_parameters()[0].variable_type.value_owned;
    1102            4 :                                                                 if (prop.has_attribute ("ConcreteAccessor") && !m.is_abstract && !m.is_virtual && prop.is_abstract) {
    1103            0 :                                                                         prop.set_attribute ("ConcreteAccessor", true);
    1104            0 :                                                                         prop.set_attribute ("NoAccessorMethod", false);
    1105              :                                                                 }
    1106              :                                                         }
    1107              :                                                 } else {
    1108            0 :                                                         prop.set_attribute ("NoAccessorMethod", true);
    1109            0 :                                                         prop.set_attribute ("ConcreteAccessor", false);
    1110              :                                                 }
    1111              :                                         }
    1112              : 
    1113           16 :                                         if (prop.has_attribute ("NoAccessorMethod")) {
    1114           13 :                                                 if (!prop.overrides && parent.symbol is Class) {
    1115              :                                                         // bug 742012
    1116              :                                                         // find base interface property with ConcreteAccessor and this overriding property with NoAccessorMethod
    1117           11 :                                                         var base_prop_node = parser.base_interface_property (this);
    1118           12 :                                                         if (base_prop_node != null) {
    1119            1 :                                                                 base_prop_node.process (parser);
    1120              : 
    1121            1 :                                                                 var base_property = (Property) base_prop_node.symbol;
    1122            1 :                                                                 if (base_property.has_attribute ("ConcreteAccessor")) {
    1123            0 :                                                                         prop.set_attribute ("NoAccessorMethod", false);
    1124            0 :                                                                         if (prop.get_accessor != null) {
    1125            0 :                                                                                 prop.get_accessor.value_type.value_owned = base_property.get_accessor.value_type.value_owned;
    1126              :                                                                         }
    1127            0 :                                                                         if (prop.set_accessor != null) {
    1128            0 :                                                                                 prop.set_accessor.value_type.value_owned = base_property.set_accessor.value_type.value_owned;
    1129              :                                                                         }
    1130              : 
    1131              :                                                                 }
    1132              :                                                         }
    1133              :                                                 }
    1134              :                                         }
    1135              : 
    1136           16 :                                         if (metadata.has_argument (ArgumentType.NO_ACCESSOR_METHOD)) {
    1137            0 :                                                 prop.set_attribute ("NoAccessorMethod", metadata.get_bool (ArgumentType.NO_ACCESSOR_METHOD));
    1138              :                                         }
    1139              : 
    1140           16 :                                         if (prop.has_attribute ("NoAccessorMethod")) {
    1141              :                                                 // gobject defaults
    1142           12 :                                                 if (prop.get_accessor != null) {
    1143           10 :                                                         prop.get_accessor.value_type.value_owned = true;
    1144              :                                                 }
    1145           12 :                                                 if (prop.set_accessor != null) {
    1146           12 :                                                         prop.set_accessor.value_type.value_owned = false;
    1147              :                                                 }
    1148              :                                         }
    1149          355 :                                 } else if (symbol is Field) {
    1150           62 :                                         var field = (Field) symbol;
    1151           62 :                                         var colliding = parent.lookup_all (name);
    1152           62 :                                         if (colliding.size > 1) {
    1153              :                                                 // whatelse has precedence over the field
    1154            0 :                                                 merged = true;
    1155              :                                         }
    1156              : 
    1157           62 :                                         if (metadata.has_argument (ArgumentType.DELEGATE_TARGET)) {
    1158            0 :                                                 field.set_attribute_bool ("CCode", "delegate_target", metadata.get_bool (ArgumentType.DELEGATE_TARGET));
    1159              :                                         }
    1160           62 :                                         if (metadata.has_argument (ArgumentType.DELEGATE_TARGET_CNAME)) {
    1161            0 :                                                 field.set_attribute_string ("CCode", "delegate_target_cname", metadata.get_string (ArgumentType.DELEGATE_TARGET_CNAME));
    1162              :                                         }
    1163           62 :                                         if (metadata.has_argument (ArgumentType.DESTROY_NOTIFY_CNAME)) {
    1164            0 :                                                 field.set_attribute_string ("CCode", "destroy_notify_cname", metadata.get_string (ArgumentType.DESTROY_NOTIFY_CNAME));
    1165              :                                         }
    1166              : 
    1167           96 :                                         if (field.variable_type is DelegateType && parent.gtype_struct_for != null) {
    1168              :                                                 // virtual method field
    1169           34 :                                                 var d = ((DelegateType) field.variable_type).delegate_symbol;
    1170           34 :                                                 parser.process_virtual_method_field (this, d, parent.gtype_struct_for);
    1171           34 :                                                 merged = true;
    1172           29 :                                         } else if (field.variable_type is DelegateType) {
    1173              :                                                 // anonymous delegate
    1174            1 :                                                 var d = ((DelegateType) field.variable_type).delegate_symbol;
    1175            1 :                                                 if (this.lookup (d.name).parent == this) {
    1176            1 :                                                         d.set_attribute_bool ("CCode", "has_typedef", false);
    1177            1 :                                                         if (d.has_target && !metadata.has_argument (ArgumentType.DELEGATE_TARGET)) {
    1178            0 :                                                                 field.set_attribute_bool ("CCode", "delegate_target", false);
    1179              :                                                         }
    1180            1 :                                                         d.name = "%s%sFunc".printf (parent.symbol.name, Symbol.lower_case_to_camel_case (d.name));
    1181            1 :                                                         get_parent_namespace (this).add_delegate (d);
    1182              :                                                 }
    1183           30 :                                         } else if (field.variable_type is ArrayType) {
    1184              :                                                 Node array_length;
    1185            3 :                                                 if (metadata.has_argument (ArgumentType.ARRAY_LENGTH_FIELD)) {
    1186            0 :                                                         array_length = parent.lookup (metadata.get_string (ArgumentType.ARRAY_LENGTH_FIELD));
    1187            3 :                                                 } else if (array_length_idx > -1 && parent.members.size > array_length_idx) {
    1188            0 :                                                         array_length = parent.members[array_length_idx];
    1189              :                                                 } else {
    1190            3 :                                                         array_length = parent.lookup ("n_%s".printf (field.name));
    1191            3 :                                                         if (array_length == null) {
    1192            3 :                                                                 array_length = parent.lookup ("num_%s".printf (field.name));
    1193            3 :                                                                 if (array_length == null) {
    1194            3 :                                                                         array_length = parent.lookup ("%s_length".printf (field.name));
    1195            3 :                                                                         if (array_length == null) {
    1196            3 :                                                                                 array_length = parent.lookup ("%s_length1".printf (field.name));
    1197              :                                                                         }
    1198              :                                                                 }
    1199              :                                                         }
    1200              :                                                 }
    1201            4 :                                                 if (array_length != null && array_length.symbol is Field) {
    1202            1 :                                                         var length_field = (Field) array_length.symbol;
    1203              :                                                         // array has length
    1204            1 :                                                         field.set_attribute_string ("CCode", "array_length_cname", length_field.name);
    1205            1 :                                                         var length_type = length_field.variable_type.to_qualified_string ();
    1206            1 :                                                         if (length_type != "int") {
    1207            0 :                                                                 var st = parser.root.lookup (length_type);
    1208            0 :                                                                 if (st != null) {
    1209            0 :                                                                         field.set_attribute_string ("CCode", "array_length_type", st.get_cname ());
    1210              :                                                                 }
    1211              :                                                         }
    1212            1 :                                                         field.remove_attribute_argument ("CCode", "array_length");
    1213            1 :                                                         field.remove_attribute_argument ("CCode", "array_null_terminated");
    1214              :                                                 }
    1215              :                                         }
    1216          231 :                                 } else if (symbol is Signal || symbol is Delegate) {
    1217           50 :                                         parser.process_callable (this);
    1218          181 :                                 } else if (symbol is Class) {
    1219           31 :                                         parser.process_class (this);
    1220          150 :                                 } else if (symbol is Interface) {
    1221            7 :                                         parser.process_interface (this);
    1222          143 :                                 } else if (symbol is Struct) {
    1223           38 :                                         if (parent.symbol is ObjectTypeSymbol || parent.symbol is Struct) {
    1224              :                                                 // nested struct
    1225            0 :                                                 foreach (var fn in members) {
    1226            0 :                                                         var f = fn.symbol as Field;
    1227            0 :                                                         if (f != null) {
    1228            0 :                                                                 if (f.binding == MemberBinding.INSTANCE) {
    1229            0 :                                                                         f.set_attribute_string ("CCode", "cname", "%s.%s".printf (name, fn.get_cname ()));
    1230              :                                                                 }
    1231            0 :                                                                 f.name = "%s_%s".printf (symbol.name, f.name);
    1232            0 :                                                                 fn.name = f.name;
    1233            0 :                                                                 parent.add_member (fn);
    1234              :                                                         }
    1235              :                                                 }
    1236            0 :                                                 merged = true;
    1237              :                                         } else {
    1238              :                                                 // record for a gtype
    1239           67 :                                                 if (gtype_struct_for != null) {
    1240           31 :                                                         var obj = parser.resolve_node (parent, gtype_struct_for);
    1241           31 :                                                         if (obj != null && obj.symbol is Interface && "%sIface".printf (obj.get_cname ()) != get_cname ()) {
    1242              :                                                                 // set the interface struct name
    1243            1 :                                                                 obj.symbol.set_attribute_string ("CCode", "type_cname", get_cname ());
    1244           30 :                                                         } else if (obj != null && obj.symbol is Class && "%sClass".printf (obj.get_cname ()) != get_cname ()) {
    1245              :                                                                 // set the class struct name
    1246            1 :                                                                 obj.symbol.set_attribute_string ("CCode", "type_cname", get_cname ());
    1247              :                                                         }
    1248           31 :                                                         merged = true;
    1249              :                                                 }
    1250              :                                         }
    1251              :                                 }
    1252              : 
    1253              :                                 // deprecated
    1254          501 :                                 if (metadata.has_argument (ArgumentType.REPLACEMENT)) {
    1255            0 :                                         deprecated = true;
    1256            0 :                                         deprecated_replacement = metadata.get_string (ArgumentType.REPLACEMENT);
    1257              :                                 }
    1258          501 :                                 if (metadata.has_argument (ArgumentType.DEPRECATED_SINCE)) {
    1259            0 :                                         deprecated = true;
    1260            0 :                                         deprecated_since = metadata.get_string (ArgumentType.DEPRECATED_SINCE);
    1261          501 :                                 } else if (girdata["deprecated-version"] != null) {
    1262            1 :                                         deprecated = true;
    1263            1 :                                         deprecated_since = girdata.get ("deprecated-version");
    1264              :                                 }
    1265          501 :                                 if (metadata.has_argument (ArgumentType.DEPRECATED)) {
    1266            0 :                                         deprecated = metadata.get_bool (ArgumentType.DEPRECATED, true);
    1267            0 :                                         if (!deprecated) {
    1268            0 :                                                 deprecated_since = null;
    1269            0 :                                                 deprecated_replacement = null;
    1270              :                                         }
    1271          501 :                                 } else if (girdata["deprecated"] != null) {
    1272            1 :                                         deprecated = true;
    1273              :                                 }
    1274          501 :                                 if (deprecated_since != null) {
    1275            1 :                                         deprecated_version = parse_version_string (deprecated_since);
    1276              :                                 }
    1277              : 
    1278              :                                 // experimental
    1279          501 :                                 if (metadata.has_argument (ArgumentType.EXPERIMENTAL)) {
    1280            0 :                                         symbol.set_attribute_bool ("Version", "experimental", metadata.get_bool (ArgumentType.EXPERIMENTAL));
    1281              :                                 }
    1282              : 
    1283              :                                 // since
    1284          501 :                                 if (metadata.has_argument (ArgumentType.SINCE)) {
    1285            0 :                                         symbol.version.since = metadata.get_string (ArgumentType.SINCE);
    1286          501 :                                 } else if (symbol is Namespace == false && girdata["version"] != null) {
    1287            1 :                                         symbol.version.since = girdata.get ("version");
    1288              :                                 }
    1289              : 
    1290          501 :                                 if (parent.symbol is Namespace) {
    1291              :                                         // always write cheader filename for namespace children
    1292          195 :                                         symbol.set_attribute_string ("CCode", "cheader_filename", get_cheader_filename ());
    1293          306 :                                 } else if (metadata.has_argument (ArgumentType.CHEADER_FILENAME)) {
    1294            0 :                                         symbol.set_attribute_string ("CCode", "cheader_filename", metadata.get_string (ArgumentType.CHEADER_FILENAME));
    1295              :                                 }
    1296          501 :                                 if (get_cname () != get_default_cname ()) {
    1297           82 :                                         symbol.set_attribute_string ("CCode", "cname", get_cname ());
    1298              :                                 }
    1299              : 
    1300          501 :                                 if (metadata.has_argument (ArgumentType.FEATURE_TEST_MACRO)) {
    1301            0 :                                         symbol.set_attribute_string ("CCode", "feature_test_macro", metadata.get_string (ArgumentType.FEATURE_TEST_MACRO));
    1302              :                                 }
    1303              : 
    1304              :                                 // lower_case_cprefix
    1305          501 :                                 if (get_lower_case_cprefix () != get_default_lower_case_cprefix ()) {
    1306            0 :                                         symbol.set_attribute_string ("CCode", "lower_case_cprefix", get_lower_case_cprefix ());
    1307              :                                 }
    1308              :                                 // lower_case_csuffix
    1309          501 :                                 if (get_lower_case_csuffix () != get_default_lower_case_csuffix ()) {
    1310            3 :                                         symbol.set_attribute_string ("CCode", "lower_case_csuffix", get_lower_case_csuffix ());
    1311              :                                 }
    1312              : 
    1313              :                                 // set gir name if the symbol has been renamed
    1314          501 :                                 string gir_name = get_gir_name ();
    1315          501 :                                 string default_gir_name = get_default_gir_name ();
    1316          501 :                                 if (is_container (symbol) && !(symbol is Namespace) && (name != gir_name || gir_name != default_gir_name)) {
    1317            0 :                                         symbol.set_attribute_string ("GIR", "name", gir_name);
    1318              :                                 }
    1319              :                         }
    1320              : 
    1321         2073 :                         if (!(new_symbol && merged) && is_container (symbol)) {
    1322         2118 :                                 foreach (var node in members) {
    1323          472 :                                         if (this.deprecated_version > 0 && node.deprecated_version > 0) {
    1324            0 :                                                 if (this.deprecated_version <= node.deprecated_version) {
    1325            0 :                                                         node.deprecated = false;
    1326            0 :                                                         node.deprecated_since = null;
    1327            0 :                                                         node.deprecated_replacement = null;
    1328              :                                                 }
    1329              :                                         }
    1330          472 :                                         if (node.deprecated) {
    1331            1 :                                                 node.symbol.version.deprecated = true;
    1332              :                                         }
    1333          472 :                                         if (node.deprecated_since != null) {
    1334            1 :                                                 node.symbol.version.deprecated_since = node.deprecated_since;
    1335              :                                         }
    1336          472 :                                         if (node.deprecated_replacement != null) {
    1337            0 :                                                 node.symbol.version.replacement = node.deprecated_replacement;
    1338              :                                         }
    1339              : 
    1340          472 :                                         if (node.new_symbol && !node.merged && !metadata.get_bool (ArgumentType.HIDDEN)) {
    1341          367 :                                                 if (symbol.name == null || node.lookup (symbol.name) == null) {
    1342          367 :                                                         add_symbol_to_container (symbol, node.symbol);
    1343              :                                                 }
    1344              :                                         }
    1345              :                                 }
    1346              : 
    1347         1646 :                                 var cl = symbol as Class;
    1348         1690 :                                 if (cl != null && !cl.is_compact && cl.default_construction_method == null) {
    1349              :                                         // always provide constructor in generated bindings
    1350              :                                         // to indicate that implicit Object () chainup is allowed
    1351           12 :                                         var cm = new CreationMethod (null, null, cl.source_reference);
    1352           12 :                                         cm.has_construct_function = false;
    1353           12 :                                         cm.access = SymbolAccessibility.PROTECTED;
    1354           12 :                                         cl.add_method (cm);
    1355              :                                 }
    1356              :                         }
    1357              : 
    1358         2041 :                         processed = true;
    1359              :                 }
    1360              : 
    1361            0 :                 public string to_string () {
    1362            0 :                         if (parent.name == null) {
    1363            0 :                                 return name;
    1364              :                         } else {
    1365            0 :                                 return "%s.%s".printf (parent.to_string (), name);
    1366              :                         }
    1367              :                 }
    1368              :         }
    1369              : 
    1370              :         static GLib.Regex type_from_string_regex;
    1371              : 
    1372         1538 :         MarkupReader reader;
    1373              : 
    1374         1538 :         CodeContext context;
    1375              : 
    1376         1538 :         SourceFile current_source_file;
    1377         1538 :         Node root;
    1378         3076 :         ArrayList<Metadata> metadata_roots = new ArrayList<Metadata> ();
    1379              : 
    1380              :         SourceLocation begin;
    1381              :         SourceLocation end;
    1382              :         MarkupTokenType current_token;
    1383              : 
    1384         1538 :         string[] cheader_filenames;
    1385              : 
    1386         1538 :         ArrayList<Metadata> metadata_stack;
    1387         1538 :         Metadata metadata;
    1388         1538 :         ArrayList<Node> tree_stack;
    1389         1538 :         Node current;
    1390         1538 :         Node old_current;
    1391              : 
    1392         3076 :         Set<string> provided_namespaces = new HashSet<string> (str_hash, str_equal);
    1393         3076 :         HashMap<UnresolvedSymbol,Symbol> unresolved_symbols_map = new HashMap<UnresolvedSymbol,Symbol> (unresolved_symbol_hash, unresolved_symbol_equal);
    1394         3076 :         ArrayList<UnresolvedSymbol> unresolved_gir_symbols = new ArrayList<UnresolvedSymbol> ();
    1395         3076 :         HashMap<UnresolvedType,Node> unresolved_type_arguments = new HashMap<UnresolvedType,Node> ();
    1396         3076 :         ArrayList<Interface> ifaces_needing_object_prereq = new ArrayList<Interface> ();
    1397              : 
    1398              :         /**
    1399              :          * Parses all .gir source files in the specified code
    1400              :          * context and builds a code tree.
    1401              :          *
    1402              :          * @param context a code context
    1403              :          */
    1404         3067 :         public void parse (CodeContext context) {
    1405         1538 :                 this.context = context;
    1406              : 
    1407         1538 :                 root = new Node (null);
    1408        74830 :                 root.symbol = context.root;
    1409         1538 :                 tree_stack = new ArrayList<Node> ();
    1410         3718 :                 current = root;
    1411              : 
    1412         1538 :                 map_vala_to_gir ();
    1413              : 
    1414         1538 :                 context.accept (this);
    1415              : 
    1416         1538 :                 resolve_gir_symbols ();
    1417         1538 :                 create_new_namespaces ();
    1418         1538 :                 resolve_type_arguments ();
    1419              : 
    1420         1538 :                 root.process (this);
    1421              : 
    1422              :                 /* Temporarily workaround G-I bug not adding GLib.Object prerequisite:
    1423              :                    ensure we have at least one instantiable prerequisite */
    1424         1538 :                 var glib_ns = context.root.scope.lookup ("GLib") as Namespace;
    1425         4596 :                 if (glib_ns != null) {
    1426         1529 :                         var object_type = (Class) glib_ns.scope.lookup ("Object");
    1427         1537 :                         foreach (var iface in ifaces_needing_object_prereq) {
    1428            4 :                                 iface.add_prerequisite (new ObjectType (object_type));
    1429              :                         }
    1430              :                 }
    1431              : 
    1432         1540 :                 foreach (var metadata in metadata_roots) {
    1433            1 :                         report_unused_metadata (metadata);
    1434              :                 }
    1435              : 
    1436         1538 :                 this.context = null;
    1437              :         }
    1438              : 
    1439         1538 :         void map_vala_to_gir () {
    1440        13196 :                 foreach (var source_file in context.get_source_files ()) {
    1441         6761 :                         string gir_namespace = source_file.gir_namespace;
    1442         6761 :                         string gir_version = source_file.gir_version;
    1443         6761 :                         Namespace ns = null;
    1444         6761 :                         if (gir_namespace == null) {
    1445      4927939 :                                 foreach (var node in source_file.get_nodes ()) {
    1446      2465486 :                                         if (node is Namespace) {
    1447        68508 :                                                 ns = (Namespace) node;
    1448        68508 :                                                 gir_namespace = ns.get_attribute_string ("CCode", "gir_namespace");
    1449        68508 :                                                 if (gir_namespace != null) {
    1450         4897 :                                                         gir_version = ns.get_attribute_string ("CCode", "gir_version");
    1451         4897 :                                                         break;
    1452              :                                                 }
    1453              :                                         }
    1454              :                                 }
    1455              :                         }
    1456         6761 :                         if (gir_namespace == null) {
    1457         1864 :                                 continue;
    1458              :                         }
    1459              : 
    1460         4897 :                         provided_namespaces.add ("%s-%s".printf (gir_namespace, gir_version));
    1461              : 
    1462         4897 :                         var gir_symbol = new UnresolvedSymbol (null, gir_namespace);
    1463         4897 :                         if (gir_namespace != ns.name) {
    1464         3219 :                                 set_symbol_mapping (gir_symbol, ns);
    1465              :                         }
    1466              : 
    1467      4846631 :                         foreach (var node in source_file.get_nodes ()) {
    1468      2482482 :                                 if (node.has_attribute_argument ("GIR", "name")) {
    1469        61615 :                                         var map_from = new UnresolvedSymbol (gir_symbol, node.get_attribute_string ("GIR", "name"));
    1470        61615 :                                         set_symbol_mapping (map_from, (Symbol) node);
    1471              :                                 }
    1472              :                         }
    1473              :                 }
    1474              :         }
    1475              : 
    1476         6886 :         public override void visit_source_file (SourceFile source_file) {
    1477         6886 :                 if (source_file.filename.has_suffix (".gir")) {
    1478          170 :                         parse_file (source_file);
    1479              :                 }
    1480              :         }
    1481              : 
    1482          170 :         public void parse_file (SourceFile source_file) {
    1483          170 :                 var has_global_context = (context != null);
    1484          170 :                 if (!has_global_context) {
    1485            0 :                         context = source_file.context;
    1486              :                 }
    1487              : 
    1488          170 :                 metadata_stack = new ArrayList<Metadata> ();
    1489         4847 :                 metadata = Metadata.empty;
    1490          170 :                 cheader_filenames = null;
    1491              : 
    1492          170 :                 this.current_source_file = source_file;
    1493          170 :                 reader = new MarkupReader (source_file.filename);
    1494              : 
    1495              :                 // xml prolog
    1496          680 :                 do {
    1497          510 :                         next ();
    1498          510 :                         if (current_token == MarkupTokenType.EOF) {
    1499            0 :                                 Report.error (get_current_src (), "unexpected end of file");
    1500            0 :                                 return;
    1501              :                         }
    1502          510 :                 } while (current_token != MarkupTokenType.START_ELEMENT && reader.name != "repository");
    1503              : 
    1504          170 :                 parse_repository ();
    1505              : 
    1506          170 :                 reader = null;
    1507          170 :                 this.current_source_file = null;
    1508          170 :                 if (!has_global_context) {
    1509            0 :                         context = null;
    1510              :                 }
    1511              :         }
    1512              : 
    1513         6746 :         void next () {
    1514         6746 :                 current_token = reader.read_token (out begin, out end);
    1515              :         }
    1516              : 
    1517         2807 :         void start_element (string name) {
    1518         2807 :                 if (current_token != MarkupTokenType.START_ELEMENT || reader.name != name) {
    1519              :                         // error
    1520            0 :                         Report.error (get_current_src (), "expected start element of `%s'", name);
    1521              :                 }
    1522              :         }
    1523              : 
    1524         2683 :         void end_element (string name) {
    1525         2683 :                 while (current_token != MarkupTokenType.END_ELEMENT || reader.name != name) {
    1526            0 :                         Report.warning (get_current_src (), "expected end element of `%s'", name);
    1527            0 :                         skip_element ();
    1528              :                 }
    1529         2683 :                 next ();
    1530              :         }
    1531              : 
    1532         1958 :         SourceReference get_current_src () {
    1533         1958 :                 return new SourceReference (this.current_source_file, begin, end);
    1534              :         }
    1535              : 
    1536          458 :         SourceReference get_src (SourceLocation begin, SourceLocation? end = null) {
    1537          458 :                 var e = this.end;
    1538          458 :                 if (end != null) {
    1539            0 :                         e = end;
    1540              :                 }
    1541          458 :                 return new SourceReference (this.current_source_file, begin, e);
    1542              :         }
    1543              : 
    1544              :         const string GIR_VERSION = "1.2";
    1545              : 
    1546          367 :         static void add_symbol_to_container (Symbol container, Symbol sym) {
    1547          367 :                 if (sym.name == "") {
    1548            1 :                         Report.warning (sym.source_reference, "node with empty name");
    1549            1 :                         return;
    1550          366 :                 } else if (sym.name != null) {
    1551          346 :                         Symbol? old_sym = container.scope.lookup (sym.name);
    1552          346 :                         if (old_sym != null) {
    1553            1 :                                 Report.warning (sym.source_reference, "`%s' already contains a definition for `%s'", container.name, sym.name);
    1554            1 :                                 Report.notice (old_sym.source_reference, "previous definition of `%s' was here", old_sym.name);
    1555            1 :                                 return;
    1556              :                         }
    1557              :                 }
    1558              : 
    1559          365 :                 if (container is Class) {
    1560          131 :                         unowned Class cl = (Class) container;
    1561              : 
    1562          131 :                         if (sym is Class) {
    1563            0 :                                 cl.add_class ((Class) sym);
    1564          131 :                         } else if (sym is Constant) {
    1565            0 :                                 cl.add_constant ((Constant) sym);
    1566          131 :                         } else if (sym is Enum) {
    1567            0 :                                 cl.add_enum ((Enum) sym);
    1568          131 :                         } else if (sym is Field) {
    1569           17 :                                 cl.add_field ((Field) sym);
    1570          114 :                         } else if (sym is Method) {
    1571           96 :                                 cl.add_method ((Method) sym);
    1572           18 :                         } else if (sym is Property) {
    1573           14 :                                 cl.add_property ((Property) sym);
    1574            4 :                         } else if (sym is Signal) {
    1575            4 :                                 cl.add_signal ((Signal) sym);
    1576            0 :                         } else if (sym is Struct) {
    1577            0 :                                 cl.add_struct ((Struct) sym);
    1578              :                         }
    1579          234 :                 } else if (container is Enum) {
    1580           21 :                         unowned Enum en = (Enum) container;
    1581              : 
    1582           21 :                         if (sym is EnumValue) {
    1583           21 :                                 en.add_value ((EnumValue) sym);
    1584            0 :                         } else if (sym is Constant) {
    1585            0 :                                 en.add_constant ((Constant) sym);
    1586            0 :                         } else if (sym is Method) {
    1587            0 :                                 en.add_method ((Method) sym);
    1588              :                         }
    1589          213 :                 } else if (container is Interface) {
    1590           16 :                         unowned Interface iface = (Interface) container;
    1591              : 
    1592           16 :                         if (sym is Class) {
    1593            0 :                                 iface.add_class ((Class) sym);
    1594           16 :                         } else if (sym is Constant) {
    1595            0 :                                 iface.add_constant ((Constant) sym);
    1596           16 :                         } else if (sym is Enum) {
    1597            0 :                                 iface.add_enum ((Enum) sym);
    1598           16 :                         } else if (sym is Field) {
    1599            0 :                                 iface.add_field ((Field) sym);
    1600           16 :                         } else if (sym is Method) {
    1601           13 :                                 iface.add_method ((Method) sym);
    1602            3 :                         } else if (sym is Property) {
    1603            2 :                                 iface.add_property ((Property) sym);
    1604            1 :                         } else if (sym is Signal) {
    1605            1 :                                 iface.add_signal ((Signal) sym);
    1606            0 :                         } else if (sym is Struct) {
    1607            0 :                                 iface.add_struct ((Struct) sym);
    1608              :                         }
    1609          197 :                 } else if (container is Namespace) {
    1610          164 :                         unowned Namespace ns = (Namespace) container;
    1611              : 
    1612          164 :                         if (sym is Namespace) {
    1613           47 :                                 ns.add_namespace ((Namespace) sym);
    1614          117 :                         } else if (sym is Class) {
    1615           31 :                                 ns.add_class ((Class) sym);
    1616           86 :                         } else if (sym is Constant) {
    1617           11 :                                 ns.add_constant ((Constant) sym);
    1618           75 :                         } else if (sym is Delegate) {
    1619           10 :                                 ns.add_delegate ((Delegate) sym);
    1620           65 :                         } else if (sym is Enum) {
    1621           10 :                                 ns.add_enum ((Enum) sym);
    1622           55 :                         } else if (sym is ErrorDomain) {
    1623            5 :                                 ns.add_error_domain ((ErrorDomain) sym);
    1624           50 :                         } else if (sym is Field) {
    1625            0 :                                 unowned Field field = (Field) sym;
    1626            0 :                                 if (field.binding == MemberBinding.INSTANCE) {
    1627            0 :                                         field.binding = MemberBinding.STATIC;
    1628              :                                 }
    1629            0 :                                 ns.add_field (field);
    1630           50 :                         } else if (sym is Interface) {
    1631            7 :                                 ns.add_interface ((Interface) sym);
    1632           43 :                         } else if (sym is Method) {
    1633           36 :                                 unowned Method method = (Method) sym;
    1634           36 :                                 if (method.binding == MemberBinding.INSTANCE) {
    1635            0 :                                         method.binding = MemberBinding.STATIC;
    1636              :                                 }
    1637           36 :                                 ns.add_method (method);
    1638            7 :                         } else if (sym is Struct) {
    1639            7 :                                 ns.add_struct ((Struct) sym);
    1640              :                         }
    1641           33 :                 } else if (container is Struct) {
    1642           22 :                         unowned Struct st = (Struct) container;
    1643              : 
    1644           22 :                         if (sym is Constant) {
    1645            0 :                                 st.add_constant ((Constant) sym);
    1646           22 :                         } else if (sym is Field) {
    1647           11 :                                 st.add_field ((Field) sym);
    1648           11 :                         } else if (sym is Method) {
    1649           11 :                                 st.add_method ((Method) sym);
    1650            0 :                         } else if (sym is Property) {
    1651            0 :                                 st.add_property ((Property) sym);
    1652              :                         }
    1653           11 :                 } else if (container is ErrorDomain) {
    1654           11 :                         unowned ErrorDomain ed = (ErrorDomain) container;
    1655              : 
    1656           11 :                         if (sym is ErrorCode) {
    1657           11 :                                 ed.add_code ((ErrorCode) sym);
    1658            0 :                         } else if (sym is Method) {
    1659            0 :                                 ed.add_method ((Method) sym);
    1660              :                         }
    1661              :                 } else {
    1662            0 :                         Report.error (sym.source_reference, "impossible to add `%s' to container `%s'", sym.name, container.name);
    1663              :                 }
    1664              :         }
    1665              : 
    1666         3042 :         static bool is_container (Symbol sym) {
    1667         3042 :                 return sym is ObjectTypeSymbol || sym is Struct || sym is Namespace || sym is ErrorDomain || sym is Enum;
    1668              :         }
    1669              : 
    1670            1 :         static unowned Namespace get_parent_namespace (Node node) {
    1671            1 :                 unowned Node? n = node.parent;
    1672            2 :                 while (n != null) {
    1673            2 :                         if (n.symbol is Namespace) {
    1674            1 :                                 return (Namespace) n.symbol;
    1675              :                         }
    1676            1 :                         n = n.parent;
    1677              :                 }
    1678            0 :                 assert_not_reached ();
    1679              :         }
    1680              : 
    1681          662 :         UnresolvedSymbol? parse_symbol_from_string (string symbol_string, SourceReference? source_reference = null) {
    1682          662 :                 UnresolvedSymbol? sym = null;
    1683         2319 :                 foreach (unowned string s in symbol_string.split (".")) {
    1684          995 :                         sym = new UnresolvedSymbol (sym, s, source_reference);
    1685              :                 }
    1686          662 :                 if (sym == null) {
    1687            0 :                         Report.error (source_reference, "a symbol must be specified");
    1688              :                 }
    1689              :                 return sym;
    1690              :         }
    1691              : 
    1692        64881 :         void set_symbol_mapping (UnresolvedSymbol map_from, Symbol map_to) {
    1693              :                 // last mapping is the most up-to-date
    1694        64881 :                 if (map_from is UnresolvedSymbol) {
    1695        64881 :                         unresolved_symbols_map[(UnresolvedSymbol) map_from] = map_to;
    1696              :                 }
    1697              :         }
    1698              : 
    1699            6 :         void assume_parameter_names (Signal sig, Symbol sym, bool skip_first) {
    1700            3 :                 var iter = ((Callable) sym).get_parameters ().iterator ();
    1701            3 :                 bool first = true;
    1702            7 :                 foreach (var param in sig.get_parameters ()) {
    1703            2 :                         if (!iter.next ()) {
    1704              :                                 // unreachable for valid GIR
    1705            0 :                                 break;
    1706              :                         }
    1707            2 :                         if (skip_first && first) {
    1708            0 :                                 if (!iter.next ()) {
    1709              :                                         // unreachable for valid GIR
    1710            0 :                                         break;
    1711              :                                 }
    1712              :                                 first = false;
    1713              :                         }
    1714            2 :                         param.name = iter.get ().name;
    1715              :                 }
    1716              :         }
    1717              : 
    1718            0 :         Node? find_invoker (Node node) {
    1719              :                 /* most common use case is invoker has at least the given method prefix
    1720              :                    and the same parameter names */
    1721            0 :                 var m = (Method) node.symbol;
    1722            0 :                 var prefix = "%s_".printf (m.name);
    1723            0 :                 foreach (var n in node.parent.members) {
    1724            0 :                         if (!n.name.has_prefix (prefix)) {
    1725            0 :                                 continue;
    1726              :                         }
    1727            0 :                         Method? invoker = n.symbol as Method;
    1728            0 :                         if (invoker == null || (m.get_parameters().size != invoker.get_parameters().size)) {
    1729            0 :                                 continue;
    1730              :                         }
    1731            0 :                         var iter = invoker.get_parameters ().iterator ();
    1732            0 :                         foreach (var param in m.get_parameters ()) {
    1733            0 :                                 assert (iter.next ());
    1734            0 :                                 if (param.name != iter.get().name)      {
    1735            0 :                                         invoker = null;
    1736            0 :                                         break;
    1737              :                                 }
    1738              :                         }
    1739            0 :                         if (invoker != null) {
    1740            0 :                                 return n;
    1741              :                         }
    1742              :                 }
    1743              : 
    1744            0 :                 return null;
    1745              :         }
    1746              : 
    1747          991 :         Metadata get_current_metadata () {
    1748          991 :                 var selector = reader.name;
    1749          991 :                 var child_name = reader.get_attribute ("name");
    1750          991 :                 if (child_name == null) {
    1751            1 :                         child_name = reader.get_attribute ("glib:name");
    1752              :                 }
    1753              :                 // Give a transparent union the generic name "union"
    1754          991 :                 if (selector == "union" && child_name == null) {
    1755            1 :                         child_name = "union";
    1756              :                 }
    1757          991 :                 if (child_name == null) {
    1758            0 :                         return Metadata.empty;
    1759              :                 }
    1760          991 :                 selector = selector.replace ("-", "_");
    1761          991 :                 child_name = child_name.replace ("-", "_");
    1762              : 
    1763          991 :                 if (selector.has_prefix ("glib:")) {
    1764            6 :                         selector = selector.substring ("glib:".length);
    1765              :                 }
    1766              : 
    1767          991 :                 return metadata.match_child (child_name, selector);
    1768              :         }
    1769              : 
    1770          991 :         bool push_metadata () {
    1771          991 :                 var new_metadata = get_current_metadata ();
    1772              :                 // skip ?
    1773          991 :                 if (new_metadata.has_argument (ArgumentType.SKIP)) {
    1774            8 :                         if (new_metadata.get_bool (ArgumentType.SKIP)) {
    1775            2 :                                 return false;
    1776              :                         }
    1777          983 :                 } else if (reader.get_attribute ("introspectable") == "0" || reader.get_attribute ("private") == "1") {
    1778           68 :                         return false;
    1779              :                 }
    1780              : 
    1781          921 :                 metadata_stack.add (metadata);
    1782         1842 :                 metadata = new_metadata;
    1783              : 
    1784          921 :                 return true;
    1785              :         }
    1786              : 
    1787          921 :         void pop_metadata () {
    1788          921 :                 metadata = metadata_stack.remove_at (metadata_stack.size - 1);
    1789              :         }
    1790              : 
    1791            0 :         bool parse_type_arguments_from_string (DataType parent_type, string type_arguments, SourceReference? source_reference = null) {
    1792            0 :                 int type_arguments_length = (int) type_arguments.length;
    1793            0 :                 GLib.StringBuilder current = new GLib.StringBuilder.sized (type_arguments_length);
    1794              : 
    1795            0 :                 int depth = 0;
    1796            0 :                 for (var c = 0 ; c < type_arguments_length ; c++) {
    1797            0 :                         if (type_arguments[c] == '<' || type_arguments[c] == '[') {
    1798            0 :                                 depth++;
    1799            0 :                                 current.append_unichar (type_arguments[c]);
    1800            0 :                         } else if (type_arguments[c] == '>' || type_arguments[c] == ']') {
    1801            0 :                                 depth--;
    1802            0 :                                 current.append_unichar (type_arguments[c]);
    1803            0 :                         } else if (type_arguments[c] == ',') {
    1804            0 :                                 if (depth == 0) {
    1805            0 :                                         var dt = parse_type_from_string (current.str, true, source_reference);
    1806            0 :                                         if (dt == null) {
    1807            0 :                                                 return false;
    1808              :                                         }
    1809            0 :                                         parent_type.add_type_argument (dt);
    1810            0 :                                         current.truncate ();
    1811              :                                 } else {
    1812            0 :                                         current.append_unichar (type_arguments[c]);
    1813              :                                 }
    1814              :                         } else {
    1815            0 :                                 current.append_unichar (type_arguments[c]);
    1816              :                         }
    1817              :                 }
    1818              : 
    1819            0 :                 var dt = parse_type_from_string (current.str, true, source_reference);
    1820            0 :                 if (dt == null) {
    1821            0 :                         return false;
    1822              :                 }
    1823            0 :                 parent_type.add_type_argument (dt);
    1824              : 
    1825            0 :                 return true;
    1826              :         }
    1827              : 
    1828            0 :         List<DataType> parse_list_of_types_from_string (string type_list, SourceReference? source_reference = null) {
    1829            0 :                 var types = new ArrayList<DataType> ();
    1830            0 :                 var type_list_length = type_list.length;
    1831            0 :                 GLib.StringBuilder current = new GLib.StringBuilder.sized (type_list_length);
    1832              : 
    1833            0 :                 for (var c = 0 ; c < type_list_length ; c++) {
    1834            0 :                         if (type_list[c] == ',') {
    1835            0 :                                 types.add (parse_type_from_string (current.str, true, source_reference));
    1836            0 :                                 current.truncate ();
    1837              :                         } else {
    1838            0 :                                 current.append_unichar (type_list[c]);
    1839              :                         }
    1840              :                 }
    1841              : 
    1842            0 :                 types.add (parse_type_from_string (current.str, true, source_reference));
    1843              : 
    1844            0 :                 return types;
    1845              :         }
    1846              : 
    1847            0 :         bool parse_type_parameters_from_string (GenericSymbol type_symbol, string type_parameters, SourceReference? source_reference = null) {
    1848            0 :                 var type_parameters_length = type_parameters.length;
    1849            0 :                 GLib.StringBuilder current = new GLib.StringBuilder.sized (type_parameters_length);
    1850              : 
    1851            0 :                 for (var c = 0 ; c < type_parameters_length ; c++) {
    1852            0 :                         if (type_parameters[c] == ',') {
    1853            0 :                                 var p = new TypeParameter (current.str, source_reference);
    1854            0 :                                 type_symbol.add_type_parameter (p);
    1855            0 :                                 current.truncate ();
    1856              :                         } else {
    1857            0 :                                 current.append_unichar (type_parameters[c]);
    1858              :                         }
    1859              :                 }
    1860              : 
    1861            0 :                 var p = new TypeParameter (current.str, source_reference);
    1862            0 :                 type_symbol.add_type_parameter (p);
    1863              : 
    1864            0 :                 return true;
    1865              :         }
    1866              : 
    1867            9 :         DataType? parse_type_from_string (string type_string, bool owned_by_default, SourceReference? source_reference = null) {
    1868            9 :                 if (type_from_string_regex == null) {
    1869            0 :                         try {
    1870            1 :                                 type_from_string_regex = new GLib.Regex ("^(?:(owned|unowned|weak) +)?([0-9a-zA-Z_\\.]+)(?:<(.+)>)?(\\*+)?(\\[,*\\])?(\\?)?$", GLib.RegexCompileFlags.ANCHORED | GLib.RegexCompileFlags.DOLLAR_ENDONLY | GLib.RegexCompileFlags.OPTIMIZE);
    1871              :                         } catch (GLib.RegexError e) {
    1872            0 :                                 GLib.error ("Unable to compile regex: %s", e.message);
    1873              :                         }
    1874              :                 }
    1875              : 
    1876              :                 GLib.MatchInfo match;
    1877            9 :                 if (!type_from_string_regex.match (type_string, 0, out match)) {
    1878            0 :                         Report.error (source_reference, "unable to parse type");
    1879            0 :                         return null;
    1880              :                 }
    1881              : 
    1882            9 :                 DataType? type = null;
    1883              : 
    1884            9 :                 var ownership_data = match.fetch (1);
    1885            9 :                 var type_name = match.fetch (2);
    1886            9 :                 var type_arguments_data = match.fetch (3);
    1887            9 :                 var pointers_data = match.fetch (4);
    1888            9 :                 var array_data = match.fetch (5);
    1889            9 :                 var nullable_data = match.fetch (6);
    1890              : 
    1891            9 :                 var nullable = nullable_data != null && nullable_data.length > 0;
    1892              : 
    1893            9 :                 if (ownership_data == null && type_name == "void") {
    1894            0 :                         if (array_data == null && !nullable) {
    1895            0 :                                 type = new VoidType (source_reference);
    1896            0 :                                 if (pointers_data != null) {
    1897            0 :                                         for (int i=0; i < pointers_data.length; i++) {
    1898            0 :                                                 type = new PointerType (type);
    1899              :                                         }
    1900              :                                 }
    1901            0 :                                 return type;
    1902              :                         } else {
    1903            0 :                                 Report.error (source_reference, "invalid void type");
    1904            0 :                                 return null;
    1905              :                         }
    1906              :                 }
    1907              : 
    1908            9 :                 bool value_owned = owned_by_default;
    1909              : 
    1910            9 :                 if (ownership_data == "owned") {
    1911            0 :                         if (owned_by_default) {
    1912            0 :                                 Report.error (source_reference, "unexpected `owned' keyword");
    1913              :                         } else {
    1914              :                                 value_owned = true;
    1915              :                         }
    1916            9 :                 } else if (ownership_data == "unowned") {
    1917            0 :                         if (owned_by_default) {
    1918              :                                 value_owned = false;
    1919              :                         } else {
    1920            0 :                                 Report.error (source_reference, "unexpected `unowned' keyword");
    1921            0 :                                 return null;
    1922              :                         }
    1923              :                 }
    1924              : 
    1925            9 :                 var sym = parse_symbol_from_string (type_name, source_reference);
    1926            9 :                 if (sym == null) {
    1927            0 :                         return null;
    1928              :                 }
    1929            9 :                 type = new UnresolvedType.from_symbol (sym, source_reference);
    1930              : 
    1931            9 :                 if (type_arguments_data != null && type_arguments_data.length > 0) {
    1932            0 :                         if (!parse_type_arguments_from_string (type, type_arguments_data, source_reference)) {
    1933            0 :                                 return null;
    1934              :                         }
    1935              :                 }
    1936              : 
    1937            9 :                 if (pointers_data != null) {
    1938            9 :                         for (int i=0; i < pointers_data.length; i++) {
    1939            0 :                                 type = new PointerType (type);
    1940              :                         }
    1941              :                 }
    1942              : 
    1943            9 :                 if (array_data != null && array_data.length != 0) {
    1944            0 :                         type.value_owned = true;
    1945            0 :                         type = new ArrayType (type, (int) array_data.length - 1, source_reference);
    1946              :                 }
    1947              : 
    1948            9 :                 type.nullable = nullable;
    1949            9 :                 type.value_owned = value_owned;
    1950            9 :                 return type;
    1951              :         }
    1952              : 
    1953          458 :         string? element_get_string (string attribute_name, ArgumentType arg_type) {
    1954          458 :                 if (metadata.has_argument (arg_type)) {
    1955            0 :                         return metadata.get_string (arg_type);
    1956              :                 } else {
    1957          458 :                         return reader.get_attribute (attribute_name);
    1958              :                 }
    1959              :         }
    1960              : 
    1961              :         /*
    1962              :          * The changed is a faster way to check whether the type has changed and it may affect the C declaration.
    1963              :          */
    1964          790 :         DataType? element_get_type (DataType orig_type, bool owned_by_default, ref bool no_array_length, ref bool array_null_terminated, out bool changed = null) {
    1965          790 :                 changed = false;
    1966          790 :                 var type = orig_type;
    1967              : 
    1968          790 :                 if (metadata.has_argument (ArgumentType.TYPE)) {
    1969            0 :                         type = parse_type_from_string (metadata.get_string (ArgumentType.TYPE), owned_by_default, metadata.get_source_reference (ArgumentType.TYPE));
    1970            0 :                         changed = true;
    1971          790 :                 } else if (!(type is VoidType)) {
    1972          633 :                         if (metadata.has_argument (ArgumentType.TYPE_ARGUMENTS)) {
    1973            0 :                                 type.remove_all_type_arguments ();
    1974            0 :                                 parse_type_arguments_from_string (type, metadata.get_string (ArgumentType.TYPE_ARGUMENTS), metadata.get_source_reference (ArgumentType.TYPE_ARGUMENTS));
    1975              :                         }
    1976              : 
    1977          633 :                         if (!(type is ArrayType) && metadata.get_bool (ArgumentType.ARRAY)) {
    1978            0 :                                 type.value_owned = true;
    1979            0 :                                 type = new ArrayType (type, 1, type.source_reference);
    1980              :                                 changed = true;
    1981              :                         }
    1982              : 
    1983          633 :                         if (owned_by_default) {
    1984          238 :                                 type.value_owned = !metadata.get_bool (ArgumentType.UNOWNED, !type.value_owned);
    1985              :                         } else {
    1986          395 :                                 type.value_owned = metadata.get_bool (ArgumentType.OWNED, type.value_owned);
    1987              :                         }
    1988          633 :                         type.nullable = metadata.get_bool (ArgumentType.NULLABLE, type.nullable);
    1989              :                 }
    1990              : 
    1991          790 :                 if (type is ArrayType) {
    1992           39 :                         if (!(orig_type is ArrayType)) {
    1993            0 :                                 no_array_length = true;
    1994              :                         }
    1995           39 :                         array_null_terminated = metadata.get_bool (ArgumentType.ARRAY_NULL_TERMINATED, array_null_terminated);
    1996              :                 }
    1997              : 
    1998          790 :                 return type;
    1999              :         }
    2000              : 
    2001          492 :         string? element_get_name (string? gir_name = null) {
    2002          492 :                 unowned string tag = reader.name;
    2003              : 
    2004          492 :                 var name = gir_name;
    2005          492 :                 if (name == null) {
    2006          463 :                         name = reader.get_attribute ("name");
    2007              :                 }
    2008          492 :                 var pattern = metadata.get_string (ArgumentType.NAME);
    2009          492 :                 if (pattern != null) {
    2010            2 :                         if (pattern.index_of_char ('(') < 0) {
    2011              :                                 // shortcut for "(.+)/replacement"
    2012            4 :                                 name = pattern;
    2013              :                         } else {
    2014            0 :                                 try {
    2015            0 :                                         string replacement = "\\1"; // replace the whole name with the match by default
    2016            0 :                                         var split = pattern.split ("/");
    2017            0 :                                         if (split.length > 1) {
    2018            0 :                                                 pattern = split[0];
    2019            0 :                                                 replacement = split[1];
    2020              :                                         }
    2021            0 :                                         var regex = new Regex (pattern, RegexCompileFlags.ANCHORED, RegexMatchFlags.ANCHORED);
    2022            0 :                                         name = regex.replace (name, -1, 0, replacement);
    2023              :                                 } catch (Error e) {
    2024            0 :                                         name = pattern;
    2025              :                                 }
    2026              :                         }
    2027          490 :                 } else if (tag == "enumeration") {
    2028              :                         // FIXME Stripping "Enum"-suffix is required for error-domains
    2029              :                         // Applied to all enumerations to preserve backwards compatibility
    2030           11 :                         if (name != null && name.has_suffix ("Enum")) {
    2031            0 :                                 name = name.substring (0, name.length - "Enum".length);
    2032              :                         }
    2033              :                 }
    2034              : 
    2035          492 :                 return name;
    2036              :         }
    2037              : 
    2038          141 :         string? element_get_type_id () {
    2039          141 :                 var type_id = metadata.get_string (ArgumentType.TYPE_ID);
    2040          141 :                 if (type_id != null) {
    2041              :                         return type_id;
    2042              :                 }
    2043              : 
    2044          141 :                 type_id = reader.get_attribute ("glib:get-type");
    2045          141 :                 if (type_id != null) {
    2046           48 :                         type_id += " ()";
    2047              :                 }
    2048              :                 return type_id;
    2049              :         }
    2050              : 
    2051           62 :         void set_array_ccode (Symbol sym, ParameterInfo info) {
    2052           31 :                 sym.set_attribute_double ("CCode", "array_length_pos", info.vala_idx);
    2053           31 :                 if (sym is Parameter) {
    2054           20 :                         sym.set_attribute_string ("CCode", "array_length_cname", info.param.name);
    2055              :                 }
    2056           31 :                 var type_name = info.param.variable_type.to_qualified_string ();
    2057           41 :                 if (type_name != "int") {
    2058           10 :                         var st = root.lookup (type_name);
    2059           10 :                         if (st != null) {
    2060           10 :                                 if (sym is Callable || sym is Parameter) {
    2061           10 :                                         sym.set_attribute_string ("CCode", "array_length_type", st.get_cname ());
    2062              :                                 }
    2063              :                         }
    2064              :                 }
    2065              :         }
    2066              : 
    2067          174 :         void set_type_id_ccode (Symbol sym) {
    2068          174 :                 if (sym.has_attribute_argument ("CCode", "has_type_id")
    2069           87 :                     || sym.has_attribute_argument ("CCode", "type_id"))
    2070            0 :                     return;
    2071              : 
    2072           87 :                 var type_id = element_get_type_id ();
    2073           87 :                 if (type_id == null) {
    2074           42 :                         sym.set_attribute_bool ("CCode", "has_type_id", false);
    2075              :                 } else {
    2076           45 :                         sym.set_attribute_string ("CCode", "type_id", type_id);
    2077              :                 }
    2078              :         }
    2079              : 
    2080          170 :         void parse_repository () {
    2081          170 :                 start_element ("repository");
    2082          170 :                 if (reader.get_attribute ("version") != GIR_VERSION) {
    2083            0 :                         Report.error (get_current_src (), "unsupported GIR version %s (supported: %s)", reader.get_attribute ("version"), GIR_VERSION);
    2084            0 :                         return;
    2085              :                 }
    2086          170 :                 next ();
    2087          510 :                 while (current_token == MarkupTokenType.START_ELEMENT) {
    2088          464 :                         if (reader.name == "namespace") {
    2089           46 :                                 parse_namespace ();
    2090          418 :                         } else if (reader.name == "include") {
    2091          202 :                                 parse_include ();
    2092          262 :                         } else if (reader.name == "package") {
    2093          170 :                                 var pkg = parse_package ();
    2094          170 :                                 this.current_source_file.package_name = pkg;
    2095          170 :                                 if (context.has_package (pkg)) {
    2096              :                                         // package already provided elsewhere, stop parsing this GIR
    2097              :                                         // if it was not passed explicitly
    2098          124 :                                         if (!this.current_source_file.from_commandline) {
    2099          124 :                                                 return;
    2100              :                                         }
    2101              :                                 } else {
    2102           46 :                                         context.add_package (pkg);
    2103              :                                 }
    2104           46 :                         } else if (reader.name == "c:include") {
    2105           46 :                                 parse_c_include ();
    2106              :                         } else {
    2107              :                                 // error
    2108            0 :                                 Report.error (get_current_src (), "unknown child element `%s' in `repository'", reader.name);
    2109            0 :                                 skip_element ();
    2110              :                         }
    2111              :                 }
    2112           46 :                 end_element ("repository");
    2113              :         }
    2114              : 
    2115          404 :         void parse_include () {
    2116          202 :                 start_element ("include");
    2117          202 :                 var pkg = reader.get_attribute ("name");
    2118          202 :                 var version = reader.get_attribute ("version");
    2119          202 :                 if (version != null) {
    2120          202 :                         pkg = "%s-%s".printf (pkg, version);
    2121              :                 }
    2122              :                 // add the package to the queue
    2123          202 :                 context.add_external_package (pkg);
    2124          202 :                 next ();
    2125          202 :                 end_element ("include");
    2126              :         }
    2127              : 
    2128          170 :         string parse_package () {
    2129          170 :                 start_element ("package");
    2130          170 :                 var pkg = reader.get_attribute ("name");
    2131          170 :                 next ();
    2132          170 :                 end_element ("package");
    2133          170 :                 return pkg;
    2134              :         }
    2135              : 
    2136           46 :         void parse_c_include () {
    2137           46 :                 start_element ("c:include");
    2138           92 :                 cheader_filenames += reader.get_attribute ("name");
    2139           46 :                 next ();
    2140           46 :                 end_element ("c:include");
    2141              :         }
    2142              : 
    2143          105 :         void skip_element () {
    2144          105 :                 next ();
    2145              : 
    2146          105 :                 int level = 1;
    2147          744 :                 while (level > 0) {
    2148          639 :                         if (current_token == MarkupTokenType.START_ELEMENT) {
    2149          267 :                                 level++;
    2150          372 :                         } else if (current_token == MarkupTokenType.END_ELEMENT) {
    2151          372 :                                 level--;
    2152            0 :                         } else if (current_token == MarkupTokenType.EOF) {
    2153            0 :                                 Report.error (get_current_src (), "unexpected end of file");
    2154              :                                 break;
    2155              :                         }
    2156          639 :                         next ();
    2157              :                 }
    2158              :         }
    2159              : 
    2160          366 :         Node? resolve_node (Node parent_scope, UnresolvedSymbol unresolved_sym, bool create_namespace = false) {
    2161          366 :                 if (unresolved_sym.inner == null) {
    2162          281 :                         var scope = parent_scope;
    2163          553 :                         while (scope != null) {
    2164          541 :                                 var node = scope.lookup (unresolved_sym.name, create_namespace, unresolved_sym.source_reference);
    2165          541 :                                 if (node != null) {
    2166          269 :                                         return node;
    2167              :                                 }
    2168          272 :                                 scope = scope.parent;
    2169              :                         }
    2170              :                 } else {
    2171           85 :                         var inner = resolve_node (parent_scope, unresolved_sym.inner, create_namespace);
    2172           85 :                         if (inner != null) {
    2173           85 :                                 return inner.lookup (unresolved_sym.name, create_namespace, unresolved_sym.source_reference);
    2174              :                         }
    2175              :                 }
    2176          366 :                 return null;
    2177              :         }
    2178              : 
    2179          122 :         Symbol? resolve_symbol (Node parent_scope, UnresolvedSymbol unresolved_sym) {
    2180          122 :                 var node = resolve_node (parent_scope, unresolved_sym);
    2181          122 :                 if (node != null) {
    2182          120 :                         return node.symbol;
    2183              :                 }
    2184          122 :                 return null;
    2185              :         }
    2186              : 
    2187         1002 :         void push_node (string name, bool merge) {
    2188          501 :                 var parent = current;
    2189          502 :                 if (metadata.has_argument (ArgumentType.PARENT)) {
    2190            1 :                         var target = parse_symbol_from_string (metadata.get_string (ArgumentType.PARENT), metadata.get_source_reference (ArgumentType.PARENT));
    2191            1 :                         parent = resolve_node (root, target, true);
    2192              :                 }
    2193              : 
    2194          501 :                 var node = parent.lookup (name);
    2195          501 :                 if (node == null || (node.symbol != null && !merge)) {
    2196          501 :                         node = new Node (name);
    2197          501 :                         node.new_symbol = true;
    2198          501 :                         parent.add_member (node);
    2199              :                 } else {
    2200            0 :                         Node.new_namespaces.remove (node);
    2201              :                 }
    2202         1002 :                 node.element_type = reader.name;
    2203          501 :                 node.girdata = reader.get_attributes ();
    2204         1002 :                 node.metadata = metadata;
    2205          501 :                 node.source_reference = get_current_src ();
    2206              : 
    2207          501 :                 var gir_name = node.get_gir_name ();
    2208          501 :                 if (parent != current || gir_name != name) {
    2209           47 :                         set_symbol_mapping (new UnresolvedSymbol (null, gir_name), node.get_unresolved_symbol ());
    2210              :                 }
    2211              : 
    2212          501 :                 tree_stack.add (current);
    2213          501 :                 current = node;
    2214              :         }
    2215              : 
    2216          501 :         void pop_node () {
    2217         1002 :                 old_current = current;
    2218          501 :                 current = tree_stack.remove_at (tree_stack.size - 1);
    2219              :         }
    2220              : 
    2221           92 :         void parse_namespace () {
    2222           46 :                 start_element ("namespace");
    2223              : 
    2224           46 :                 string? cprefix = reader.get_attribute ("c:identifier-prefixes");
    2225           46 :                 if (cprefix != null) {
    2226           46 :                         int idx = cprefix.index_of (",");
    2227           46 :                         if (idx != -1) {
    2228            0 :                                 cprefix = cprefix.substring (0, idx);
    2229              :                         }
    2230              :                 }
    2231              : 
    2232           46 :                 string? lower_case_cprefix = reader.get_attribute ("c:symbol-prefixes");
    2233           46 :                 string vala_namespace = cprefix;
    2234           46 :                 string gir_namespace = reader.get_attribute ("name");
    2235           46 :                 string gir_version = reader.get_attribute ("version");
    2236              : 
    2237           46 :                 if (lower_case_cprefix != null) {
    2238           46 :                         int idx = lower_case_cprefix.index_of (",");
    2239           46 :                         if (idx != -1) {
    2240            0 :                                 lower_case_cprefix = lower_case_cprefix.substring (0, idx);
    2241              :                         }
    2242              :                 }
    2243              : 
    2244           46 :                 if (provided_namespaces.contains ("%s-%s".printf (gir_namespace, gir_version))) {
    2245            0 :                         skip_element ();
    2246            0 :                         return;
    2247              :                 }
    2248              : 
    2249              :                 // load metadata, first look into metadata directories then in the same directory of the .gir.
    2250           46 :                 string? metadata_filename = context.get_metadata_path (current_source_file.filename);
    2251           47 :                 if (metadata_filename != null && FileUtils.test (metadata_filename, FileTest.EXISTS)) {
    2252            1 :                         var metadata_parser = new MetadataParser ();
    2253            1 :                         var metadata_file = new SourceFile (context, current_source_file.file_type, metadata_filename);
    2254            1 :                         context.add_source_file (metadata_file);
    2255            1 :                         metadata = metadata_parser.parse_metadata (metadata_file);
    2256            1 :                         metadata_roots.add (metadata);
    2257              :                 }
    2258              : 
    2259           46 :                 var ns_metadata = metadata.match_child (gir_namespace);
    2260           46 :                 if (ns_metadata.has_argument (ArgumentType.NAME)) {
    2261            0 :                         vala_namespace = ns_metadata.get_string (ArgumentType.NAME);
    2262              :                 }
    2263           46 :                 if (vala_namespace == null) {
    2264            0 :                         vala_namespace = gir_namespace;
    2265              :                 }
    2266              : 
    2267           46 :                 current_source_file.gir_namespace = gir_namespace;
    2268           46 :                 current_source_file.gir_version = gir_version;
    2269              : 
    2270              :                 Namespace ns;
    2271           46 :                 push_node (vala_namespace, true);
    2272           46 :                 if (current.new_symbol) {
    2273           46 :                         ns = new Namespace (vala_namespace, current.source_reference);
    2274           92 :                         current.symbol = ns;
    2275              :                 } else {
    2276            0 :                         ns = (Namespace) current.symbol;
    2277            0 :                         ns.attributes = null;
    2278            0 :                         ns.source_reference = current.source_reference;
    2279              :                 }
    2280              : 
    2281           92 :                 current.metadata = ns_metadata;
    2282              : 
    2283           46 :                 if (ns_metadata.has_argument (ArgumentType.CPREFIX)) {
    2284            0 :                         cprefix = ns_metadata.get_string (ArgumentType.CPREFIX);
    2285              :                 }
    2286              : 
    2287           46 :                 if (ns_metadata.has_argument (ArgumentType.LOWER_CASE_CPREFIX)) {
    2288            0 :                         lower_case_cprefix = ns_metadata.get_string (ArgumentType.LOWER_CASE_CPREFIX);
    2289           46 :                 } else if (lower_case_cprefix != null) {
    2290           46 :                         lower_case_cprefix += "_";
    2291              :                 }
    2292              : 
    2293           46 :                 ns.set_attribute_string ("CCode", "gir_namespace", gir_namespace);
    2294           46 :                 ns.set_attribute_string ("CCode", "gir_version", gir_version);
    2295              : 
    2296           46 :                 if (cprefix != null) {
    2297           46 :                         ns.set_attribute_string ("CCode", "cprefix", cprefix);
    2298           46 :                         if (lower_case_cprefix == null) {
    2299            0 :                                 ns.set_attribute_string ("CCode", "lower_case_cprefix", Symbol.camel_case_to_lower_case (cprefix) + "_");
    2300              :                         }
    2301              :                 }
    2302              : 
    2303           46 :                 if (lower_case_cprefix != null) {
    2304           46 :                         ns.set_attribute_string ("CCode", "lower_case_cprefix", lower_case_cprefix);
    2305              :                 }
    2306              : 
    2307           46 :                 if (cheader_filenames != null) {
    2308           46 :                         ns.set_attribute_string ("CCode", "cheader_filename", string.joinv (",", cheader_filenames));
    2309              :                 }
    2310              : 
    2311           46 :                 next ();
    2312          216 :                 while (current_token == MarkupTokenType.START_ELEMENT) {
    2313          170 :                         if (!push_metadata ()) {
    2314            6 :                                 skip_element ();
    2315            6 :                                 continue;
    2316              :                         }
    2317              : 
    2318          164 :                         if (reader.name == "alias") {
    2319            5 :                                 parse_alias ();
    2320          159 :                         } else if (reader.name == "enumeration") {
    2321           11 :                                 if (metadata.has_argument (ArgumentType.ERRORDOMAIN)) {
    2322            0 :                                         if (metadata.get_bool (ArgumentType.ERRORDOMAIN)) {
    2323            0 :                                                 parse_error_domain ();
    2324              :                                         } else {
    2325            0 :                                                 parse_enumeration ();
    2326              :                                         }
    2327              :                                 } else {
    2328           11 :                                         if (reader.has_attribute ("glib:error-quark") || reader.has_attribute ("glib:error-domain")) {
    2329            5 :                                                 parse_error_domain ();
    2330              :                                         } else {
    2331            6 :                                                 parse_enumeration ();
    2332              :                                         }
    2333              :                                 }
    2334          148 :                         } else if (reader.name == "bitfield") {
    2335            4 :                                 parse_bitfield ();
    2336          144 :                         } else if (reader.name == "function") {
    2337           37 :                                 parse_method ("function");
    2338          107 :                         } else if (reader.name == "function-macro") {
    2339            0 :                                 skip_element ();
    2340          107 :                         } else if (reader.name == "callback") {
    2341            8 :                                 parse_callback ();
    2342           99 :                         } else if (reader.name == "record") {
    2343           55 :                                 if (metadata.has_argument (ArgumentType.STRUCT)) {
    2344            2 :                                         if (metadata.get_bool (ArgumentType.STRUCT)) {
    2345            1 :                                                 parse_record ();
    2346              :                                         } else {
    2347            1 :                                                 parse_boxed ("record");
    2348              :                                         }
    2349           53 :                                 } else if (element_get_type_id () != null) {
    2350            3 :                                         parse_boxed ("record");
    2351           50 :                                 } else if (!reader.get_attribute ("name").has_suffix ("Private")) {
    2352           35 :                                         if (!reader.has_attribute ("glib:is-gtype-struct-for") && reader.get_attribute ("disguised") == "1") {
    2353            0 :                                                 parse_boxed ("record");
    2354              :                                         } else {
    2355           35 :                                                 parse_record ();
    2356              :                                         }
    2357              :                                 } else {
    2358           15 :                                         skip_element ();
    2359              :                                 }
    2360           44 :                         } else if (reader.name == "class") {
    2361           26 :                                 parse_class ();
    2362           18 :                         } else if (reader.name == "interface") {
    2363            6 :                                 parse_interface ();
    2364           12 :                         } else if (reader.name == "glib:boxed") {
    2365            0 :                                 parse_boxed ("glib:boxed");
    2366           12 :                         } else if (reader.name == "union") {
    2367            1 :                                 if (element_get_type_id () != null && !metadata.get_bool (ArgumentType.STRUCT)) {
    2368            0 :                                         parse_boxed ("union");
    2369              :                                 } else {
    2370            1 :                                         parse_union ();
    2371              :                                 }
    2372           11 :                         } else if (reader.name == "constant") {
    2373           11 :                                 parse_constant ();
    2374            0 :                         } else if (reader.name == "docsection") {
    2375            0 :                                 skip_element ();
    2376              :                         } else {
    2377              :                                 // error
    2378            0 :                                 Report.error (get_current_src (), "unknown child element `%s' in `namespace'", reader.name);
    2379            0 :                                 skip_element ();
    2380              :                         }
    2381              : 
    2382          164 :                         pop_metadata ();
    2383              :                 }
    2384           46 :                 pop_node ();
    2385           46 :                 end_element ("namespace");
    2386              :         }
    2387              : 
    2388            5 :         void parse_alias () {
    2389            5 :                 start_element ("alias");
    2390            5 :                 push_node (element_get_name (), true);
    2391              :                 // not enough information, symbol will be created while processing the tree
    2392              : 
    2393            5 :                 next ();
    2394              : 
    2395            5 :                 if (current.comment == null) {
    2396            5 :                         current.comment = parse_symbol_doc ();
    2397              :                 } else {
    2398            0 :                         parse_symbol_doc ();
    2399              :                 }
    2400              : 
    2401            5 :                 bool no_array_length = false;
    2402            5 :                 bool array_null_terminated = false;
    2403            5 :                 current.base_type = element_get_type (parse_type (null, null, true), true, ref no_array_length, ref array_null_terminated);
    2404              : 
    2405            5 :                 if (metadata.has_argument (ArgumentType.BASE_TYPE)) {
    2406            0 :                         current.base_type = parse_type_from_string (metadata.get_string (ArgumentType.BASE_TYPE), true, metadata.get_source_reference (ArgumentType.BASE_TYPE));
    2407              :                 }
    2408              : 
    2409            5 :                 pop_node ();
    2410            5 :                 end_element ("alias");
    2411              :         }
    2412              : 
    2413           33 :         private void calculate_common_prefix (ref string? common_prefix, string cname) {
    2414           33 :                 if (common_prefix == null) {
    2415           30 :                         common_prefix = cname;
    2416           84 :                         while (common_prefix.length > 0 && !common_prefix.has_suffix ("_")) {
    2417              :                                 // FIXME: could easily be made faster
    2418           69 :                                 common_prefix = common_prefix.substring (0, common_prefix.length - 1);
    2419              :                         }
    2420              :                 } else {
    2421           18 :                         while (!cname.has_prefix (common_prefix)) {
    2422            0 :                                 common_prefix = common_prefix.substring (0, common_prefix.length - 1);
    2423              :                         }
    2424              :                 }
    2425           33 :                 while (common_prefix.length > 0 && (!common_prefix.has_suffix ("_") ||
    2426           33 :                        (cname.get_char (common_prefix.length).isdigit ()) && (cname.length - common_prefix.length) <= 1)) {
    2427              :                         // enum values may not consist solely of digits
    2428            0 :                         common_prefix = common_prefix.substring (0, common_prefix.length - 1);
    2429              :                 }
    2430              :         }
    2431              : 
    2432          456 :         GirComment? parse_symbol_doc () {
    2433              :                 GirComment? comment = null;
    2434              : 
    2435          456 :                 while (current_token == MarkupTokenType.START_ELEMENT) {
    2436          416 :                         unowned string reader_name = reader.name;
    2437              : 
    2438          416 :                         if (reader_name == "doc") {
    2439            0 :                                 start_element ("doc");
    2440            0 :                                 next ();
    2441              : 
    2442              : 
    2443            0 :                                 if (current_token == MarkupTokenType.TEXT) {
    2444            0 :                                         comment = new GirComment (reader.content, current.source_reference);
    2445            0 :                                         next ();
    2446              :                                 }
    2447              : 
    2448            0 :                                 end_element ("doc");
    2449          416 :                         } else if (reader_name == "doc-version" || reader_name == "doc-deprecated" || reader_name == "doc-stability") {
    2450            0 :                                 skip_element ();
    2451          416 :                         } else if (reader_name == "source-position") {
    2452            0 :                                 skip_element ();
    2453          416 :                         } else if (reader_name == "attribute") {
    2454            0 :                                 skip_element ();
    2455              :                         } else {
    2456              :                                 break;
    2457              :                         }
    2458              :                 }
    2459              : 
    2460              :                 return comment;
    2461              :         }
    2462              : 
    2463          698 :         Comment? parse_doc () {
    2464              :                 Comment? comment = null;
    2465              : 
    2466          700 :                 while (current_token == MarkupTokenType.START_ELEMENT) {
    2467          700 :                         unowned string reader_name = reader.name;
    2468              : 
    2469          700 :                         if (reader_name == "doc") {
    2470            2 :                                 start_element ("doc");
    2471            2 :                                 next ();
    2472              : 
    2473              : 
    2474            2 :                                 if (current_token == MarkupTokenType.TEXT) {
    2475            2 :                                         comment = new Comment (reader.content, current.source_reference);
    2476            2 :                                         next ();
    2477              :                                 }
    2478              : 
    2479            2 :                                 end_element ("doc");
    2480          698 :                         } else if (reader_name == "doc-version" || reader_name == "doc-deprecated" || reader_name == "doc-stability") {
    2481            0 :                                 skip_element ();
    2482          698 :                         } else if (reader_name == "source-position") {
    2483            0 :                                 skip_element ();
    2484          698 :                         } else if (reader_name == "attribute") {
    2485            0 :                                 skip_element ();
    2486              :                         } else {
    2487              :                                 break;
    2488              :                         }
    2489              :                 }
    2490              : 
    2491              :                 return comment;
    2492              :         }
    2493              : 
    2494           30 :         void parse_enumeration (string element_name = "enumeration", bool error_domain = false) {
    2495           15 :                 start_element (element_name);
    2496           15 :                 push_node (element_get_name (), true);
    2497              : 
    2498              :                 Symbol sym;
    2499           15 :                 if (current.new_symbol) {
    2500           15 :                         if (error_domain) {
    2501            5 :                                 sym = new ErrorDomain (current.name, current.source_reference);
    2502              :                         } else {
    2503           10 :                                 var en = new Enum (current.name, current.source_reference);
    2504           10 :                                 if (element_name == "bitfield") {
    2505            4 :                                         en.set_attribute ("Flags", true);
    2506              :                                 }
    2507           20 :                                 sym = en;
    2508              :                         }
    2509           30 :                         current.symbol = sym;
    2510              :                 } else {
    2511            0 :                         sym = current.symbol;
    2512              :                 }
    2513              : 
    2514           15 :                 set_type_id_ccode (sym);
    2515              : 
    2516           15 :                 sym.access = SymbolAccessibility.PUBLIC;
    2517              : 
    2518           15 :                 string? common_prefix = null;
    2519           15 :                 bool explicit_prefix = false;
    2520           15 :                 if (metadata.has_argument (ArgumentType.CPREFIX)) {
    2521            0 :                         sym.set_attribute_string ("CCode", "cprefix", metadata.get_string (ArgumentType.CPREFIX));
    2522            0 :                         explicit_prefix = true;
    2523              :                 }
    2524           15 :                 bool has_member = false;
    2525              : 
    2526           15 :                 next ();
    2527              : 
    2528           15 :                 sym.comment = parse_symbol_doc ();
    2529              : 
    2530           48 :                 while (current_token == MarkupTokenType.START_ELEMENT) {
    2531           33 :                         if (!push_metadata ()) {
    2532            0 :                                 skip_element ();
    2533            0 :                                 continue;
    2534              :                         }
    2535              : 
    2536           33 :                         if (reader.name == "member") {
    2537           33 :                                 has_member = true;
    2538           33 :                                 if (error_domain) {
    2539           11 :                                         parse_error_member ();
    2540              :                                 } else {
    2541           22 :                                         parse_enumeration_member ();
    2542              :                                 }
    2543           33 :                                 if (!explicit_prefix) {
    2544           33 :                                         calculate_common_prefix (ref common_prefix, old_current.get_cname ());
    2545              :                                 }
    2546            0 :                         } else if (reader.name == "function") {
    2547            0 :                                 parse_method ("function");
    2548            0 :                         } else if (reader.name == "function-macro") {
    2549            0 :                                 skip_element ();
    2550              :                         } else {
    2551              :                                 // error
    2552            0 :                                 Report.error (get_current_src (), "unknown child element `%s' in `%s'", reader.name, element_name);
    2553            0 :                                 skip_element ();
    2554              :                         }
    2555              : 
    2556           33 :                         pop_metadata ();
    2557              :                 }
    2558              : 
    2559           15 :                 if (!has_member) {
    2560            0 :                         Report.error (get_current_src (), "%s `%s' has no members", element_name, current.name);
    2561              :                 }
    2562              : 
    2563           15 :                 if (common_prefix != null) {
    2564           15 :                         sym.set_attribute_string ("CCode", "cprefix", common_prefix);
    2565              :                 }
    2566              : 
    2567           15 :                 pop_node ();
    2568           15 :                 end_element (element_name);
    2569              :         }
    2570              : 
    2571            5 :         void parse_error_domain () {
    2572            5 :                 parse_enumeration ("enumeration", true);
    2573              :         }
    2574              : 
    2575            4 :         void parse_bitfield () {
    2576            4 :                 parse_enumeration ("bitfield");
    2577              :         }
    2578              : 
    2579           44 :         void parse_enumeration_member () {
    2580           22 :                 start_element ("member");
    2581           22 :                 push_node (element_get_name().ascii_up().replace ("-", "_"), false);
    2582              : 
    2583           22 :                 var ev = new EnumValue (current.name, metadata.get_expression (ArgumentType.DEFAULT), current.source_reference);
    2584           44 :                 current.symbol = ev;
    2585           22 :                 next ();
    2586              : 
    2587           22 :                 ev.comment = parse_symbol_doc ();
    2588              : 
    2589           22 :                 pop_node ();
    2590           22 :                 end_element ("member");
    2591              :         }
    2592              : 
    2593           22 :         void parse_error_member () {
    2594           11 :                 start_element ("member");
    2595           11 :                 push_node (element_get_name().ascii_up().replace ("-", "_"), false);
    2596              : 
    2597              :                 ErrorCode ec;
    2598           11 :                 string value = reader.get_attribute ("value");
    2599           11 :                 if (value != null) {
    2600           11 :                         ec = new ErrorCode.with_value (current.name, new IntegerLiteral (value));
    2601              :                 } else {
    2602            0 :                         ec = new ErrorCode (current.name);
    2603              :                 }
    2604           22 :                 current.symbol = ec;
    2605           11 :                 next ();
    2606              : 
    2607           11 :                 ec.comment = parse_symbol_doc ();
    2608              : 
    2609           11 :                 pop_node ();
    2610           11 :                 end_element ("member");
    2611              :         }
    2612              : 
    2613          240 :         DataType parse_return_value (out string? ctype = null, out int array_length_idx = null, out bool no_array_length = null, out bool array_null_terminated = null, out Comment? comment = null) {
    2614          240 :                 start_element ("return-value");
    2615              : 
    2616          240 :                 string transfer = reader.get_attribute ("transfer-ownership");
    2617          240 :                 string nullable = reader.get_attribute ("nullable");
    2618          240 :                 string allow_none = reader.get_attribute ("allow-none");
    2619          240 :                 next ();
    2620              : 
    2621          240 :                 comment = parse_doc ();
    2622              : 
    2623          240 :                 var transfer_elements = transfer != "container";
    2624          240 :                 var type = parse_type (out ctype, out array_length_idx, transfer_elements, out no_array_length, out array_null_terminated);
    2625          240 :                 if (transfer == "full" || transfer == "container") {
    2626          156 :                         type.value_owned = true;
    2627              :                 }
    2628          240 :                 if (nullable == "1" || allow_none == "1") {
    2629            2 :                         type.nullable = true;
    2630              :                 }
    2631          240 :                 type = element_get_type (type, true, ref no_array_length, ref array_null_terminated);
    2632              : 
    2633          240 :                 end_element ("return-value");
    2634          240 :                 return type;
    2635              :         }
    2636              : 
    2637          458 :         Parameter parse_parameter (out bool caller_allocates, out int array_length_idx = null, out int closure_idx = null, out int destroy_idx = null, out string? scope = null, out Comment? comment = null, string? default_name = null) {
    2638          458 :                 var begin = this.begin;
    2639              :                 Parameter param;
    2640              : 
    2641          458 :                 array_length_idx = -1;
    2642          458 :                 closure_idx = -1;
    2643          458 :                 destroy_idx = -1;
    2644              : 
    2645          458 :                 string element_type = reader.name;
    2646          458 :                 if (current_token != MarkupTokenType.START_ELEMENT || (element_type != "parameter" && element_type != "instance-parameter")) {
    2647            0 :                         Report.error (get_current_src (), "expected start element of `parameter' or `instance-parameter'");
    2648              :                 }
    2649          458 :                 start_element (element_type);
    2650          458 :                 var name = metadata.get_string (ArgumentType.NAME);
    2651          458 :                 if (name == null) {
    2652          458 :                         name = reader.get_attribute ("name");
    2653              :                 }
    2654          458 :                 if (name == null) {
    2655            0 :                         name = default_name;
    2656          458 :                 } else if (name.contains ("-")) {
    2657            0 :                         Report.warning (get_current_src (), "parameter name contains hyphen");
    2658            0 :                         name = name.replace ("-", "_");
    2659              :                 }
    2660          458 :                 string direction = null;
    2661          458 :                 if (metadata.has_argument (ArgumentType.OUT)) {
    2662            0 :                         if (metadata.get_bool (ArgumentType.OUT)) {
    2663            0 :                                 direction = "out";
    2664              :                         } // null otherwise
    2665          458 :                 } else if (metadata.has_argument (ArgumentType.REF)) {
    2666            0 :                         if (metadata.get_bool (ArgumentType.REF)) {
    2667            0 :                                 direction = "inout";
    2668              :                         } // null otherwise
    2669              :                 } else {
    2670          458 :                         direction = reader.get_attribute ("direction");
    2671              :                 }
    2672          458 :                 string transfer = reader.get_attribute ("transfer-ownership");
    2673          458 :                 string nullable = reader.get_attribute ("nullable");
    2674          458 :                 string allow_none = reader.get_attribute ("allow-none");
    2675              : 
    2676          458 :                 caller_allocates = reader.get_attribute ("caller-allocates") == "1";
    2677          458 :                 scope = element_get_string ("scope", ArgumentType.SCOPE);
    2678              : 
    2679          458 :                 string closure = reader.get_attribute ("closure");
    2680          458 :                 string destroy = reader.get_attribute ("destroy");
    2681          458 :                 if (closure != null && &closure_idx != null) {
    2682           43 :                         closure_idx = int.parse (closure);
    2683              :                 }
    2684          458 :                 if (destroy != null && &destroy_idx != null) {
    2685           16 :                         destroy_idx = int.parse (destroy);
    2686              :                 }
    2687          458 :                 if (metadata.has_argument (ArgumentType.CLOSURE)) {
    2688            0 :                         closure_idx = metadata.get_integer (ArgumentType.CLOSURE);
    2689              :                 }
    2690          458 :                 if (metadata.has_argument (ArgumentType.DESTROY)) {
    2691            0 :                         destroy_idx = metadata.get_integer (ArgumentType.DESTROY);
    2692              :                 }
    2693              : 
    2694          458 :                 next ();
    2695              : 
    2696          458 :                 comment = parse_doc ();
    2697              : 
    2698          914 :                 if (reader.name == "varargs") {
    2699            2 :                         start_element ("varargs");
    2700            2 :                         next ();
    2701            2 :                         param = new Parameter.with_ellipsis (get_src (begin));
    2702            2 :                         end_element ("varargs");
    2703              :                 } else {
    2704              :                         string ctype;
    2705              :                         bool no_array_length;
    2706              :                         bool array_null_terminated;
    2707          456 :                         var type = parse_type (out ctype, out array_length_idx, transfer != "container", out no_array_length, out array_null_terminated);
    2708          456 :                         if (transfer == "full" || transfer == "container" || destroy != null) {
    2709           54 :                                 type.value_owned = true;
    2710              :                         }
    2711          456 :                         if (nullable == "1" || (allow_none == "1" && direction != "out")) {
    2712           72 :                                 type.nullable = true;
    2713              :                         }
    2714              : 
    2715              :                         bool changed;
    2716          456 :                         type = element_get_type (type, direction == "out" || direction == "inout", ref no_array_length, ref array_null_terminated, out changed);
    2717          456 :                         if (!changed) {
    2718          456 :                                 if (metadata.has_argument (ArgumentType.CTYPE)) {
    2719            0 :                                         ctype = metadata.get_string (ArgumentType.CTYPE);
    2720              :                                 } else {
    2721              :                                         // discard ctype, duplicated information
    2722          456 :                                         ctype = null;
    2723              :                                 }
    2724              :                         }
    2725              : 
    2726          456 :                         param = new Parameter (name, type, get_src (begin));
    2727          456 :                         if (ctype != null) {
    2728            0 :                                 param.set_attribute_string ("CCode", "type", ctype);
    2729              :                         }
    2730          456 :                         if (direction == "out") {
    2731           53 :                                 param.direction = ParameterDirection.OUT;
    2732          403 :                         } else if (direction == "inout") {
    2733            8 :                                 param.direction = ParameterDirection.REF;
    2734              :                         }
    2735          456 :                         if (type is DelegateType && metadata.has_argument (ArgumentType.DELEGATE_TARGET)) {
    2736            0 :                                 param.set_attribute_bool ("CCode", "delegate_target", metadata.get_bool (ArgumentType.DELEGATE_TARGET));
    2737              :                         }
    2738          456 :                         if (type is ArrayType) {
    2739           23 :                                 if (metadata.has_argument (ArgumentType.ARRAY_LENGTH_IDX)) {
    2740            0 :                                         array_length_idx = metadata.get_integer (ArgumentType.ARRAY_LENGTH_IDX);
    2741              :                                 } else {
    2742           23 :                                         if (no_array_length || array_null_terminated) {
    2743            3 :                                                 param.set_attribute_bool ("CCode", "array_length", !no_array_length);
    2744              :                                         }
    2745           23 :                                         if (array_null_terminated) {
    2746            0 :                                                 param.set_attribute_bool ("CCode", "array_null_terminated", array_null_terminated);
    2747              :                                         }
    2748              :                                 }
    2749              :                         }
    2750          456 :                         param.initializer = metadata.get_expression (ArgumentType.DEFAULT);
    2751              : 
    2752              :                         // empty tuple used for parameters without initializer
    2753          456 :                         if (param.initializer is Tuple) {
    2754            0 :                                 param.initializer = null;
    2755              :                         }
    2756              :                 }
    2757          458 :                 end_element (element_type);
    2758          458 :                 return param;
    2759              :         }
    2760              : 
    2761          840 :         DataType parse_type (out string? ctype = null, out int array_length_idx = null, bool transfer_elements = true, out bool no_array_length = null, out bool array_null_terminated = null) {
    2762          840 :                 bool is_array = false;
    2763          840 :                 string type_name = reader.get_attribute ("name");
    2764          840 :                 ctype = null;
    2765              : 
    2766          840 :                 var fixed_length = -1;
    2767          840 :                 array_length_idx = -1;
    2768          840 :                 no_array_length = true;
    2769          840 :                 array_null_terminated = true;
    2770              : 
    2771          841 :                 if (reader.name == "array") {
    2772           40 :                         is_array = true;
    2773           40 :                         start_element ("array");
    2774              : 
    2775           40 :                         var src = get_current_src ();
    2776              : 
    2777           40 :                         if (type_name == null) {
    2778           39 :                                 if (reader.has_attribute ("length")) {
    2779           31 :                                         array_length_idx = int.parse (reader.get_attribute ("length"));
    2780           31 :                                         no_array_length = false;
    2781           31 :                                         array_null_terminated = false;
    2782              :                                 }
    2783           39 :                                 if (reader.has_attribute ("fixed-size")) {
    2784            6 :                                         fixed_length = int.parse (reader.get_attribute ("fixed-size"));
    2785            6 :                                         array_null_terminated = false;
    2786              :                                 }
    2787           39 :                                 if (reader.get_attribute ("c:type") == "GStrv") {
    2788            0 :                                         no_array_length = true;
    2789            0 :                                         array_null_terminated = true;
    2790              :                                 }
    2791           39 :                                 if (reader.has_attribute ("zero-terminated")) {
    2792            8 :                                         array_null_terminated = int.parse (reader.get_attribute ("zero-terminated")) != 0;
    2793              :                                 }
    2794           39 :                                 next ();
    2795           39 :                                 var element_type = parse_type ();
    2796           39 :                                 element_type.value_owned = transfer_elements;
    2797           39 :                                 end_element ("array");
    2798              : 
    2799           39 :                                 var array_type = new ArrayType (element_type, 1, src);
    2800           39 :                                 if (fixed_length > 0) {
    2801            6 :                                         array_type.fixed_length = true;
    2802            6 :                                         array_type.length = new IntegerLiteral (fixed_length.to_string ());
    2803              :                                 }
    2804           39 :                                 return array_type;
    2805              :                         }
    2806          800 :                 } else if (reader.name == "callback"){
    2807           35 :                         parse_callback ();
    2808           35 :                         return new DelegateType ((Delegate) old_current.symbol);
    2809              :                 } else {
    2810          765 :                         start_element ("type");
    2811              :                 }
    2812              : 
    2813          766 :                 if (metadata.has_argument (ArgumentType.CTYPE)) {
    2814            0 :                         ctype = metadata.get_string (ArgumentType.CTYPE);
    2815              :                 } else {
    2816          766 :                         ctype = reader.get_attribute("c:type");
    2817              :                 }
    2818              : 
    2819          766 :                 next ();
    2820              : 
    2821          766 :                 if (type_name == null) {
    2822            0 :                         type_name = ctype;
    2823              :                 }
    2824              : 
    2825              :                 DataType type;
    2826          766 :                 if (type_name != null) {
    2827          766 :                         type = parse_type_from_gir_name (type_name, out no_array_length, out array_null_terminated, ctype);
    2828              :                 } else {
    2829              :                         // empty <type/>
    2830            0 :                         no_array_length = false;
    2831            0 :                         array_null_terminated = false;
    2832            0 :                         type = new InvalidType ();
    2833            0 :                         Report.error (get_current_src (), "empty type element");
    2834              :                 }
    2835              : 
    2836              :                 // type arguments / element types
    2837          788 :                 while (current_token == MarkupTokenType.START_ELEMENT) {
    2838           11 :                         if (type_name == "GLib.ByteArray") {
    2839            0 :                                 skip_element ();
    2840            0 :                                 continue;
    2841              :                         }
    2842           11 :                         var element_type = parse_type ();
    2843           11 :                         element_type.value_owned = transfer_elements;
    2844           11 :                         type.add_type_argument (element_type);
    2845              : 
    2846           12 :                         if (element_type is UnresolvedType) {
    2847            1 :                                 Node parent = current ?? root;
    2848            3 :                                 while (parent != root && parent.parent != null && parent.parent != root) {
    2849            2 :                                         parent = parent.parent;
    2850              :                                 }
    2851            1 :                                 unresolved_type_arguments[(UnresolvedType) element_type] = parent;
    2852              :                         }
    2853              :                 }
    2854              : 
    2855          766 :                 end_element (is_array ? "array" : "type");
    2856          766 :                 return type;
    2857              :         }
    2858              : 
    2859          794 :         DataType parse_type_from_gir_name (string type_name, out bool no_array_length = null, out bool array_null_terminated = null, string? ctype = null) {
    2860          794 :                 no_array_length = false;
    2861          794 :                 array_null_terminated = false;
    2862              : 
    2863          794 :                 DataType? type = null;
    2864          794 :                 if (type_name == "none") {
    2865          157 :                         type = new VoidType (get_current_src ());
    2866          637 :                 } else if (type_name == "gpointer") {
    2867           61 :                         type = new PointerType (new VoidType (get_current_src ()), get_current_src ());
    2868          576 :                 } else if (type_name == "GObject.Strv") {
    2869            0 :                         var element_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (null, "string"));
    2870            0 :                         element_type.value_owned = true;
    2871            0 :                         type = new ArrayType (element_type, 1, get_current_src ());
    2872            0 :                         no_array_length = true;
    2873            0 :                         array_null_terminated = true;
    2874              :                 } else {
    2875          576 :                         bool known_type = true;
    2876          576 :                         if (type_name == "utf8") {
    2877           40 :                                 if (ctype == null || ctype.has_suffix ("*") || ctype == "gpointer" || ctype == "gconstpointer") {
    2878              :                                         type_name = "string";
    2879              :                                 } else {
    2880              :                                         //FIXME Work around a g-ir-scanner bug
    2881            2 :                                         type_name = "char";
    2882              :                                 }
    2883          536 :                         } else if (type_name == "gboolean") {
    2884            7 :                                 type = new BooleanType ((Struct) context.root.scope.lookup ("bool"));
    2885          529 :                         } else if (type_name == "gchar") {
    2886              :                                 type_name = "char";
    2887          529 :                         } else if (type_name == "gshort") {
    2888              :                                 type_name = "short";
    2889          529 :                         } else if (type_name == "gushort") {
    2890              :                                 type_name = "ushort";
    2891          529 :                         } else if (type_name == "gint") {
    2892          111 :                                 if (ctype != null && ctype.has_prefix ("dev_t")) {
    2893              :                                         type_name = "dev_t";
    2894          109 :                                 } else if (ctype != null && ctype.has_prefix ("pid_t")) {
    2895              :                                         type_name = "pid_t";
    2896              :                                 } else {
    2897              :                                         type_name = "int";
    2898              :                                 }
    2899          418 :                         } else if (type_name == "guint") {
    2900           10 :                                 if (ctype != null && ctype.has_prefix ("gid_t")) {
    2901              :                                         type_name = "gid_t";
    2902            8 :                                 } else if (ctype != null && ctype.has_prefix ("uid_t")) {
    2903              :                                         type_name = "uid_t";
    2904              :                                 } else {
    2905              :                                         type_name = "uint";
    2906              :                                 }
    2907          408 :                         } else if (type_name == "glong") {
    2908            2 :                                 if (ctype != null && ctype.has_prefix ("gssize")) {
    2909              :                                         type_name = "ssize_t";
    2910            2 :                                 } else if (ctype != null && ctype.has_prefix ("gintptr")) {
    2911              :                                         type_name = "intptr";
    2912            2 :                                 } else if (ctype != null && ctype.has_prefix ("time_t")) {
    2913              :                                         type_name = "time_t";
    2914              :                                 } else {
    2915              :                                         type_name = "long";
    2916              :                                 }
    2917          406 :                         } else if (type_name == "gulong") {
    2918            3 :                                 if (ctype != null && ctype.has_prefix ("gsize")) {
    2919              :                                         type_name = "size_t";
    2920            0 :                                 } else if (ctype != null && ctype.has_prefix ("guintptr")) {
    2921              :                                         type_name = "uintptr";
    2922              :                                 } else {
    2923              :                                         type_name = "ulong";
    2924              :                                 }
    2925          403 :                         } else if (type_name == "gint8") {
    2926              :                                 type_name = "int8";
    2927          379 :                         } else if (type_name == "guint8") {
    2928              :                                 type_name = "uint8";
    2929          374 :                         } else if (type_name == "gint16") {
    2930              :                                 type_name = "int16";
    2931          374 :                         } else if (type_name == "guint16") {
    2932              :                                 type_name = "uint16";
    2933          374 :                         } else if (type_name == "gint32") {
    2934            2 :                                 if (ctype != null && ctype.has_prefix ("socklen_t")) {
    2935              :                                         type_name = "socklen_t";
    2936              :                                 } else {
    2937              :                                         type_name = "int32";
    2938              :                                 }
    2939          372 :                         } else if (type_name == "guint32") {
    2940              :                                 type_name = "uint32";
    2941          372 :                         } else if (type_name == "gint64") {
    2942              :                                 type_name = "int64";
    2943          372 :                         } else if (type_name == "guint64") {
    2944              :                                 type_name = "uint64";
    2945          372 :                         } else if (type_name == "gfloat") {
    2946              :                                 type_name = "float";
    2947          371 :                         } else if (type_name == "gdouble") {
    2948              :                                 type_name = "double";
    2949          370 :                         } else if (type_name == "filename") {
    2950              :                                 type_name = "string";
    2951          370 :                         } else if (type_name == "GLib.offset") {
    2952              :                                 type_name = "int64";
    2953          370 :                         } else if (type_name == "gsize") {
    2954            7 :                                 if (ctype != null && ctype.has_prefix ("off_t")) {
    2955              :                                         type_name = "off_t";
    2956              :                                 } else {
    2957              :                                         type_name = "size_t";
    2958              :                                 }
    2959          363 :                         } else if (type_name == "gssize") {
    2960              :                                 type_name = "ssize_t";
    2961          363 :                         } else if (type_name == "guintptr") {
    2962              :                                 type_name = "uintptr";
    2963          363 :                         } else if (type_name == "gintptr") {
    2964              :                                 type_name = "intptr";
    2965          363 :                         } else if (type_name == "GType") {
    2966              :                                 type_name = "GLib.Type";
    2967          352 :                         } else if (type_name == "GObject.Class") {
    2968              :                                 type_name = "GLib.ObjectClass";
    2969          352 :                         } else if (type_name == "gunichar") {
    2970              :                                 type_name = "unichar";
    2971          352 :                         } else if (type_name == "Atk.ImplementorIface") {
    2972              :                                 type_name = "Atk.Implementor";
    2973              :                         } else {
    2974          352 :                                 known_type = false;
    2975              :                         }
    2976              : 
    2977         1145 :                         if (type == null) {
    2978          569 :                                 var sym = parse_symbol_from_string (type_name, get_current_src ());
    2979          569 :                                 type = new UnresolvedType.from_symbol (sym, get_current_src ());
    2980          569 :                                 if (!known_type) {
    2981          352 :                                         unresolved_gir_symbols.add (sym);
    2982              :                                 }
    2983              :                         }
    2984              :                 }
    2985              : 
    2986          794 :                 return type;
    2987              :         }
    2988              : 
    2989           72 :         void parse_record () {
    2990           36 :                 start_element ("record");
    2991           36 :                 push_node (element_get_name (), true);
    2992              : 
    2993              :                 Struct st;
    2994           36 :                 bool require_copy_free = false;
    2995           36 :                 if (current.new_symbol) {
    2996           36 :                         st = new Struct (element_get_name (), current.source_reference);
    2997           72 :                         current.symbol = st;
    2998              :                 } else {
    2999            0 :                         st = (Struct) current.symbol;
    3000              :                 }
    3001              : 
    3002           36 :                 set_type_id_ccode (st);
    3003           36 :                 require_copy_free = st.has_attribute_argument ("CCode", "type_id");
    3004              : 
    3005           36 :                 st.access = SymbolAccessibility.PUBLIC;
    3006              : 
    3007           36 :                 var gtype_struct_for = reader.get_attribute ("glib:is-gtype-struct-for");
    3008           36 :                 if (gtype_struct_for != null) {
    3009           31 :                         current.gtype_struct_for = parse_symbol_from_string (gtype_struct_for, current.source_reference);
    3010           31 :                         unresolved_gir_symbols.add (current.gtype_struct_for);
    3011              :                 }
    3012           36 :                 if (metadata.has_argument (ArgumentType.TYPE_PARAMETERS)) {
    3013            0 :                         parse_type_parameters_from_string (st, metadata.get_string (ArgumentType.TYPE_PARAMETERS), metadata.get_source_reference (ArgumentType.TYPE_PARAMETERS));
    3014              :                 }
    3015              : 
    3016           36 :                 bool first_field = true;
    3017           36 :                 next ();
    3018              : 
    3019           36 :                 st.comment = parse_symbol_doc ();
    3020              : 
    3021          122 :                 while (current_token == MarkupTokenType.START_ELEMENT) {
    3022           86 :                         if (!push_metadata ()) {
    3023           24 :                                 if (first_field && reader.name == "field") {
    3024           24 :                                         first_field = false;
    3025              :                                 }
    3026           24 :                                 skip_element ();
    3027           24 :                                 continue;
    3028              :                         }
    3029              : 
    3030           62 :                         if (reader.name == "field") {
    3031           49 :                                 if (reader.get_attribute ("name") != "priv" && !(first_field && gtype_struct_for != null)) {
    3032           42 :                                         parse_field ();
    3033              :                                 } else {
    3034            7 :                                         skip_element ();
    3035              :                                 }
    3036              :                                 first_field = false;
    3037           13 :                         } else if (reader.name == "constructor") {
    3038            1 :                                 parse_constructor ();
    3039           12 :                         } else if (reader.name == "method") {
    3040           11 :                                 parse_method ("method");
    3041            1 :                         } else if (reader.name == "function") {
    3042            0 :                                 parse_method ("function");
    3043            1 :                         } else if (reader.name == "function-macro") {
    3044            0 :                                 skip_element ();
    3045            1 :                         } else if (reader.name == "union") {
    3046            1 :                                 parse_union ();
    3047              :                         } else {
    3048              :                                 // error
    3049            0 :                                 Report.error (get_current_src (), "unknown child element `%s' in `record'", reader.name);
    3050            0 :                                 skip_element ();
    3051              :                         }
    3052              : 
    3053           62 :                         pop_metadata ();
    3054              :                 }
    3055              : 
    3056              :                 // Add default g_boxed_copy/free ccode-attributes
    3057           36 :                 if (require_copy_free) {
    3058            1 :                         st.set_attribute_string ("CCode", "copy_function", "g_boxed_copy");
    3059            1 :                         st.set_attribute_string ("CCode", "free_function", "g_boxed_free");
    3060              :                 }
    3061              : 
    3062           36 :                 pop_node ();
    3063           36 :                 end_element ("record");
    3064              :         }
    3065              : 
    3066           52 :         void parse_class () {
    3067           26 :                 start_element ("class");
    3068           26 :                 push_node (element_get_name (), true);
    3069              : 
    3070              :                 Class cl;
    3071           26 :                 var parent = reader.get_attribute ("parent");
    3072           26 :                 if (current.new_symbol) {
    3073           26 :                         cl = new Class (current.name, current.source_reference);
    3074           26 :                         cl.is_abstract = metadata.get_bool (ArgumentType.ABSTRACT, reader.get_attribute ("abstract") == "1");
    3075           26 :                         cl.is_sealed = metadata.get_bool (ArgumentType.SEALED, reader.get_attribute ("final") == "1");
    3076           26 :                         if (metadata.has_argument (ArgumentType.TYPE_GET_FUNCTION)) {
    3077            0 :                                 cl.set_attribute_string ("CCode", "type_get_function", metadata.get_string (ArgumentType.TYPE_GET_FUNCTION));
    3078              :                         }
    3079              : 
    3080           26 :                         if (parent != null) {
    3081           21 :                                 cl.add_base_type (parse_type_from_gir_name (parent));
    3082              :                         }
    3083           26 :                         var type_struct = reader.get_attribute ("glib:type-struct");
    3084           26 :                         if (type_struct != null) {
    3085           26 :                                 current.type_struct = parse_symbol_from_string (type_struct, current.source_reference);
    3086           26 :                                 unresolved_gir_symbols.add (current.type_struct);
    3087              :                         }
    3088           52 :                         current.symbol = cl;
    3089              :                 } else {
    3090            0 :                         cl = (Class) current.symbol;
    3091              :                 }
    3092              : 
    3093           26 :                 set_type_id_ccode (cl);
    3094              : 
    3095           26 :                 cl.access = SymbolAccessibility.PUBLIC;
    3096              : 
    3097           26 :                 if (metadata.has_argument (ArgumentType.REF_FUNCTION)) {
    3098            0 :                         cl.set_attribute_string ("CCode", "ref_function", metadata.get_string (ArgumentType.REF_FUNCTION));
    3099           26 :                 } else if (reader.has_attribute ("glib:ref-func")) {
    3100            5 :                         cl.set_attribute_string ("CCode", "ref_function", reader.get_attribute ("glib:ref-func"));
    3101              :                 }
    3102           26 :                 if (metadata.has_argument (ArgumentType.REF_SINK_FUNCTION)) {
    3103            0 :                         cl.set_attribute_string ("CCode", "ref_sink_function", metadata.get_string (ArgumentType.REF_SINK_FUNCTION));
    3104              :                 }
    3105           26 :                 if (metadata.has_argument (ArgumentType.UNREF_FUNCTION)) {
    3106            0 :                         cl.set_attribute_string ("CCode", "unref_function", metadata.get_string (ArgumentType.UNREF_FUNCTION));
    3107           26 :                 } else if (reader.has_attribute ("glib:unref-func")) {
    3108            5 :                         cl.set_attribute_string ("CCode", "unref_function", reader.get_attribute ("glib:unref-func"));
    3109              :                 }
    3110           26 :                 if (metadata.has_argument (ArgumentType.TYPE_PARAMETERS)) {
    3111            0 :                         parse_type_parameters_from_string (cl, metadata.get_string (ArgumentType.TYPE_PARAMETERS), metadata.get_source_reference (ArgumentType.TYPE_PARAMETERS));
    3112              :                 }
    3113           26 :                 if (metadata.has_argument (ArgumentType.IMPLEMENTS)) {
    3114            0 :                         current.inherited_types = parse_list_of_types_from_string (metadata.get_string (ArgumentType.IMPLEMENTS), metadata.get_source_reference (ArgumentType.IMPLEMENTS));
    3115              :                 }
    3116              : 
    3117           26 :                 next ();
    3118              : 
    3119           26 :                 cl.comment = parse_symbol_doc ();
    3120              : 
    3121              :                 var first_field = true;
    3122          222 :                 while (current_token == MarkupTokenType.START_ELEMENT) {
    3123          196 :                         if (!push_metadata ()) {
    3124           33 :                                 if (first_field && reader.name == "field") {
    3125           33 :                                         first_field = false;
    3126              :                                 }
    3127           33 :                                 skip_element ();
    3128           33 :                                 continue;
    3129              :                         }
    3130              : 
    3131          163 :                         if (reader.name == "implements") {
    3132            3 :                                 start_element ("implements");
    3133            3 :                                 cl.add_base_type (parse_type_from_gir_name (reader.get_attribute ("name")));
    3134            3 :                                 next ();
    3135            3 :                                 end_element ("implements");
    3136          160 :                         } else if (reader.name == "constant") {
    3137            0 :                                 parse_constant ();
    3138          160 :                         } else if (reader.name == "field") {
    3139           26 :                                 if (first_field && parent != null) {
    3140              :                                         // first field is guaranteed to be the parent instance
    3141           13 :                                         skip_element ();
    3142              :                                 } else {
    3143           13 :                                         if (reader.get_attribute ("name") != "priv") {
    3144           13 :                                                 parse_field ();
    3145              :                                         } else {
    3146            0 :                                                 skip_element ();
    3147              :                                         }
    3148              :                                 }
    3149              :                                 first_field = false;
    3150          134 :                         } else if (reader.name == "property") {
    3151           14 :                                 parse_property ();
    3152          120 :                         } else if (reader.name == "constructor") {
    3153           21 :                                 parse_constructor ();
    3154           99 :                         } else if (reader.name == "function") {
    3155            8 :                                 parse_method ("function");
    3156           91 :                         } else if (reader.name == "function-macro") {
    3157            0 :                                 skip_element ();
    3158           91 :                         } else if (reader.name == "method") {
    3159           62 :                                 parse_method ("method");
    3160           29 :                         } else if (reader.name == "virtual-method") {
    3161           25 :                                 parse_method ("virtual-method");
    3162            4 :                         } else if (reader.name == "union") {
    3163            0 :                                 parse_union ();
    3164            4 :                         } else if (reader.name == "glib:signal") {
    3165            4 :                                 parse_signal ();
    3166              :                         } else {
    3167              :                                 // error
    3168            0 :                                 Report.error (get_current_src (), "unknown child element `%s' in `class'", reader.name);
    3169            0 :                                 skip_element ();
    3170              :                         }
    3171              : 
    3172          163 :                         pop_metadata ();
    3173              :                 }
    3174              : 
    3175              :                 // There is no instance field therefore this type might be final/sealed
    3176           26 :                 if (first_field && !cl.is_abstract && !(cl.is_opaque || cl.is_sealed)) {
    3177            0 :                         if (!cl.is_compact
    3178            0 :                             && !metadata.has_argument (ArgumentType.ABSTRACT)
    3179            0 :                             && !metadata.has_argument (ArgumentType.COMPACT)
    3180            0 :                             && !metadata.has_argument (ArgumentType.SEALED)) {
    3181            0 :                                 cl.is_sealed = true;
    3182              :                         }
    3183              :                 }
    3184              : 
    3185           26 :                 pop_node ();
    3186           26 :                 end_element ("class");
    3187              :         }
    3188              : 
    3189           12 :         void parse_interface () {
    3190            6 :                 start_element ("interface");
    3191            6 :                 push_node (element_get_name (), true);
    3192              : 
    3193              :                 Interface iface;
    3194            6 :                 if (current.new_symbol) {
    3195            6 :                         iface = new Interface (current.name, current.source_reference);
    3196            6 :                         if (metadata.has_argument (ArgumentType.TYPE_GET_FUNCTION)){
    3197            0 :                                 iface.set_attribute_string ("CCode", "type_get_function", metadata.get_string (ArgumentType.TYPE_GET_FUNCTION));
    3198              :                         }
    3199              : 
    3200           12 :                         current.symbol = iface;
    3201              :                 } else {
    3202            0 :                         iface = (Interface) current.symbol;
    3203              :                 }
    3204              : 
    3205            6 :                 set_type_id_ccode (iface);
    3206              : 
    3207            6 :                 iface.access = SymbolAccessibility.PUBLIC;
    3208              : 
    3209            6 :                 if (metadata.has_argument (ArgumentType.TYPE_PARAMETERS)) {
    3210            0 :                         parse_type_parameters_from_string (iface, metadata.get_string (ArgumentType.TYPE_PARAMETERS), metadata.get_source_reference (ArgumentType.TYPE_PARAMETERS));
    3211              :                 }
    3212            6 :                 if (metadata.has_argument (ArgumentType.PREREQUISITES)) {
    3213            0 :                         current.inherited_types = parse_list_of_types_from_string (metadata.get_string (ArgumentType.PREREQUISITES), metadata.get_source_reference (ArgumentType.PREREQUISITES));
    3214              :                 }
    3215              : 
    3216            6 :                 next ();
    3217              : 
    3218            6 :                 iface.comment = parse_symbol_doc ();
    3219              : 
    3220           42 :                 while (current_token == MarkupTokenType.START_ELEMENT) {
    3221           36 :                         if (!push_metadata ()) {
    3222            6 :                                 skip_element ();
    3223            6 :                                 continue;
    3224              :                         }
    3225              : 
    3226           30 :                         if (reader.name == "prerequisite") {
    3227            4 :                                 start_element ("prerequisite");
    3228            4 :                                 iface.add_prerequisite (parse_type_from_gir_name (reader.get_attribute ("name")));
    3229            4 :                                 next ();
    3230            4 :                                 end_element ("prerequisite");
    3231           26 :                         } else if (reader.name == "field") {
    3232            0 :                                 parse_field ();
    3233           26 :                         } else if (reader.name == "property") {
    3234            2 :                                 parse_property ();
    3235           24 :                         } else if (reader.name == "virtual-method") {
    3236           11 :                                 parse_method ("virtual-method");
    3237           13 :                         } else if (reader.name == "function") {
    3238            1 :                                 parse_method ("function");
    3239           12 :                         } else if (reader.name == "function-macro") {
    3240            0 :                                 skip_element ();
    3241           12 :                         } else if (reader.name == "method") {
    3242           11 :                                 parse_method ("method");
    3243            1 :                         } else if (reader.name == "glib:signal") {
    3244            1 :                                 parse_signal ();
    3245              :                         } else {
    3246              :                                 // error
    3247            0 :                                 Report.error (get_current_src (), "unknown child element `%s' in `interface'", reader.name);
    3248            0 :                                 skip_element ();
    3249              :                         }
    3250              : 
    3251           30 :                         pop_metadata ();
    3252              :                 }
    3253              : 
    3254            6 :                 pop_node ();
    3255            6 :                 end_element ("interface");
    3256              :         }
    3257              : 
    3258          124 :         void parse_field () {
    3259           62 :                 start_element ("field");
    3260           62 :                 push_node (element_get_name (), false);
    3261              : 
    3262           62 :                 string nullable = reader.get_attribute ("nullable");
    3263           62 :                 string allow_none = reader.get_attribute ("allow-none");
    3264           62 :                 next ();
    3265              : 
    3266           62 :                 var comment = parse_symbol_doc ();
    3267              : 
    3268              :                 bool no_array_length;
    3269              :                 bool array_null_terminated;
    3270              :                 int array_length_idx;
    3271           62 :                 var type = parse_type (null, out array_length_idx, true, out no_array_length, out array_null_terminated);
    3272           62 :                 type = element_get_type (type, true, ref no_array_length, ref array_null_terminated);
    3273              : 
    3274           62 :                 string name = current.name;
    3275           62 :                 string cname = current.girdata["name"];
    3276              : 
    3277           62 :                 var field = new Field (name, type, null, current.source_reference);
    3278           62 :                 field.access = SymbolAccessibility.PUBLIC;
    3279           62 :                 field.comment = comment;
    3280           62 :                 if (name != cname) {
    3281            0 :                         field.set_attribute_string ("CCode", "cname", cname);
    3282              :                 }
    3283           62 :                 if (type is ArrayType) {
    3284            3 :                         if (!no_array_length && array_length_idx > -1) {
    3285            0 :                                 current.array_length_idx = array_length_idx;
    3286              :                         }
    3287            3 :                         if (no_array_length || array_null_terminated) {
    3288            3 :                                 field.set_attribute_bool ("CCode", "array_length", !no_array_length);
    3289              :                         }
    3290            3 :                         if (array_null_terminated) {
    3291            1 :                                 field.set_attribute_bool ("CCode", "array_null_terminated", true);
    3292              :                         }
    3293              :                 }
    3294           62 :                 if (nullable == "1" || allow_none == "1") {
    3295            1 :                         type.nullable = true;
    3296              :                 }
    3297          124 :                 current.symbol = field;
    3298              : 
    3299           62 :                 pop_node ();
    3300           62 :                 end_element ("field");
    3301              :         }
    3302              : 
    3303           16 :         Property parse_property () {
    3304           16 :                 start_element ("property");
    3305           16 :                 push_node (element_get_name().replace ("-", "_"), false);
    3306           16 :                 bool is_abstract = metadata.get_bool (ArgumentType.ABSTRACT, current.parent.symbol is Interface);
    3307           16 :                 string transfer = reader.get_attribute ("transfer-ownership");
    3308              : 
    3309           16 :                 next ();
    3310              : 
    3311           16 :                 var comment = parse_symbol_doc ();
    3312              : 
    3313              :                 bool no_array_length;
    3314              :                 bool array_null_terminated;
    3315           16 :                 var type = parse_type (null, null, transfer != "container", out no_array_length, out array_null_terminated);
    3316           16 :                 type = element_get_type (type, true, ref no_array_length, ref array_null_terminated);
    3317           16 :                 var prop = new Property (current.name, type, null, null, current.source_reference);
    3318           16 :                 prop.comment = comment;
    3319           16 :                 prop.access = SymbolAccessibility.PUBLIC;
    3320           16 :                 prop.is_abstract = is_abstract;
    3321           16 :                 if (no_array_length || array_null_terminated) {
    3322            0 :                         prop.set_attribute_bool ("CCode", "array_length", !no_array_length);
    3323              :                 }
    3324           16 :                 if (array_null_terminated) {
    3325            0 :                         prop.set_attribute_bool ("CCode", "array_null_terminated", true);
    3326              :                 }
    3327           32 :                 current.symbol = prop;
    3328              : 
    3329           16 :                 pop_node ();
    3330           16 :                 end_element ("property");
    3331           16 :                 return prop;
    3332              :         }
    3333              : 
    3334           43 :         void parse_callback () {
    3335           43 :                 parse_function ("callback");
    3336              :         }
    3337              : 
    3338           24 :         void parse_constructor () {
    3339           24 :                 parse_function ("constructor");
    3340              :         }
    3341              : 
    3342         2902 :         class ParameterInfo {
    3343          700 :                 public ParameterInfo (Parameter param, int array_length_idx, int closure_idx, int destroy_idx, bool is_async = false) {
    3344          350 :                         this.param = param;
    3345          350 :                         this.array_length_idx = array_length_idx;
    3346          350 :                         this.closure_idx = closure_idx;
    3347          350 :                         this.destroy_idx = destroy_idx;
    3348          350 :                         this.vala_idx = 0.0F;
    3349          350 :                         this.keep = true;
    3350          350 :                         this.is_async = is_async;
    3351              :                 }
    3352              : 
    3353          350 :                 public Parameter param;
    3354              :                 public float vala_idx;
    3355              :                 public int array_length_idx;
    3356              :                 public int closure_idx;
    3357              :                 public int destroy_idx;
    3358              :                 public bool keep;
    3359              :                 public bool is_async;
    3360              :                 public bool is_async_result;
    3361              :                 public bool is_error;
    3362              :                 public bool caller_allocates;
    3363              :         }
    3364              : 
    3365          480 :         void parse_function (string element_name) {
    3366          240 :                 start_element (element_name);
    3367          240 :                 push_node (element_get_name (reader.get_attribute ("invoker")).replace ("-", "_"), false);
    3368              : 
    3369              :                 string symbol_type;
    3370          240 :                 if (metadata.has_argument (ArgumentType.SYMBOL_TYPE)) {
    3371            0 :                         symbol_type = metadata.get_string (ArgumentType.SYMBOL_TYPE);
    3372              :                 } else {
    3373          480 :                         symbol_type = element_name;
    3374              :                 }
    3375              : 
    3376          240 :                 string? ctype = null;
    3377          240 :                 if (metadata.has_argument (ArgumentType.CTYPE)) {
    3378            0 :                         ctype = metadata.get_string (ArgumentType.CTYPE);
    3379              :                 }
    3380              : 
    3381          240 :                 string name = current.name;
    3382          240 :                 string throws_string = reader.get_attribute ("throws");
    3383          240 :                 string invoker = reader.get_attribute ("invoker");
    3384          240 :                 current.deprecated_replacement = reader.get_attribute ("moved-to");
    3385              : 
    3386          240 :                 next ();
    3387              : 
    3388          240 :                 var comment = parse_symbol_doc ();
    3389              : 
    3390              :                 DataType return_type;
    3391          240 :                 string return_ctype = null;
    3392          240 :                 int return_array_length_idx = -1;
    3393          240 :                 bool return_no_array_length = false;
    3394          240 :                 bool return_array_null_terminated = false;
    3395          240 :                 if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "return-value") {
    3396              :                         Comment? return_comment;
    3397          240 :                         return_type = parse_return_value (out return_ctype, out return_array_length_idx, out return_no_array_length, out return_array_null_terminated, out return_comment);
    3398          240 :                         if (return_comment != null) {
    3399            0 :                                 if (comment == null) {
    3400            0 :                                         comment = new GirComment (null, current.source_reference);
    3401              :                                 }
    3402            0 :                                 comment.return_content = return_comment;
    3403              :                         }
    3404              :                 } else {
    3405            0 :                         return_type = new VoidType ();
    3406              :                 }
    3407              : 
    3408              :                 Symbol s;
    3409              : 
    3410          240 :                 if (symbol_type == "callback") {
    3411           43 :                         s = new Delegate (name, return_type, current.source_reference);
    3412           43 :                         ((Delegate) s).has_target = false;
    3413           43 :                         if (metadata.has_argument (ArgumentType.TYPE_PARAMETERS)) {
    3414            0 :                                 parse_type_parameters_from_string ((Delegate) s, metadata.get_string (ArgumentType.TYPE_PARAMETERS), metadata.get_source_reference (ArgumentType.TYPE_PARAMETERS));
    3415              :                         }
    3416          221 :                 } else if (symbol_type == "constructor") {
    3417           24 :                         if (name == "new") {
    3418           17 :                                 name = null;
    3419            7 :                         } else if (name.has_prefix ("new_")) {
    3420            2 :                                 name = name.substring ("new_".length);
    3421              :                         }
    3422           24 :                         var m = new CreationMethod (null, name, current.source_reference);
    3423           24 :                         m.has_construct_function = false;
    3424              : 
    3425           24 :                         if (name != null && !current.name.has_prefix ("new_")) {
    3426            5 :                                 m.set_attribute_string ("CCode", "cname", current.girdata["c:identifier"]);
    3427              :                         }
    3428              : 
    3429           24 :                         string parent_ctype = null;
    3430           24 :                         if (current.parent.symbol is Class) {
    3431           23 :                                 parent_ctype = current.parent.get_cname ();
    3432              :                         }
    3433           24 :                         if (return_ctype != null && (parent_ctype == null || return_ctype != parent_ctype + "*")) {
    3434            1 :                                 m.set_attribute_string ("CCode", "type", return_ctype);
    3435              :                         }
    3436           24 :                         if (metadata.has_argument (ArgumentType.TYPE_PARAMETERS)) {
    3437            0 :                                 parse_type_parameters_from_string (m, metadata.get_string (ArgumentType.TYPE_PARAMETERS), metadata.get_source_reference (ArgumentType.TYPE_PARAMETERS));
    3438              :                         }
    3439           48 :                         s = m;
    3440          173 :                 } else if (symbol_type == "glib:signal") {
    3441            5 :                         s = new Signal (name, return_type, current.source_reference);
    3442              :                 } else {
    3443          168 :                         s = new Method (name, return_type, current.source_reference);
    3444          168 :                         if (metadata.has_argument (ArgumentType.TYPE_PARAMETERS)) {
    3445            0 :                                 parse_type_parameters_from_string ((Method) s, metadata.get_string (ArgumentType.TYPE_PARAMETERS), metadata.get_source_reference (ArgumentType.TYPE_PARAMETERS));
    3446              :                         }
    3447              :                 }
    3448              : 
    3449          240 :                 s.access = SymbolAccessibility.PUBLIC;
    3450          240 :                 s.comment = comment;
    3451              : 
    3452              :                 // Transform fixed-array properties of return-type into ccode-attribute
    3453          240 :                 var array_type = return_type as ArrayType;
    3454           12 :                 if (array_type != null && array_type.fixed_length) {
    3455            1 :                         s.set_attribute_string ("CCode", "array_length_cexpr", ((IntegerLiteral) array_type.length).value);
    3456            1 :                         array_type.fixed_length = false;
    3457            1 :                         array_type.length = null;
    3458              :                 }
    3459              : 
    3460          240 :                 if (s is Signal) {
    3461            5 :                         if (current.girdata["name"] != name.replace ("_", "-")) {
    3462            0 :                                 s.set_attribute_string ("CCode", "cname", current.girdata["name"]);
    3463              :                         }
    3464              :                 }
    3465              : 
    3466          432 :                 if (s is Method) {
    3467          192 :                         var m = (Method) s;
    3468          192 :                         if (symbol_type == "virtual-method" || symbol_type == "callback") {
    3469           36 :                                 if (current.parent.symbol is Interface) {
    3470           11 :                                         m.is_abstract = true;
    3471              :                                 } else {
    3472           25 :                                         m.is_virtual = true;
    3473              :                                 }
    3474           36 :                                 if (metadata.has_argument (ArgumentType.NO_WRAPPER)) {
    3475            0 :                                         s.set_attribute ("NoWrapper", metadata.get_bool (ArgumentType.NO_WRAPPER), s.source_reference);
    3476           36 :                                 } else if (invoker == null && !metadata.has_argument (ArgumentType.VFUNC_NAME)) {
    3477           11 :                                         s.set_attribute ("NoWrapper", true, s.source_reference);
    3478              :                                 }
    3479           36 :                                 if (current.girdata["name"] != name) {
    3480            0 :                                         m.set_attribute_string ("CCode", "vfunc_name", current.girdata["name"]);
    3481              :                                 }
    3482          156 :                         } else if (symbol_type == "function") {
    3483           46 :                                 m.binding = MemberBinding.STATIC;
    3484              :                         }
    3485          192 :                         if (metadata.has_argument (ArgumentType.FLOATING)) {
    3486            0 :                                 m.returns_floating_reference = metadata.get_bool (ArgumentType.FLOATING);
    3487            0 :                                 m.return_type.value_owned = true;
    3488              :                         }
    3489          192 :                         if (metadata.has_argument (ArgumentType.NEW)) {
    3490            0 :                                 m.hides = metadata.get_bool (ArgumentType.NEW);
    3491              :                         }
    3492              :                 }
    3493              : 
    3494          408 :                 if (s is Method && !(s is CreationMethod)) {
    3495          168 :                         var method = (Method) s;
    3496          168 :                         if (metadata.has_argument (ArgumentType.VIRTUAL)) {
    3497           10 :                                 method.is_virtual = metadata.get_bool (ArgumentType.VIRTUAL);
    3498           10 :                                 method.is_abstract = false;
    3499          158 :                         } else if (metadata.has_argument (ArgumentType.ABSTRACT)) {
    3500           10 :                                 method.is_abstract = metadata.get_bool (ArgumentType.ABSTRACT);
    3501           10 :                                 method.is_virtual = false;
    3502              :                         }
    3503          168 :                         if (metadata.has_argument (ArgumentType.VFUNC_NAME)) {
    3504            0 :                                 method.set_attribute_string ("CCode", "vfunc_name", metadata.get_string (ArgumentType.VFUNC_NAME));
    3505            0 :                                 method.is_virtual = true;
    3506              :                         }
    3507          168 :                         if (metadata.has_argument (ArgumentType.FINISH_VFUNC_NAME)) {
    3508            0 :                                 method.set_attribute_string ("CCode", "finish_vfunc_name", metadata.get_string (ArgumentType.FINISH_VFUNC_NAME));
    3509            0 :                                 method.is_virtual = true;
    3510              :                         }
    3511              :                 }
    3512              : 
    3513          240 :                 if (!(metadata.get_expression (ArgumentType.THROWS) is NullLiteral)) {
    3514          249 :                         if (metadata.has_argument (ArgumentType.THROWS)) {
    3515            9 :                                 var error_types = metadata.get_string (ArgumentType.THROWS).split(",");
    3516           36 :                                 foreach (var error_type_name in error_types) {
    3517            9 :                                         var error_type = parse_type_from_string (error_type_name, true, metadata.get_source_reference (ArgumentType.THROWS));
    3518            9 :                                         if (s is Method) {
    3519            8 :                                                 ((Method) s).add_error_type (error_type);
    3520              :                                         } else {
    3521            1 :                                                 ((Delegate) s).add_error_type (error_type);
    3522              :                                         }
    3523              :                                 }
    3524          231 :                         } else if (throws_string == "1") {
    3525           16 :                                 if (s is Method) {
    3526           12 :                                         ((Method) s).add_error_type (new ErrorType (null, null));
    3527              :                                 } else {
    3528            4 :                                         ((Delegate) s).add_error_type (new ErrorType (null, null));
    3529              :                                 }
    3530              :                         }
    3531              :                 }
    3532              : 
    3533          432 :                 if (s is Method) {
    3534          192 :                         var m = (Method) s;
    3535          192 :                         m.set_attribute ("PrintfFormat", metadata.get_bool (ArgumentType.PRINTF_FORMAT));
    3536          192 :                         if (metadata.has_argument (ArgumentType.SENTINEL)) {
    3537            0 :                                 m.set_attribute_string ("CCode", "sentinel", metadata.get_string (ArgumentType.SENTINEL));
    3538              :                         }
    3539              :                 }
    3540              : 
    3541          240 :                 if (return_type is ArrayType && metadata.has_argument (ArgumentType.ARRAY_LENGTH_IDX)) {
    3542            0 :                         return_array_length_idx = metadata.get_integer (ArgumentType.ARRAY_LENGTH_IDX);
    3543              :                 } else {
    3544          240 :                         if (return_no_array_length || return_array_null_terminated) {
    3545            2 :                                 s.set_attribute_bool ("CCode", "array_length", !return_no_array_length);
    3546              :                         }
    3547          240 :                         if (return_array_null_terminated) {
    3548            1 :                                 s.set_attribute_bool ("CCode", "array_null_terminated", true);
    3549              :                         }
    3550              :                 }
    3551          240 :                 current.return_array_length_idx = return_array_length_idx;
    3552              : 
    3553          240 :                 if (ctype != null) {
    3554            0 :                         s.set_attribute_string ("CCode", "type", ctype);
    3555              :                 }
    3556              : 
    3557          480 :                 current.symbol = s;
    3558              : 
    3559          240 :                 if (metadata.has_argument (ArgumentType.FINISH_NAME)) {
    3560            0 :                         s.set_attribute_string ("CCode", "finish_name", metadata.get_string (ArgumentType.FINISH_NAME));
    3561              :                 }
    3562          240 :                 if (metadata.has_argument (ArgumentType.FINISH_INSTANCE)) {
    3563            0 :                         s.set_attribute_bool ("CCode", "finish_instance", metadata.get_bool (ArgumentType.FINISH_INSTANCE));
    3564              :                 }
    3565              : 
    3566          240 :                 int instance_idx = -2;
    3567          240 :                 if (element_name == "function" && symbol_type == "method") {
    3568            0 :                         if (metadata.has_argument (ArgumentType.INSTANCE_IDX)) {
    3569            0 :                                 instance_idx = metadata.get_integer (ArgumentType.INSTANCE_IDX);
    3570            0 :                                 if (instance_idx != 0) {
    3571            0 :                                         s.set_attribute_double ("CCode", "instance_pos", instance_idx + 0.5);
    3572              :                                 }
    3573              :                         } else {
    3574            0 :                                 Report.error (get_current_src (), "instance_idx required when converting function to method");
    3575              :                         }
    3576              :                 }
    3577          240 :                 if (element_name == "callback") {
    3578           43 :                         if (metadata.has_argument (ArgumentType.INSTANCE_IDX)) {
    3579            0 :                                 instance_idx = metadata.get_integer (ArgumentType.INSTANCE_IDX);
    3580            0 :                                 s.set_attribute_double ("CCode", "instance_pos", instance_idx + 0.9);
    3581            0 :                                 ((Delegate) s).has_target = true;
    3582              :                         }
    3583              :                 }
    3584              : 
    3585          240 :                 var parameters = new ArrayList<ParameterInfo> ();
    3586          240 :                 current.array_length_parameters = new ArrayList<int> ();
    3587          240 :                 current.closure_parameters = new ArrayList<int> ();
    3588          240 :                 current.destroy_parameters = new ArrayList<int> ();
    3589          240 :                 if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "parameters") {
    3590          203 :                         start_element ("parameters");
    3591          203 :                         next ();
    3592              : 
    3593          203 :                         var current_parameter_idx = -1;
    3594         1011 :                         while (current_token == MarkupTokenType.START_ELEMENT) {
    3595          458 :                                 var is_instance_parameter = (reader.name == "instance-parameter"
    3596          108 :                                         && !(symbol_type == "function" || symbol_type == "constructor"));
    3597              : 
    3598          108 :                                 if (!is_instance_parameter) {
    3599          350 :                                         current_parameter_idx++;
    3600              :                                 }
    3601              : 
    3602          458 :                                 if (instance_idx > -2 && instance_idx == current_parameter_idx) {
    3603            0 :                                         skip_element ();
    3604          108 :                                         continue;
    3605              :                                 }
    3606              : 
    3607          458 :                                 if (!push_metadata ()) {
    3608            0 :                                         skip_element ();
    3609            0 :                                         continue;
    3610              :                                 }
    3611              : 
    3612              :                                 bool caller_allocates;
    3613              :                                 int array_length_idx, closure_idx, destroy_idx;
    3614              :                                 string scope;
    3615          458 :                                 string default_param_name = null;
    3616              :                                 Comment? param_comment;
    3617          458 :                                 default_param_name = "arg%d".printf (parameters.size);
    3618          458 :                                 var param = parse_parameter (out caller_allocates, out array_length_idx, out closure_idx, out destroy_idx, out scope, out param_comment, default_param_name);
    3619              : 
    3620          458 :                                 if (is_instance_parameter) {
    3621          108 :                                         unowned Method? m = s as Method;
    3622          108 :                                         if (m != null) {
    3623          108 :                                                 if (param.direction == ParameterDirection.IN) {
    3624          104 :                                                         if (param.variable_type.value_owned) {
    3625            2 :                                                                 m.set_attribute ("DestroysInstance", true);
    3626              :                                                         }
    3627          104 :                                                         pop_metadata ();
    3628          104 :                                                         continue;
    3629            4 :                                                 } else if (current.parent.symbol is Struct
    3630            4 :                                                     && caller_allocates && param.direction == ParameterDirection.OUT) {
    3631              :                                                         // struct methods that have instance parameters with 'out' direction are usually creation methods
    3632            4 :                                                         string? cm_name = m.name;
    3633            4 :                                                         if (cm_name != null && (cm_name == "init" || cm_name.has_prefix ("init_"))) {
    3634            4 :                                                                 if (cm_name == "init") {
    3635            2 :                                                                         cm_name = null;
    3636            2 :                                                                 } else if (cm_name.has_prefix ("init_")) {
    3637            2 :                                                                         cm_name = cm_name.substring ("init_".length);
    3638              :                                                                 }
    3639            4 :                                                                 s = new CreationMethod (null, cm_name, m.source_reference, m.comment);
    3640            4 :                                                                 s.access = SymbolAccessibility.PUBLIC;
    3641            8 :                                                                 current.symbol = s;
    3642            4 :                                                                 pop_metadata ();
    3643            4 :                                                                 continue;
    3644              :                                                         }
    3645            0 :                                                 } else if (current.parent.symbol is Class && ((Class) current.parent.symbol).is_compact
    3646            0 :                                                     && caller_allocates && param.direction == ParameterDirection.OUT) {
    3647            0 :                                                         pop_metadata ();
    3648            0 :                                                         continue;
    3649              :                                                 }
    3650              :                                                 //TODO can more be done here?
    3651            0 :                                                 m.binding = MemberBinding.STATIC;
    3652              :                                         }
    3653              :                                 }
    3654              : 
    3655          350 :                                 if (array_length_idx != -1) {
    3656           20 :                                         if (instance_idx > -2 && instance_idx < array_length_idx) {
    3657            0 :                                                 array_length_idx--;
    3658              :                                         }
    3659           20 :                                         current.array_length_parameters.add (array_length_idx);
    3660              :                                 }
    3661          350 :                                 if (closure_idx != -1) {
    3662           43 :                                         if (instance_idx > -2 && instance_idx < closure_idx) {
    3663            0 :                                                 closure_idx--;
    3664              :                                         }
    3665           43 :                                         if (current.closure_parameters.index_of (current_parameter_idx) < 0) {
    3666           41 :                                                 current.closure_parameters.add (closure_idx);
    3667              :                                         }
    3668              :                                 }
    3669          350 :                                 if (destroy_idx != -1) {
    3670           16 :                                         if (instance_idx > -2 && instance_idx < destroy_idx) {
    3671            0 :                                                 destroy_idx--;
    3672              :                                         }
    3673           16 :                                         if (current.destroy_parameters.index_of (current_parameter_idx) < 0) {
    3674           14 :                                                 current.destroy_parameters.add (destroy_idx);
    3675              :                                         }
    3676              :                                 }
    3677          350 :                                 if (param_comment != null) {
    3678            2 :                                         if (comment == null) {
    3679            1 :                                                 comment = new GirComment (null, s.source_reference);
    3680            1 :                                                 s.comment = comment;
    3681              :                                         }
    3682              : 
    3683            2 :                                         comment.add_content_for_parameter ((param.ellipsis)? "..." : param.name, param_comment);
    3684              :                                 }
    3685              : 
    3686          350 :                                 var info = new ParameterInfo (param, array_length_idx, closure_idx, destroy_idx, scope == "async");
    3687          350 :                                 info.caller_allocates = caller_allocates;
    3688          350 :                                 parameters.add (info);
    3689          350 :                                 pop_metadata ();
    3690              :                         }
    3691          203 :                         end_element ("parameters");
    3692              :                 }
    3693          480 :                 current.parameters = parameters;
    3694              : 
    3695          240 :                 pop_node ();
    3696          240 :                 end_element (element_name);
    3697              :         }
    3698              : 
    3699          168 :         void parse_method (string element_name) {
    3700          168 :                 parse_function (element_name);
    3701              :         }
    3702              : 
    3703            5 :         void parse_signal () {
    3704            5 :                 parse_function ("glib:signal");
    3705              :         }
    3706              : 
    3707            8 :         void parse_boxed (string element_name) {
    3708            4 :                 start_element (element_name);
    3709            4 :                 string name = reader.get_attribute ("name");
    3710            4 :                 if (name == null) {
    3711            0 :                         name = reader.get_attribute ("glib:name");
    3712              :                 }
    3713            4 :                 push_node (element_get_name (name), true);
    3714              : 
    3715              :                 Class cl;
    3716            4 :                 bool require_copy_free = false;
    3717            4 :                 if (current.new_symbol) {
    3718            4 :                         cl = new Class (current.name, current.source_reference);
    3719            4 :                         if (metadata.has_argument (ArgumentType.COMPACT)) {
    3720            0 :                                 cl.set_attribute ("Compact", metadata.get_bool (ArgumentType.COMPACT));
    3721              :                         } else {
    3722            4 :                                 cl.set_attribute ("Compact", true);
    3723              :                         }
    3724            4 :                         if (metadata.has_argument (ArgumentType.SEALED) && metadata.get_bool (ArgumentType.SEALED)) {
    3725            0 :                                 if (cl.is_compact) {
    3726            0 :                                         cl.set_attribute_bool ("Compact", "opaque", true);
    3727              :                                 } else {
    3728            0 :                                         cl.is_sealed = true;
    3729              :                                 }
    3730              :                         }
    3731              : 
    3732            8 :                         current.symbol = cl;
    3733              :                 } else {
    3734            0 :                         cl = (Class) current.symbol;
    3735              :                 }
    3736              : 
    3737            4 :                 set_type_id_ccode (cl);
    3738            4 :                 require_copy_free = cl.has_attribute_argument ("CCode", "type_id");
    3739              : 
    3740            4 :                 cl.access = SymbolAccessibility.PUBLIC;
    3741              : 
    3742            4 :                 if (metadata.has_argument (ArgumentType.BASE_TYPE)) {
    3743            0 :                         cl.add_base_type (parse_type_from_string (metadata.get_string (ArgumentType.BASE_TYPE), true, metadata.get_source_reference (ArgumentType.BASE_TYPE)));
    3744              :                 }
    3745            4 :                 if (metadata.has_argument (ArgumentType.COPY_FUNCTION)) {
    3746            0 :                         cl.set_attribute_string ("CCode", "copy_function", metadata.get_string (ArgumentType.COPY_FUNCTION));
    3747            4 :                 } else if (reader.has_attribute ("copy-function")) {
    3748            1 :                         cl.set_attribute_string ("CCode", "copy_function", reader.get_attribute ("copy-function"));
    3749              :                 }
    3750            4 :                 if (metadata.has_argument (ArgumentType.FREE_FUNCTION)) {
    3751            0 :                         cl.set_attribute_string ("CCode", "free_function", metadata.get_string (ArgumentType.FREE_FUNCTION));
    3752            4 :                 } else if (reader.has_attribute ("free-function")) {
    3753            1 :                         cl.set_attribute_string ("CCode", "free_function", reader.get_attribute ("free-function"));
    3754              :                 }
    3755            4 :                 if (metadata.has_argument (ArgumentType.REF_FUNCTION)) {
    3756            0 :                         cl.set_attribute_string ("CCode", "ref_function", metadata.get_string (ArgumentType.REF_FUNCTION));
    3757            4 :                 } else if (reader.has_attribute ("glib:ref-func")) {
    3758            0 :                         cl.set_attribute_string ("CCode", "ref_function", reader.get_attribute ("glib:ref-func"));
    3759              :                 }
    3760            4 :                 if (metadata.has_argument (ArgumentType.REF_SINK_FUNCTION)) {
    3761            0 :                         cl.set_attribute_string ("CCode", "ref_sink_function", metadata.get_string (ArgumentType.REF_SINK_FUNCTION));
    3762              :                 }
    3763            4 :                 if (metadata.has_argument (ArgumentType.UNREF_FUNCTION)) {
    3764            0 :                         cl.set_attribute_string ("CCode", "unref_function", metadata.get_string (ArgumentType.UNREF_FUNCTION));
    3765            4 :                 } else if (reader.has_attribute ("glib:unref-func")) {
    3766            0 :                         cl.set_attribute_string ("CCode", "unref_function", reader.get_attribute ("glib:unref-func"));
    3767              :                 }
    3768              : 
    3769            4 :                 next ();
    3770              : 
    3771            4 :                 cl.comment = parse_symbol_doc ();
    3772              : 
    3773              :                 Node? ref_method = null;
    3774              :                 Node? unref_method = null;
    3775              : 
    3776           12 :                 while (current_token == MarkupTokenType.START_ELEMENT) {
    3777            8 :                         if (!push_metadata ()) {
    3778            0 :                                 skip_element ();
    3779            0 :                                 continue;
    3780              :                         }
    3781              : 
    3782            8 :                         if (reader.name == "field") {
    3783            4 :                                 parse_field ();
    3784            4 :                         } else if (reader.name == "constructor") {
    3785            2 :                                 parse_constructor ();
    3786            4 :                         } else if (reader.name == "method") {
    3787            2 :                                 parse_method ("method");
    3788            2 :                                 var cname = old_current.get_cname ();
    3789            2 :                                 if (cname.has_suffix ("_ref") && (ref_method == null || old_current.name == "ref")) {
    3790            0 :                                         ref_method = old_current;
    3791            2 :                                 } else if (cname.has_suffix ("_unref") && (unref_method == null || old_current.name == "unref")) {
    3792            0 :                                         unref_method = old_current;
    3793              :                                 }
    3794            0 :                         } else if (reader.name == "function") {
    3795            0 :                                 parse_method ("function");
    3796            0 :                         } else if (reader.name == "function-macro") {
    3797            0 :                                 skip_element ();
    3798            0 :                         } else if (reader.name == "union") {
    3799            0 :                                 parse_union ();
    3800              :                         } else {
    3801              :                                 // error
    3802            0 :                                 Report.error (get_current_src (), "unknown child element `%s' in `class'", reader.name);
    3803            0 :                                 skip_element ();
    3804              :                         }
    3805              : 
    3806            8 :                         pop_metadata ();
    3807              :                 }
    3808              : 
    3809              :                 // Add ccode-attributes for ref/unref methodes if available
    3810              :                 // otherwise fallback to default g_boxed_copy/free
    3811           11 :                 if (cl.has_attribute_argument ("CCode", "ref_function") || cl.has_attribute_argument ("CCode", "unref_function")
    3812            7 :                     || cl.has_attribute_argument ("CCode", "copy_function") || cl.has_attribute_argument ("CCode", "free_function")) {
    3813              :                         //do nothing
    3814            3 :                 } else if (ref_method != null && unref_method != null) {
    3815            0 :                         cl.set_attribute_string ("CCode", "ref_function", ref_method.get_cname ());
    3816            0 :                         cl.set_attribute_string ("CCode", "unref_function", unref_method.get_cname ());
    3817            3 :                 } else if (require_copy_free) {
    3818            2 :                         cl.set_attribute_string ("CCode", "copy_function", "g_boxed_copy");
    3819            2 :                         cl.set_attribute_string ("CCode", "free_function", "g_boxed_free");
    3820              :                 }
    3821              : 
    3822            4 :                 pop_node ();
    3823            4 :                 end_element (element_name);
    3824              :         }
    3825              : 
    3826            3 :         void parse_union () {
    3827            2 :                 start_element ("union");
    3828              : 
    3829            2 :                 string? element_name = element_get_name ();
    3830            2 :                 if (element_name == null) {
    3831            1 :                         next ();
    3832              : 
    3833            1 :                         parse_symbol_doc ();
    3834              : 
    3835            3 :                         while (current_token == MarkupTokenType.START_ELEMENT) {
    3836            2 :                                 if (!push_metadata ()) {
    3837            1 :                                         skip_element ();
    3838            1 :                                         continue;
    3839              :                                 }
    3840              : 
    3841            1 :                                 if (reader.name == "field") {
    3842            1 :                                         parse_field ();
    3843            0 :                                 } else if (reader.name == "record") {
    3844            0 :                                         Report.warning (get_current_src (), "unhandled child element `%s' in `transparent union'", reader.name);
    3845            0 :                                         skip_element ();
    3846              :                                 } else {
    3847              :                                         // error
    3848            0 :                                         Report.error (get_current_src (), "unknown child element `%s' in `transparent union'", reader.name);
    3849            0 :                                         skip_element ();
    3850              :                                 }
    3851              : 
    3852            1 :                                 pop_metadata ();
    3853              :                         }
    3854              : 
    3855            1 :                         end_element ("union");
    3856            1 :                         return;
    3857              :                 }
    3858              : 
    3859            1 :                 push_node (element_name, true);
    3860              : 
    3861              :                 Struct st;
    3862            1 :                 if (current.new_symbol) {
    3863            1 :                         st = new Struct (reader.get_attribute ("name"), current.source_reference);
    3864            2 :                         current.symbol = st;
    3865              :                 } else {
    3866            0 :                         st = (Struct) current.symbol;
    3867              :                 }
    3868            1 :                 st.access = SymbolAccessibility.PUBLIC;
    3869              : 
    3870            1 :                 if (metadata.has_argument (ArgumentType.TYPE_PARAMETERS)) {
    3871            0 :                         parse_type_parameters_from_string (st, metadata.get_string (ArgumentType.TYPE_PARAMETERS), metadata.get_source_reference (ArgumentType.TYPE_PARAMETERS));
    3872              :                 }
    3873              : 
    3874            1 :                 next ();
    3875              : 
    3876            1 :                 st.comment = parse_symbol_doc ();
    3877              : 
    3878            3 :                 while (current_token == MarkupTokenType.START_ELEMENT) {
    3879            2 :                         if (!push_metadata ()) {
    3880            0 :                                 skip_element ();
    3881            0 :                                 continue;
    3882              :                         }
    3883              : 
    3884            2 :                         if (reader.name == "field") {
    3885            2 :                                 parse_field ();
    3886            0 :                         } else if (reader.name == "constructor") {
    3887            0 :                                 parse_constructor ();
    3888            0 :                         } else if (reader.name == "method") {
    3889            0 :                                 parse_method ("method");
    3890            0 :                         } else if (reader.name == "function") {
    3891            0 :                                 parse_method ("function");
    3892            0 :                         } else if (reader.name == "function-macro") {
    3893            0 :                                 skip_element ();
    3894            0 :                         } else if (reader.name == "record") {
    3895            0 :                                 parse_record ();
    3896              :                         } else {
    3897              :                                 // error
    3898            0 :                                 Report.error (get_current_src (), "unknown child element `%s' in `union'", reader.name);
    3899            0 :                                 skip_element ();
    3900              :                         }
    3901              : 
    3902            2 :                         pop_metadata ();
    3903              :                 }
    3904              : 
    3905            1 :                 pop_node ();
    3906            1 :                 end_element ("union");
    3907              :         }
    3908              : 
    3909           22 :         void parse_constant () {
    3910           11 :                 start_element ("constant");
    3911           11 :                 push_node (element_get_name (), false);
    3912              : 
    3913           11 :                 next ();
    3914              : 
    3915           11 :                 var comment = parse_symbol_doc ();
    3916              : 
    3917              :                 bool no_array_length;
    3918              :                 bool array_null_terminated;
    3919              :                 int array_length_idx;
    3920           11 :                 var type = parse_type (null, out array_length_idx, true, out no_array_length, out array_null_terminated);
    3921           11 :                 type = element_get_type (type, true, ref no_array_length, ref array_null_terminated);
    3922           11 :                 var c = new Constant (current.name, type, null, current.source_reference);
    3923           22 :                 current.symbol = c;
    3924           11 :                 c.access = SymbolAccessibility.PUBLIC;
    3925           11 :                 c.comment = comment;
    3926           11 :                 if (no_array_length || array_null_terminated) {
    3927            1 :                         c.set_attribute_bool ("CCode", "array_length", !no_array_length);
    3928              :                 }
    3929           11 :                 if (array_null_terminated) {
    3930            1 :                         c.set_attribute_bool ("CCode", "array_null_terminated", true);
    3931              :                 }
    3932              : 
    3933           11 :                 pop_node ();
    3934           11 :                 end_element ("constant");
    3935              :         }
    3936              : 
    3937              :         /* Reporting */
    3938           27 :         void report_unused_metadata (Metadata metadata) {
    3939           27 :                 if (metadata == Metadata.empty) {
    3940              :                         return;
    3941              :                 }
    3942              : 
    3943           27 :                 if (metadata.args.size == 0 && metadata.children.size == 0) {
    3944            0 :                         Report.warning (metadata.source_reference, "empty metadata");
    3945            0 :                         return;
    3946              :                 }
    3947              : 
    3948           78 :                 foreach (var arg_type in metadata.args.get_keys ()) {
    3949           24 :                         var arg = metadata.args[arg_type];
    3950           24 :                         if (!arg.used) {
    3951              :                                 // if metadata is used and argument is not, then it's a unexpected argument
    3952            0 :                                 Report.warning (arg.source_reference, "argument never used");
    3953              :                         }
    3954              :                 }
    3955              : 
    3956           53 :                 foreach (var child in metadata.children) {
    3957           26 :                         if (!child.used) {
    3958            0 :                                 Report.warning (child.source_reference, "metadata never used");
    3959              :                         } else {
    3960           26 :                                 report_unused_metadata (child);
    3961              :                         }
    3962              :                 }
    3963              :         }
    3964              : 
    3965              :         /* Post-parsing */
    3966              : 
    3967         1538 :         void resolve_gir_symbols () {
    3968              :                 // gir has simple namespaces, we won't get deeper than 2 levels here, except reparenting
    3969         2356 :                 foreach (var map_from in unresolved_gir_symbols) {
    3970         1057 :                         while (map_from != null) {
    3971          720 :                                 var map_to = unresolved_symbols_map[map_from];
    3972          720 :                                 if (map_to != null) {
    3973              :                                         // remap the original symbol to match the target
    3974           72 :                                         map_from.inner = null;
    3975           72 :                                         map_from.name = map_to.name;
    3976           72 :                                         if (map_to is UnresolvedSymbol) {
    3977            0 :                                                 var umap_to = (UnresolvedSymbol) map_to;
    3978            0 :                                                 while (umap_to.inner != null) {
    3979            0 :                                                         umap_to = umap_to.inner;
    3980            0 :                                                         map_from.inner = new UnresolvedSymbol (null, umap_to.name);
    3981            0 :                                                         map_from = map_from.inner;
    3982              :                                                 }
    3983              :                                         } else {
    3984           73 :                                                 while (map_to.parent_symbol != null && map_to.parent_symbol != context.root) {
    3985            2 :                                                         map_to = map_to.parent_symbol;
    3986            1 :                                                         map_from.inner = new UnresolvedSymbol (null, map_to.name);
    3987            2 :                                                         map_from = map_from.inner;
    3988              :                                                 }
    3989              :                                         }
    3990           72 :                                         break;
    3991              :                                 }
    3992          959 :                                 map_from = map_from.inner;
    3993              :                         }
    3994              :                 }
    3995              :         }
    3996              : 
    3997         1538 :         void create_new_namespaces () {
    3998         1539 :                 foreach (var node in Node.new_namespaces) {
    3999            1 :                         if (node.symbol == null) {
    4000            1 :                                 node.symbol = new Namespace (node.name, node.source_reference);
    4001              :                         }
    4002              :                 }
    4003              :         }
    4004              : 
    4005         3076 :         void resolve_type_arguments () {
    4006         1538 :                 var it = unresolved_type_arguments.map_iterator ();
    4007         1540 :                 while (it.next ()) {
    4008            1 :                         var element_type = it.get_key ();
    4009            1 :                         var parent = it.get_value ();
    4010            1 :                         var sym = (TypeSymbol) resolve_symbol (parent, element_type.unresolved_symbol);
    4011              : 
    4012              :                         // box structs in type arguments
    4013            1 :                         var st = sym as Struct;
    4014            1 :                         if (st != null && !st.is_integer_type () && !st.is_floating_type ()) {
    4015            0 :                                 element_type.nullable = true;
    4016              :                         }
    4017              :                 }
    4018              :         }
    4019              : 
    4020           38 :         void resolve_inherited_types (Node object_node) {
    4021           38 :                 if (object_node.inherited_types == null) {
    4022              :                         return;
    4023              :                 }
    4024              : 
    4025            0 :                 int i = 0;
    4026            0 :                 foreach (var t in object_node.inherited_types) {
    4027            0 :                         Symbol? sym = null;
    4028            0 :                         if (t is UnresolvedType) {
    4029            0 :                                 var unresolved_symbol = ((UnresolvedType) t).unresolved_symbol;
    4030            0 :                                 sym = resolve_symbol (object_node.parent, unresolved_symbol);
    4031              :                         }
    4032            0 :                         if (sym is ObjectTypeSymbol) {
    4033            0 :                                 var type = new ObjectType ((ObjectTypeSymbol) sym, t.source_reference);
    4034            0 :                                 foreach (var arg in t.get_type_arguments ()) {
    4035            0 :                                         type.add_type_argument (arg);
    4036              :                                 }
    4037            0 :                                 object_node.inherited_types[i] = type;
    4038              :                         }
    4039            0 :                         i++;
    4040              :                 }
    4041              :         }
    4042              : 
    4043           62 :         void process_class (Node class_node) {
    4044           31 :                 resolve_inherited_types (class_node);
    4045              : 
    4046           62 :                 Class cl = (Class) class_node.symbol;
    4047           81 :                 foreach (DataType base_type in cl.get_base_types ()) {
    4048           25 :                         Symbol sym = null;
    4049           50 :                         if (base_type is UnresolvedType) {
    4050           25 :                                 var unresolved_symbol = ((UnresolvedType) base_type).unresolved_symbol;
    4051           25 :                                 sym = resolve_symbol (class_node.parent, unresolved_symbol);
    4052              :                         } else {
    4053            0 :                                 sym = base_type.type_symbol;
    4054              :                         }
    4055           25 :                         if (class_node.inherited_types != null) {
    4056            0 :                                 foreach (var t in class_node.inherited_types) {
    4057            0 :                                         if (sym == t.type_symbol) {
    4058            0 :                                                 cl.replace_type (base_type, t);
    4059              :                                         }
    4060              :                                 }
    4061              :                         }
    4062              :                 }
    4063              :         }
    4064              : 
    4065           14 :         void process_interface (Node iface_node) {
    4066            7 :                 resolve_inherited_types (iface_node);
    4067              : 
    4068              :                 /* Temporarily workaround G-I bug not adding GLib.Object prerequisite:
    4069              :                    ensure we have at least one instantiable prerequisite */
    4070            7 :                 Interface iface = (Interface) iface_node.symbol;
    4071            7 :                 bool has_instantiable_prereq = false;
    4072           17 :                 foreach (DataType prereq in iface.get_prerequisites ()) {
    4073            5 :                         Symbol sym = null;
    4074           10 :                         if (prereq is UnresolvedType) {
    4075            5 :                                 var unresolved_symbol = ((UnresolvedType) prereq).unresolved_symbol;
    4076            5 :                                 sym = resolve_symbol (iface_node.parent, unresolved_symbol);
    4077              :                         } else {
    4078            0 :                                 sym = prereq.type_symbol;
    4079              :                         }
    4080            5 :                         if (iface_node.inherited_types != null) {
    4081            0 :                                 foreach (var t in iface_node.inherited_types) {
    4082            0 :                                         if (sym == t.type_symbol) {
    4083            0 :                                                 iface.replace_type (prereq, t);
    4084              :                                         }
    4085              :                                 }
    4086              :                         }
    4087            5 :                         if (sym is Class) {
    4088            5 :                                 has_instantiable_prereq = true;
    4089              :                         }
    4090              :                 }
    4091              : 
    4092            7 :                 if (!has_instantiable_prereq) {
    4093            4 :                         ifaces_needing_object_prereq.add (iface);
    4094              :                 }
    4095              :         }
    4096              : 
    4097           10 :         void process_alias (Node alias) {
    4098              :                 /* this is unfortunate because <alias> tag has no type information, thus we have
    4099              :                    to guess it from the base type */
    4100            5 :                 DataType base_type = null;
    4101            5 :                 Symbol type_sym = null;
    4102            5 :                 Node base_node = null;
    4103            5 :                 bool simple_type = false;
    4104            5 :                 if (alias.base_type is UnresolvedType) {
    4105            5 :                         base_type = alias.base_type;
    4106            5 :                         base_node = resolve_node (alias.parent, ((UnresolvedType) base_type).unresolved_symbol);
    4107            5 :                         if (base_node != null) {
    4108            5 :                                 type_sym = base_node.symbol;
    4109              :                         }
    4110            0 :                 } else if (alias.base_type is PointerType && ((PointerType) alias.base_type).base_type is VoidType) {
    4111              :                         // gpointer, if it's a struct make it a simpletype
    4112              :                         simple_type = true;
    4113              :                 } else {
    4114            0 :                         base_type = alias.base_type;
    4115            0 :                         type_sym = base_type.type_symbol;
    4116            0 :                         if (type_sym != null) {
    4117            0 :                                 base_node = resolve_node (alias.parent, parse_symbol_from_string (type_sym.get_full_name (), alias.source_reference));
    4118              :                         }
    4119              :                 }
    4120              : 
    4121            5 :                 if (type_sym is Struct && ((Struct) type_sym).is_simple_type ()) {
    4122            5 :                         simple_type = true;
    4123              :                 }
    4124              : 
    4125            6 :                 if (base_type == null || type_sym == null || type_sym is Struct) {
    4126            1 :                         var st = new Struct (alias.name, alias.source_reference);
    4127            1 :                         st.access = SymbolAccessibility.PUBLIC;
    4128            1 :                         if (base_type != null) {
    4129              :                                 // threat target="none" as a new struct
    4130            1 :                                 st.base_type = base_type;
    4131              :                         }
    4132            1 :                         st.comment = alias.comment;
    4133            1 :                         st.set_simple_type (simple_type);
    4134            2 :                         alias.symbol = st;
    4135            5 :                 } else if (type_sym is Class) {
    4136            1 :                         var cl = new Class (alias.name, alias.source_reference);
    4137            1 :                         cl.access = SymbolAccessibility.PUBLIC;
    4138            1 :                         if (base_type != null) {
    4139            1 :                                 cl.add_base_type (base_type);
    4140              :                         }
    4141            1 :                         cl.comment = alias.comment;
    4142            1 :                         cl.set_attribute ("Compact", ((Class) type_sym).is_compact);
    4143            2 :                         alias.symbol = cl;
    4144            4 :                 } else if (type_sym is Interface) {
    4145              :                         // this is not a correct alias, but what can we do otherwise?
    4146            1 :                         var iface = new Interface (alias.name, alias.source_reference);
    4147            1 :                         iface.access = SymbolAccessibility.PUBLIC;
    4148            1 :                         if (base_type != null) {
    4149            1 :                                 iface.add_prerequisite (base_type);
    4150              :                         }
    4151            1 :                         iface.comment = alias.comment;
    4152            2 :                         alias.symbol = iface;
    4153            4 :                 } else if (type_sym is Delegate) {
    4154            2 :                         var orig = (Delegate) type_sym;
    4155            2 :                         if (base_node != null) {
    4156            2 :                                 base_node.process (this);
    4157            4 :                                 orig = (Delegate) base_node.symbol;
    4158              :                         }
    4159              : 
    4160            2 :                         var deleg = new Delegate (alias.name, orig.return_type.copy (), alias.source_reference);
    4161            2 :                         deleg.access = orig.access;
    4162              : 
    4163            4 :                         foreach (var param in orig.get_parameters ()) {
    4164            1 :                                 deleg.add_parameter (param.copy ());
    4165              :                         }
    4166              : 
    4167            2 :                         var error_types = new ArrayList<DataType> ();
    4168            2 :                         orig.get_error_types (error_types, alias.source_reference);
    4169            2 :                         foreach (var error_type in error_types) {
    4170            0 :                                 deleg.add_error_type (error_type.copy ());
    4171              :                         }
    4172              : 
    4173            4 :                         foreach (var attribute in orig.attributes) {
    4174            2 :                                 deleg.add_attribute (attribute);
    4175              :                         }
    4176              : 
    4177            4 :                         alias.symbol = deleg;
    4178            0 :                 } else if (type_sym != null) {
    4179            0 :                         Report.warning (alias.source_reference, "alias `%s' for `%s' is not supported", alias.get_full_name (), type_sym.get_full_name ());
    4180            0 :                         alias.symbol = type_sym;
    4181            0 :                         alias.merged = true;
    4182              :                 }
    4183              : 
    4184              :                 // inherit attributes, like type_id
    4185            5 :                 if (type_sym is Class || (type_sym is Struct && !simple_type)) {
    4186            1 :                         if (type_sym.has_attribute_argument ("CCode", "has_type_id")) {
    4187            0 :                                 alias.symbol.set_attribute_bool ("CCode", "has_type_id", type_sym.get_attribute_bool ("CCode", "has_type_id"));
    4188            1 :                         } else if (type_sym.has_attribute_argument ("CCode", "type_id")) {
    4189            1 :                                 alias.symbol.set_attribute_string ("CCode", "type_id", type_sym.get_attribute_string ("CCode", "type_id"));
    4190              :                         }
    4191              :                 }
    4192              :         }
    4193              : 
    4194          482 :         void process_callable (Node node) {
    4195          242 :                 if (node.element_type == "alias" && node.symbol is Delegate) {
    4196              :                         // processed in parse_alias
    4197              :                         return;
    4198              :                 }
    4199              : 
    4200          240 :                 var s = node.symbol;
    4201          240 :                 List<ParameterInfo> parameters = node.parameters;
    4202              : 
    4203          240 :                 DataType return_type = null;
    4204          240 :                 if (s is Callable) {
    4205          240 :                         return_type = ((Callable) s).return_type;
    4206              :                 }
    4207              : 
    4208          240 :                 if (return_type is ArrayType && node.return_array_length_idx >= 0) {
    4209           11 :                         if (node.return_array_length_idx >= parameters.size) {
    4210            0 :                                 Report.error (return_type.source_reference, "invalid array length index");
    4211              :                         } else {
    4212           11 :                                 parameters[node.return_array_length_idx].keep = false;
    4213           11 :                                 node.array_length_parameters.add (node.return_array_length_idx);
    4214              :                         }
    4215          229 :                 } else if (return_type is VoidType && parameters.size > 0) {
    4216          135 :                         int n_out_parameters = 0;
    4217          414 :                         foreach (var info in parameters) {
    4218          279 :                                 if (info.param.direction == ParameterDirection.OUT) {
    4219           26 :                                         n_out_parameters++;
    4220              :                                 }
    4221              :                         }
    4222              : 
    4223          153 :                         if (n_out_parameters == 1) {
    4224           18 :                                 ParameterInfo last_param = parameters[parameters.size-1];
    4225           18 :                                 if (last_param.param.direction == ParameterDirection.OUT) {
    4226              :                                         // use last out real-non-null-struct parameter as return type
    4227           25 :                                         if (last_param.param.variable_type is UnresolvedType) {
    4228           14 :                                                 var st = resolve_symbol (node.parent, ((UnresolvedType) last_param.param.variable_type).unresolved_symbol) as Struct;
    4229           16 :                                                 if (st != null && !st.is_simple_type () && !last_param.param.variable_type.nullable) {
    4230            2 :                                                         if (!node.metadata.get_bool (ArgumentType.RETURN_VOID, false)) {
    4231            2 :                                                                 last_param.keep = false;
    4232            2 :                                                                 return_type = last_param.param.variable_type.copy ();
    4233              :                                                         }
    4234              :                                                 }
    4235              :                                         }
    4236              :                                 }
    4237              :                         }
    4238              :                 } else {
    4239          114 :                         if (return_type is UnresolvedType && !return_type.nullable) {
    4240           39 :                                 var st = resolve_symbol (node.parent, ((UnresolvedType) return_type).unresolved_symbol) as Struct;
    4241           40 :                                 if (st != null) {
    4242           20 :                                         bool is_simple_type = false;
    4243           20 :                                         Struct? base_st = st;
    4244              : 
    4245           21 :                                         while (base_st != null) {
    4246           20 :                                                 if (base_st.is_simple_type ()) {
    4247              :                                                         is_simple_type = true;
    4248              :                                                         break;
    4249              :                                                 }
    4250              : 
    4251            1 :                                                 if (base_st.base_type is UnresolvedType) {
    4252            0 :                                                         base_st = resolve_symbol (node.parent, ((UnresolvedType) base_st.base_type).unresolved_symbol) as Struct;
    4253              :                                                 } else {
    4254            1 :                                                         base_st = base_st.base_struct;
    4255              :                                                 }
    4256              :                                         }
    4257              : 
    4258           20 :                                         if (!is_simple_type) {
    4259            1 :                                                 return_type.nullable = true;
    4260              :                                         }
    4261              :                                 }
    4262              :                         }
    4263              :                 }
    4264              : 
    4265          240 :                 bool first_param = true;
    4266          590 :                 foreach (ParameterInfo info in parameters) {
    4267          350 :                         unowned DataType type = info.param.variable_type;
    4268              : 
    4269              :                         // Do not mark out-parameters as nullable if they are simple-types,
    4270              :                         // since it would result in a boxed-type in vala
    4271          351 :                         if (info.param.direction == ParameterDirection.OUT && type.nullable) {
    4272            5 :                                 Struct? st = null;
    4273            5 :                                 if (type is UnresolvedType) {
    4274            1 :                                         st = resolve_symbol (node.parent, ((UnresolvedType) type).unresolved_symbol) as Struct;
    4275            4 :                                 } else if (type is ValueType) {
    4276            0 :                                         st = type.type_symbol as Struct;
    4277              :                                 }
    4278            6 :                                 if (st != null && st.is_simple_type ()) {
    4279            1 :                                         type.nullable = false;
    4280              :                                 }
    4281              :                         }
    4282              : 
    4283              :                         // Check and mark GAsync-style methods
    4284          596 :                         if (s is Method) {
    4285          246 :                                 string? type_name = null;
    4286          246 :                                 unowned UnresolvedType? unresolved_type = type as UnresolvedType;
    4287          246 :                                 if (unresolved_type != null) {
    4288          388 :                                         type_name = unresolved_type.unresolved_symbol.name;
    4289           52 :                                 } else if (type != null) {
    4290           50 :                                         type_name = type.to_string ();
    4291              :                                 }
    4292          246 :                                 if (info.is_async) {
    4293           14 :                                         if ((unresolved_type != null && type_name == "AsyncReadyCallback")
    4294            0 :                                             || type_name == "GLib.AsyncReadyCallback" || type_name == "Gio.AsyncReadyCallback"
    4295            0 :                                             || type_name == "GLib.AsyncReadyCallback?" || type_name == "Gio.AsyncReadyCallback?") {
    4296           14 :                                                 ((Method) s).coroutine = true;
    4297           14 :                                                 info.keep = false;
    4298              :                                         }
    4299              :                                 }
    4300          246 :                                 if ((unresolved_type != null && type_name == "AsyncResult")
    4301          232 :                                     || type_name == "GLib.AsyncResult" || type_name == "Gio.AsyncResult"
    4302          232 :                                     || type_name == "GLib.AsyncResult?" || type_name == "Gio.AsyncResult?") {
    4303           14 :                                         info.is_async_result = true;
    4304              :                                 }
    4305              :                         }
    4306              : 
    4307              :                         // More thorough check for delegates throwing an error
    4308          350 :                         if (info.param.direction == ParameterDirection.OUT && s is Delegate && !s.tree_can_fail) {
    4309            3 :                                 unowned UnresolvedType? unresolved_type = type as UnresolvedType;
    4310            3 :                                 if (unresolved_type != null && unresolved_type.unresolved_symbol.to_string () == "GLib.Error") {
    4311            1 :                                         ((Delegate) s).add_error_type (new ErrorType (null, null));
    4312            1 :                                         info.is_error = true;
    4313            1 :                                         info.keep = false;
    4314              :                                 }
    4315              :                         }
    4316              : 
    4317              :                         // Try to transform static function to instance method
    4318          385 :                         if (first_param && info.keep && type != null && s is Method && ((Method) s).binding == MemberBinding.STATIC) {
    4319              :                                 Symbol? sym;
    4320           35 :                                 if (type is UnresolvedType) {
    4321           31 :                                         sym = resolve_symbol (node.parent, ((UnresolvedType) type).unresolved_symbol);
    4322              :                                 } else {
    4323            4 :                                         sym = type.type_symbol;
    4324              :                                 }
    4325           35 :                                 if (sym == node.parent.symbol && !type.nullable
    4326            4 :                                     && ((sym is TypeSymbol && info.param.direction == ParameterDirection.IN)
    4327            4 :                                     || (info.caller_allocates && info.param.direction == ParameterDirection.OUT
    4328            0 :                                         && (sym is Struct || (sym is Class && ((Class) sym).is_compact))))) {
    4329            0 :                                         ((Method) s).binding = MemberBinding.INSTANCE;
    4330            0 :                                         info.keep = false;
    4331              :                                 }
    4332              :                         }
    4333              : 
    4334          350 :                         first_param = false;
    4335              :                 }
    4336              : 
    4337              :                 // Add null-literal as default-value for trailing GLib.Cancellable parameters
    4338          242 :                 for (int param_n = parameters.size - 1 ; param_n >= 0 ; param_n--) {
    4339          178 :                         ParameterInfo info = parameters[param_n];
    4340          178 :                         if (!info.param.ellipsis && info.param.initializer == null) {
    4341          176 :                                 string type_string = info.param.variable_type.to_string ();
    4342          176 :                                 if (type_string == "GLib.Cancellable?" || type_string == "Gio.Cancellable?") {
    4343            0 :                                         info.param.initializer = new Vala.NullLiteral ();
    4344              :                                 } else {
    4345          176 :                                         break;
    4346              :                                 }
    4347              :                         }
    4348              :                 }
    4349              : 
    4350          324 :                 if (parameters.size > 1) {
    4351           84 :                         ParameterInfo last_param = parameters[parameters.size-1];
    4352           86 :                         if (last_param.param.ellipsis) {
    4353            2 :                                 var first_vararg_param = parameters[parameters.size-2];
    4354            2 :                                 if (first_vararg_param.param.name.has_prefix ("first_")) {
    4355            0 :                                         first_vararg_param.keep = false;
    4356              :                                 }
    4357              :                         }
    4358              :                 }
    4359              : 
    4360          240 :                 int i = 0, j=1;
    4361              : 
    4362          240 :                 int first_out = -1;
    4363          240 :                 int last = -1;
    4364          940 :                 foreach (ParameterInfo info in parameters) {
    4365          355 :                         if (s is Delegate && info.closure_idx == i) {
    4366            5 :                                 var d = (Delegate) s;
    4367            5 :                                 d.has_target = true;
    4368            5 :                                 d.set_attribute_double ("CCode", "instance_pos", j - 0.1);
    4369            5 :                                 info.keep = false;
    4370          345 :                         } else if (info.keep
    4371          317 :                                            && !node.array_length_parameters.contains (i)
    4372          297 :                                            && !node.closure_parameters.contains (i)
    4373          261 :                                            && !node.destroy_parameters.contains (i)) {
    4374          247 :                                 info.vala_idx = (float) j;
    4375          247 :                                 info.keep = true;
    4376              : 
    4377              :                                 /* interpolate for vala_idx between this and last*/
    4378          247 :                                 float last_idx = 0.0F;
    4379          247 :                                 if (last != -1) {
    4380           88 :                                         last_idx = parameters[last].vala_idx;
    4381              :                                 }
    4382          260 :                                 for (int k=last+1; k < i; k++) {
    4383           13 :                                         parameters[k].vala_idx =  last_idx + (((j - last_idx) / (i-last)) * (k-last));
    4384              :                                 }
    4385          247 :                                 last = i;
    4386          247 :                                 j++;
    4387              :                         } else {
    4388           98 :                                 info.keep = false;
    4389              :                                 // make sure that vala_idx is always set
    4390              :                                 // the above if branch does not set vala_idx for
    4391              :                                 // hidden parameters at the end of the parameter list
    4392           98 :                                 info.vala_idx = (j - 1) + (i - last) * 0.1F;
    4393              :                         }
    4394          350 :                         if (first_out < 0 && info.param.direction == ParameterDirection.OUT) {
    4395          350 :                                 first_out = i;
    4396              :                         }
    4397          350 :                         if (first_out >= 0 && info.is_async_result && s is Method) {
    4398            1 :                                 var shift = ((Method) s).binding == MemberBinding.INSTANCE ? 1.1 : 0.1;
    4399            1 :                                 s.set_attribute_double ("CCode", "async_result_pos", i + shift);
    4400              :                         }
    4401          350 :                         if (s is Delegate && info.is_error) {
    4402            1 :                                 if (!s.has_attribute_argument ("CCode", "instance_pos")) {
    4403            1 :                                         s.set_attribute_double ("CCode", "error_pos", j - 0.2);
    4404              :                                 }
    4405              :                         }
    4406          350 :                         i++;
    4407              :                 }
    4408              : 
    4409          837 :                 foreach (ParameterInfo info in parameters) {
    4410          350 :                         if (!info.keep) {
    4411          103 :                                 continue;
    4412              :                         }
    4413              : 
    4414              :                         /* add_parameter sets carray_length_parameter_position and cdelegate_target_parameter_position
    4415              :                            so do it first*/
    4416          247 :                         if (s is Callable) {
    4417          247 :                                 ((Callable) s).add_parameter (info.param);
    4418              :                         }
    4419              : 
    4420          247 :                         if (info.array_length_idx != -1) {
    4421           20 :                                 if ((info.array_length_idx) >= parameters.size) {
    4422            0 :                                         Report.error (info.param.source_reference, "invalid array_length index");
    4423            0 :                                         continue;
    4424              :                                 }
    4425           20 :                                 set_array_ccode (info.param, parameters[info.array_length_idx]);
    4426              :                         }
    4427              : 
    4428          247 :                         if (info.closure_idx != -1) {
    4429           22 :                                 if ((info.closure_idx) >= parameters.size) {
    4430            0 :                                         Report.error (info.param.source_reference, "invalid closure index");
    4431            0 :                                         continue;
    4432              :                                 }
    4433           22 :                                 if ("%g".printf (parameters[info.closure_idx].vala_idx) != "%g".printf (info.vala_idx + 0.1)) {
    4434            1 :                                         info.param.set_attribute_double ("CCode", "delegate_target_pos", parameters[info.closure_idx].vala_idx);
    4435              :                                 }
    4436              :                         }
    4437          247 :                         if (info.destroy_idx != -1) {
    4438           14 :                                 if (info.destroy_idx >= parameters.size) {
    4439            0 :                                         Report.error (info.param.source_reference, "invalid destroy index");
    4440            0 :                                         continue;
    4441              :                                 }
    4442           14 :                                 if ("%g".printf (parameters[info.destroy_idx].vala_idx) != "%g".printf (info.vala_idx + 0.2)) {
    4443            0 :                                         info.param.set_attribute_double ("CCode", "destroy_notify_pos", parameters[info.destroy_idx].vala_idx);
    4444              :                                 }
    4445              :                         }
    4446              : 
    4447          494 :                         if (info.is_async) {
    4448            6 :                                 var resolved_type = info.param.variable_type;
    4449           12 :                                 if (resolved_type is UnresolvedType) {
    4450            6 :                                         var resolved_symbol = resolve_symbol (node.parent, ((UnresolvedType) resolved_type).unresolved_symbol);
    4451            6 :                                         if (resolved_symbol is Delegate) {
    4452            6 :                                                 resolved_type = new DelegateType ((Delegate) resolved_symbol);
    4453              :                                         }
    4454              :                                 }
    4455              : 
    4456           12 :                                 if (resolved_type is DelegateType) {
    4457            6 :                                         var d = ((DelegateType) resolved_type).delegate_symbol;
    4458            6 :                                         if (!(d.name == "DestroyNotify" && d.parent_symbol.name == "GLib")) {
    4459            6 :                                                 info.param.set_attribute_string ("CCode", "scope", "async");
    4460            6 :                                                 info.param.variable_type.value_owned = (info.closure_idx != -1 && info.destroy_idx != -1);
    4461              :                                         }
    4462              :                                 }
    4463              :                         } else {
    4464          241 :                                 var resolved_type = info.param.variable_type;
    4465          241 :                                 if (resolved_type is DelegateType) {
    4466            0 :                                         info.param.variable_type.value_owned = (info.closure_idx != -1 && info.destroy_idx != -1);
    4467              :                                 }
    4468              :                         }
    4469              :                 }
    4470              : 
    4471          240 :                 if (return_type is ArrayType && node.return_array_length_idx >= 0) {
    4472           11 :                         set_array_ccode (s, parameters[node.return_array_length_idx]);
    4473              :                 }
    4474              : 
    4475          240 :                 if (s is Callable) {
    4476          240 :                         ((Callable) s).return_type = return_type;
    4477              :                 }
    4478              :         }
    4479              : 
    4480           72 :         void find_parent (string cname, Node current, ref Node best, ref int match) {
    4481           36 :                 var old_best = best;
    4482           36 :                 if (current.symbol is Namespace) {
    4483          598 :                         foreach (var child in current.members) {
    4484              :                                 // symbol is null only for aliases that aren't yet processed
    4485          562 :                                 if ((child.symbol == null || is_container (child.symbol)) && cname.has_prefix (child.get_lower_case_cprefix ())) {
    4486            0 :                                         find_parent (cname, child, ref best, ref match);
    4487              :                                 }
    4488              :                         }
    4489              :                 }
    4490           36 :                 if (best != old_best) {
    4491              :                         // child is better
    4492            0 :                         return;
    4493              :                 }
    4494              : 
    4495           36 :                 var current_match = current.get_lower_case_cprefix().length;
    4496           36 :                 if (current_match > match) {
    4497           36 :                         match = current_match;
    4498           36 :                         best = current;
    4499              :                 }
    4500              :         }
    4501              : 
    4502           60 :         bool same_gir (Symbol gir_component, Symbol sym) {
    4503           60 :                 var gir_name = gir_component.source_reference.file.gir_namespace;
    4504           60 :                 var gir_version = gir_component.source_reference.file.gir_version;
    4505           60 :                 return "%s-%s".printf (gir_name, gir_version) in sym.source_reference.file.filename;
    4506              :         }
    4507              : 
    4508           72 :         void process_namespace_method (Node ns, Node node) {
    4509              :                 /* transform static methods into instance methods if possible.
    4510              :                    In most of cases this is a .gir fault we are going to fix */
    4511              : 
    4512           36 :                 var ns_cprefix = ns.get_lower_case_cprefix ();
    4513           36 :                 var method = (Method) node.symbol;
    4514           36 :                 var cname = node.get_cname ();
    4515              : 
    4516           36 :                 Parameter first_param = null;
    4517           36 :                 if (node.parameters.size > 0) {
    4518           33 :                         first_param = node.parameters[0].param;
    4519              :                 }
    4520           57 :                 if (first_param != null && first_param.direction == ParameterDirection.IN && first_param.variable_type is UnresolvedType) {
    4521              :                         // check if it's a missed instance method (often happens for structs)
    4522           24 :                         var sym = ((UnresolvedType) first_param.variable_type).unresolved_symbol;
    4523           24 :                         var parent = resolve_node (ns, sym);
    4524           24 :                         if (parent != null && same_gir (method, parent.symbol) && parent.parent == ns && is_container (parent.symbol) && cname.has_prefix (parent.get_lower_case_cprefix ())) {
    4525              :                                 // instance method
    4526            0 :                                 var new_name = method.name.substring (parent.get_lower_case_cprefix().length - ns_cprefix.length);
    4527            0 :                                 if (parent.lookup (new_name) == null) {
    4528            0 :                                         ns.remove_member (node);
    4529            0 :                                         node.name = new_name;
    4530            0 :                                         node.parameters.remove_at (0);
    4531            0 :                                         node.return_array_length_idx--;
    4532            0 :                                         method.name = new_name;
    4533            0 :                                         method.binding = MemberBinding.INSTANCE;
    4534            0 :                                         parent.add_member (node);
    4535              :                                 }
    4536            0 :                                 return;
    4537              :                         }
    4538              :                 }
    4539              : 
    4540           36 :                 int match = 0;
    4541           36 :                 Node parent = ns;
    4542           36 :                 find_parent (cname, ns, ref parent, ref match);
    4543           36 :                 var new_name = method.name.substring (parent.get_lower_case_cprefix().length - ns_cprefix.length);
    4544           36 :                 if (same_gir (method, parent.symbol) && parent.lookup (new_name) == null) {
    4545            0 :                         ns.remove_member (node);
    4546            0 :                         node.name = new_name;
    4547            0 :                         method.name = new_name;
    4548            0 :                         parent.add_member (node);
    4549              :                 }
    4550              :         }
    4551              : 
    4552           65 :         void process_virtual_method_field (Node node, Delegate d, UnresolvedSymbol gtype_struct_for) {
    4553           34 :                 var gtype_node = resolve_node (node.parent, gtype_struct_for);
    4554           34 :                 if (gtype_node == null || !(gtype_node.symbol is ObjectTypeSymbol)) {
    4555            0 :                         Report.error (gtype_struct_for.source_reference, "Unknown symbol `%s' for virtual method field `%s'", gtype_struct_for.to_string (), node.to_string ());
    4556              :                 }
    4557           34 :                 var nodes = gtype_node.lookup_all (d.name);
    4558           34 :                 if (nodes == null) {
    4559            3 :                         return;
    4560              :                 }
    4561          135 :                 foreach (var n in nodes) {
    4562           52 :                         if (node != n) {
    4563           52 :                                 n.process (this);
    4564              :                         }
    4565              :                 }
    4566          111 :                 foreach (var n in nodes) {
    4567           52 :                         if (n.merged) {
    4568           24 :                                 continue;
    4569              :                         }
    4570           28 :                         var sym = n.symbol;
    4571           28 :                         if (sym is Signal) {
    4572            0 :                                 var sig = (Signal) sym;
    4573            0 :                                 sig.is_virtual = true;
    4574            0 :                                 assume_parameter_names (sig, d, true);
    4575           28 :                         } else if (sym is Property) {
    4576            0 :                                 var prop = (Property) sym;
    4577            0 :                                 prop.is_virtual = true;
    4578              :                         }
    4579              :                 }
    4580              :         }
    4581              : 
    4582           28 :         void process_async_method (Node node) {
    4583           14 :                 var m = (Method) node.symbol;
    4584              : 
    4585              :                 // TODO: async methods with out-parameters before in-parameters are not supported
    4586           14 :                 bool requires_pointer = false;
    4587           28 :                 foreach (var param in m.get_parameters ()) {
    4588            7 :                         if (param.direction == ParameterDirection.IN) {
    4589              :                                 requires_pointer = true;
    4590            1 :                         } else if (requires_pointer) {
    4591            1 :                                 param.direction = ParameterDirection.IN;
    4592            1 :                                 param.variable_type.nullable = false;
    4593            1 :                                 param.variable_type = new PointerType (param.variable_type);
    4594            1 :                                 Report.warning (param.source_reference, "Synchronous out-parameters are not supported in async methods");
    4595              :                         }
    4596              :                 }
    4597              : 
    4598              :                 string finish_method_base;
    4599           14 :                 if (m.name == null) {
    4600            0 :                         assert (m is CreationMethod);
    4601            0 :                         finish_method_base = "new";
    4602           14 :                 } else if (m.name.has_suffix ("_async")) {
    4603           12 :                         finish_method_base = m.name.substring (0, m.name.length - "_async".length);
    4604              :                 } else {
    4605            4 :                         finish_method_base = m.name;
    4606              :                 }
    4607           14 :                 var finish_method_node = node.parent.lookup (finish_method_base + "_finish");
    4608              : 
    4609              :                 // check if the method is using non-standard finish method name
    4610           14 :                 if (finish_method_node == null) {
    4611            0 :                         var method_cname = node.get_finish_cname ();
    4612            0 :                         foreach (var n in node.parent.members) {
    4613            0 :                                 if (n.symbol is Method && n.get_cname () == method_cname) {
    4614            0 :                                         finish_method_node = n;
    4615            0 :                                         break;
    4616              :                                 }
    4617              :                         }
    4618              :                 }
    4619              : 
    4620           14 :                 Method method = m;
    4621              : 
    4622           28 :                 if (finish_method_node != null && finish_method_node.symbol is Method) {
    4623           14 :                         finish_method_node.process (this);
    4624           14 :                         var finish_method = (Method) finish_method_node.symbol;
    4625           27 :                         if (finish_method is CreationMethod) {
    4626            1 :                                 method = new CreationMethod (((CreationMethod) finish_method).class_name, null, m.source_reference);
    4627            1 :                                 method.access = m.access;
    4628            1 :                                 method.coroutine = true;
    4629            1 :                                 method.has_construct_function = finish_method.has_construct_function;
    4630              : 
    4631              :                                 // cannot use List.copy()
    4632              :                                 // as it returns a list of unowned elements
    4633            1 :                                 foreach (Attribute a in m.attributes) {
    4634            0 :                                         method.add_attribute (a);
    4635              :                                 }
    4636              : 
    4637            1 :                                 method.set_attribute_string ("CCode", "cname", node.get_cname ());
    4638            1 :                                 if (finish_method_base == "new") {
    4639            1 :                                         method.name = null;
    4640            0 :                                 } else if (finish_method_base.has_prefix ("new_")) {
    4641            0 :                                         method.name = m.name.substring ("new_".length);
    4642              :                                 }
    4643            3 :                                 foreach (var param in m.get_parameters ()) {
    4644            1 :                                         method.add_parameter (param);
    4645              :                                 }
    4646            2 :                                 node.symbol = method;
    4647              :                         } else {
    4648           13 :                                 method.return_type = finish_method.return_type.copy ();
    4649           13 :                                 var a = finish_method.get_attribute ("CCode");
    4650            1 :                                 if (a != null && a.has_argument ("array_length")) {
    4651            0 :                                         method.set_attribute_bool ("CCode", "array_length", a.get_bool ("array_length"));
    4652              :                                 }
    4653           13 :                                 if (a != null && a.has_argument ("array_null_terminated")) {
    4654            0 :                                         method.set_attribute_bool ("CCode", "array_null_terminated", a.get_bool ("array_null_terminated"));
    4655              :                                 }
    4656              :                         }
    4657              : 
    4658           14 :                         method.copy_attribute_double (finish_method, "CCode", "async_result_pos");
    4659              : 
    4660           52 :                         foreach (var param in finish_method.get_parameters ()) {
    4661           24 :                                 if (param.direction == ParameterDirection.OUT) {
    4662            5 :                                         var async_param = param.copy ();
    4663            5 :                                         if (method.scope.lookup (param.name) != null) {
    4664              :                                                 // parameter name conflict
    4665            0 :                                                 async_param.name += "_out";
    4666              :                                         }
    4667            5 :                                         method.add_parameter (async_param);
    4668              :                                 }
    4669              :                         }
    4670              : 
    4671           14 :                         var error_types = new ArrayList<DataType> ();
    4672           14 :                         finish_method.get_error_types (error_types, method.source_reference);
    4673           26 :                         foreach (DataType error_type in error_types) {
    4674            6 :                                 method.add_error_type (error_type);
    4675              :                         }
    4676           14 :                         finish_method_node.processed = true;
    4677           14 :                         finish_method_node.merged = true;
    4678              :                 }
    4679              :         }
    4680              : 
    4681              :         /* Hash and equal functions */
    4682              : 
    4683              :         static uint unresolved_symbol_hash (UnresolvedSymbol? sym) {
    4684       107509 :                 var builder = new StringBuilder ();
    4685       315625 :                 while (sym != null) {
    4686       208116 :                         builder.append (sym.name);
    4687       208116 :                         sym = sym.inner;
    4688              :                 }
    4689       107509 :                 return builder.str.hash ();
    4690              :         }
    4691              : 
    4692              :         static bool unresolved_symbol_equal (UnresolvedSymbol? sym1, UnresolvedSymbol? sym2) {
    4693        46091 :                 while (sym1 != sym2) {
    4694        23046 :                         if (sym1 == null || sym2 == null) {
    4695              :                                 return false;
    4696              :                         }
    4697        23046 :                         if (sym1.name != sym2.name) {
    4698              :                                 return false;
    4699              :                         }
    4700        23046 :                         sym1 = sym1.inner;
    4701        23046 :                         sym2 = sym2.inner;
    4702              :                 }
    4703              :                 return true;
    4704              :         }
    4705              : 
    4706              :         /* Helper methods */
    4707              : 
    4708           11 :         Node? base_interface_property (Node prop_node) {
    4709           11 :                 var cl = prop_node.parent.symbol as Class;
    4710           11 :                 if (cl == null) {
    4711            0 :                         return null;
    4712              :                 }
    4713              : 
    4714           33 :                 foreach (DataType type in cl.get_base_types ()) {
    4715           12 :                         if (!(type is UnresolvedType)) {
    4716            0 :                                 continue;
    4717              :                         }
    4718              : 
    4719           12 :                         var base_node = resolve_node (prop_node.parent, ((UnresolvedType) type).unresolved_symbol);
    4720           12 :                         if (base_node != null && base_node.symbol is Interface) {
    4721            1 :                                 var base_prop_node = base_node.lookup (prop_node.name);
    4722            1 :                                 if (base_prop_node != null && base_prop_node.symbol is Property) {
    4723            1 :                                         var base_property = (Property) base_prop_node.symbol;
    4724            1 :                                         if (base_property.is_abstract || base_property.is_virtual) {
    4725              :                                                 // found
    4726            1 :                                                 return base_prop_node;
    4727              :                                         }
    4728              :                                 }
    4729              :                         }
    4730              :                 }
    4731              : 
    4732           10 :                 return null;
    4733              :         }
    4734              : 
    4735              : }
        

Generated by: LCOV version 2.0-1