]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
girparser: Refactoring, create GIR nodes to improve the tree analysis
authorLuca Bruno <lucabru@src.gnome.org>
Sun, 24 Apr 2011 12:57:48 +0000 (14:57 +0200)
committerLuca Bruno <lucabru@src.gnome.org>
Tue, 26 Apr 2011 20:03:29 +0000 (22:03 +0200)
vala/valagirparser.vala

index b7168ff47ebe7915fc3dde7007a38649368ab1c8..3864d2b01ea595695cfc61a32e466be929da8a7b 100644 (file)
 using GLib;
 
 /**
- * Code visitor parsing all Vala source files.
+ * Code visitor parsing all GIR source files.
  *
  * Pipeline:
  * 1) Parse metadata
- * 2) Parse GIR with metadata, track unresolved GIR symbols, create symbol mappings
+ * 2) Parse GIR with metadata, track unresolved GIR symbols, create Vala symbols
  * 3) Reconciliate the tree by mapping tracked symbols
- * 4) Reparent nodes
- * 5) Process callbacks/virtual
- * 6) Process aliases
- * 7) Autoreparent static methods
- * 8) Process callables
- *
- * Best hacking practices:
- * - Keep GIR parsing bloat-free, it must contain the logic
- * - Prefer being clean / short over performance
- * - Try to make things common as much as possible
- * - Prefer replace/merge after parse rather than a bunch of if-then-else and hardcoding
- * - Prefer postprocessing over hardcoding the parser
+ * 4) Process the tree
  */
 public class Vala.GirParser : CodeVisitor {
+       /*
+        * Metadata parser
+        */
+
        enum ArgumentType {
                SKIP,
                HIDDEN,
@@ -469,19 +462,327 @@ public class Vala.GirParser : CodeVisitor {
                }
        }
 
-       class SymbolInfo {
-               public Symbol symbol;
-               public Metadata metadata;
-               // additional information from GIR
-               public Map<string,string> girdata;
-       }
+       /*
+        * GIR parser
+        */
 
-       class Alias {
+       class Node {
+               public static ArrayList<Node> new_namespaces = new ArrayList<Node> ();
+
+               public weak Node parent;
+               public string element_type;
                public string name;
-               public string cname;
+               public Map<string,string> girdata = null;
+               public Metadata metadata = Metadata.empty;
+               public SourceReference source_reference = null;
+               public ArrayList<Node> members = new ArrayList<Node> (); // guarantees fields order
+               public HashMap<string, ArrayList<Node>> scope = new HashMap<string, ArrayList<Node>> (str_hash, str_equal);
+
+               public Symbol symbol;
+               public bool new_symbol;
+               public bool merged;
+               public bool processed;
+
+               // function-specific
+               public List<ParameterInfo> parameters;
+               public ArrayList<int> array_length_parameters;
+               public ArrayList<int> closure_parameters;
+               public ArrayList<int> destroy_parameters;
+               // alias-specific
                public DataType base_type;
-               public Symbol parent_symbol;
-               public SourceReference source_reference;
+
+               public Node (string? name) {
+                       this.name = name;
+               }
+
+               public void add_member (Node node) {
+                       var nodes = scope[node.name];
+                       if (nodes == null) {
+                               nodes = new ArrayList<Node> ();
+                               scope[node.name] = nodes;
+                       }
+                       nodes.add (node);
+                       members.add (node);
+                       node.parent = this;
+               }
+
+               public Node? lookup (string name, bool create_namespace = false, SourceReference? source_reference = null) {
+                       var nodes = scope[name];
+                       Node node = null;
+                       if (nodes != null) {
+                               node = nodes[0];
+                       }
+                       if (node == null) {
+                               Symbol sym = null;
+                               if (symbol != null) {
+                                       sym = symbol.scope.lookup (name);
+                               }
+                               if (sym != null || create_namespace) {
+                                       node = new Node (name);
+                                       node.symbol = sym;
+                                       node.new_symbol = node.symbol == null;
+                                       node.source_reference = source_reference;
+                                       add_member (node);
+
+                                       if (sym == null) {
+                                               new_namespaces.add (node);
+                                       }
+                               }
+                       }
+                       return node;
+               }
+
+               public ArrayList<Node>? lookup_all (string name) {
+                       return scope[name];
+               }
+
+               public UnresolvedSymbol get_unresolved_symbol () {
+                       if (parent.name == null) {
+                               return new UnresolvedSymbol (null, name);
+                       } else {
+                               return new UnresolvedSymbol (parent.get_unresolved_symbol (), name);
+                       }
+               }
+
+               public void process (GirParser parser) {
+                       if (processed) {
+                               return;
+                       }
+
+                       // process children allowing node removals
+                       for (int i=0; i < members.size; i++) {
+                               var node = members[i];
+                               node.process (parser);
+                               if (i < members.size && members[i] != node) {
+                                       // node removed in the middle
+                                       i--;
+                               }
+                       }
+
+                       if (girdata != null) {
+                               // GIR node processing
+                               if (symbol is Method) {
+                                       var m = (Method) symbol;
+                                       parser.process_callable (this);
+
+                                       var colliding = parent.lookup_all (name);
+                                       foreach (var node in colliding) {
+                                               var sym = node.symbol;
+                                               if (sym is Field && !(m.return_type is VoidType) && m.get_parameters().size == 0) {
+                                                       // assume method is getter
+                                                       merged = true;
+                                               } else if (sym is Signal) {
+                                                       var sig = (Signal) sym;
+                                                       if (m.is_virtual) {
+                                                               sig.is_virtual = true;
+                                                       } else {
+                                                               sig.has_emitter = true;
+                                                       }
+                                                       parser.assume_parameter_names (sig, m, false);
+                                                       merged = true;
+                                               } else if (sym is Method && !(sym is CreationMethod) && node != this) {
+                                                       if (m.is_virtual) {
+                                                               bool different_invoker = false;
+                                                               foreach (var attr in m.attributes) {
+                                                                       if (attr.name == "NoWrapper") {
+                                                                               /* no invoker but this method has the same name,
+                                                                                  most probably the invoker has a different name
+                                                                                  and g-ir-scanner missed it */
+                                                                               var invoker = parser.find_invoker (this);
+                                                                               if (invoker != null) {
+                                                                                       m.vfunc_name = m.name;
+                                                                                       m.name = invoker.symbol.name;
+                                                                                       m.attributes.remove (attr);
+                                                                                       invoker.processed = true;
+                                                                                       invoker.merged = true;
+                                                                                       different_invoker = true;
+                                                                               }
+                                                                       }
+                                                               }
+                                                               if (!different_invoker) {
+                                                                       node.processed = true;
+                                                                       node.merged = true;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       if (!(m is CreationMethod)) {
+                                               // merge custom vfunc
+                                               if (metadata.has_argument (ArgumentType.VFUNC_NAME)) {
+                                                       var vfunc = parent.lookup (metadata.get_string (ArgumentType.VFUNC_NAME));
+                                                       if (vfunc != null && vfunc != this) {
+                                                               vfunc.processed = true;
+                                                               vfunc.merged = true;
+                                                       }
+                                               }
+                                       }
+                                       if (m.coroutine) {
+                                               parser.process_async_method (this);
+                                       }
+                               } else if (symbol is Property) {
+                                       var getter = parent.lookup ("get_%s".printf (name));
+                                       var setter = parent.lookup ("set_%s".printf (name));
+                                       var colliding = parent.lookup_all (name);
+                                       foreach (var node in colliding) {
+                                               if (node.symbol is Signal) {
+                                                       // properties take precedence
+                                                       node.processed = true;
+                                                       node.merged = true;
+                                               } else if (node.symbol is Method) {
+                                                       // try assuming it's the getter
+                                                       getter = node;
+                                               }
+                                       }
+                                       var prop = (Property) symbol;
+                                       if (prop.no_accessor_method) {
+                                               // property getter and setter must be matched both, otherwise it's NoAccessorMethod
+                                               prop.no_accessor_method = false;
+                                               if (prop.get_accessor != null) {
+                                                       var m = getter != null ? getter.symbol as Method : null;
+                                                       if (m != null) {
+                                                               getter.process (parser);
+                                                               if (m.return_type is VoidType || m.get_parameters().size != 0) {
+                                                                       prop.no_accessor_method = true;
+                                                               } else {
+                                                                       if (getter.name == name) {
+                                                                               getter.merged = true;
+                                                                       }
+                                                                       prop.get_accessor.value_type.value_owned = m.return_type.value_owned;
+                                                               }
+                                                       } else {
+                                                               prop.no_accessor_method = true;
+                                                       }
+                                               }
+                                               if (!prop.no_accessor_method && prop.set_accessor != null && prop.set_accessor.writable) {
+                                                       var m = setter != null ? setter.symbol as Method : null;
+                                                       if (m != null) {
+                                                               setter.process (parser);
+                                                               if (!(m.return_type is VoidType) || m.get_parameters().size != 1) {
+                                                                       prop.no_accessor_method = true;
+                                                               }
+                                                       } else {
+                                                               prop.no_accessor_method = true;
+                                                       }
+                                               }
+                                       }
+                               } else if (symbol is Field) {
+                                       var field = (Field) symbol;
+                                       var colliding = parent.lookup_all (name);
+                                       if (colliding.size > 1) {
+                                               // whatelse has precedence over the field
+                                               merged = true;
+                                       }
+
+                                       var gtype_struct_for = parent.girdata["glib:is-gtype-struct-for"];
+                                       if (field.variable_type is DelegateType && gtype_struct_for != null) {
+                                               // virtual method field
+                                               var d = ((DelegateType) field.variable_type).delegate_symbol;
+                                               parser.process_virtual_method_field (this, d, parser.parse_symbol_from_string (gtype_struct_for, d.source_reference));
+                                               merged = true;
+                                       } else if (field.variable_type is ArrayType) {
+                                               var array_length = parent.lookup ("n_%s".printf (field.name));
+                                               if (array_length == null) {
+                                                       array_length = parent.lookup ("%s_length".printf (field.name));
+                                               }
+                                               if (array_length != null) {
+                                                       // array has length
+                                                       field.set_array_length_cname (array_length.symbol.name);
+                                                       field.no_array_length = false;
+                                                       field.array_null_terminated = false;
+                                                       array_length.processed = true;
+                                                       array_length.merged = true;
+                                               }
+                                       }
+                               } else if (symbol is Signal || symbol is Delegate) {
+                                       parser.process_callable (this);
+                               } else if (symbol is Interface) {
+                                       parser.process_interface (this);
+                               } else if (element_type == "alias") {
+                                       parser.process_alias (this);
+                               } else if (symbol is Struct) {
+                                       if (parent.symbol is Struct) {
+                                       // nested struct
+                                               var st = (Struct) parent.symbol;
+                                               foreach (var fn in members) {
+                                                       var f = fn.symbol as Field;
+                                                       if (f != null) {
+                                                               f.set_cname (st.get_cname () + "." + f.get_cname ());
+                                                               f.name = symbol.name + "_" + f.name;
+                                                               fn.name = f.name;
+                                                               parent.add_member (fn);
+                                                       }
+                                               }
+                                               merged = true;
+                                       } else {
+                                               // record for a gtype
+                                               var gtype_struct_for = girdata["glib:is-gtype-struct-for"];
+                                               if (gtype_struct_for != null) {
+                                                       var iface = parser.resolve_symbol (parent, parser.parse_symbol_from_string (gtype_struct_for, source_reference)) as Interface;
+                                                       if (iface != null) {
+                                                               // set the interface struct name
+                                                               iface.set_type_cname (((Struct) symbol).get_cname ());
+                                                       }
+                                                       merged = true;
+                                               }
+                                       }
+                               }
+
+                               // deprecation
+                               symbol.replacement = metadata.get_string (ArgumentType.REPLACEMENT);
+                               symbol.deprecated_since = metadata.get_string (ArgumentType.DEPRECATED_SINCE);
+                               if (symbol.deprecated_since == null) {
+                                       symbol.deprecated_since = girdata.get ("deprecated-version");
+                               }
+                               symbol.deprecated = metadata.get_bool (ArgumentType.DEPRECATED) || symbol.replacement != null || symbol.deprecated_since != null;
+
+                               // cheader filename
+                               var cheader_filename = metadata.get_string (ArgumentType.CHEADER_FILENAME);
+                               if (cheader_filename != null) {
+                                       foreach (string filename in cheader_filename.split (",")) {
+                                               symbol.add_cheader_filename (filename);
+                                       }
+                               }
+                       }
+
+                       var ns = symbol as Namespace;
+                       if (!(new_symbol && merged) && is_container (symbol)) {
+                               foreach (var node in members) {
+                                       if (node.new_symbol && !node.merged && !metadata.get_bool (ArgumentType.HIDDEN) && !(ns != null && node.symbol is Method)) {
+                                               add_symbol_to_container (symbol, node.symbol);
+                                       }
+                               }
+
+                               var cl = symbol as Class;
+                               if (cl != null && cl.default_construction_method == null) {
+                                       // always provide constructor in generated bindings
+                                       // to indicate that implicit Object () chainup is allowed
+                                       var cm = new CreationMethod (null, null, cl.source_reference);
+                                       cm.has_construct_function = false;
+                                       cm.access = SymbolAccessibility.PROTECTED;
+                                       cl.add_method (cm);
+                               } else if (symbol is Namespace) {
+                                       // postprocess namespace methods
+                                       foreach (var nodes in scope.get_values ()) {
+                                               foreach (var node in nodes) {
+                                                       var m = node.symbol as Method;
+                                                       if (m != null) {
+                                                               parser.process_namespace_method (ns, m);
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       processed = true;
+               }
+
+               public string to_string () {
+                       if (parent.name == null) {
+                               return name;
+                       } else {
+                               return "%s.%s".printf (parent.to_string (), name);
+                       }
+               }
        }
 
        static GLib.Regex type_from_string_regex;
@@ -492,9 +793,8 @@ public class Vala.GirParser : CodeVisitor {
        Namespace glib_ns;
 
        SourceFile current_source_file;
-       Symbol current_symbol;
+       Node root;
 
-       string current_gtype_struct_for;
        SourceLocation begin;
        SourceLocation end;
        MarkupTokenType current_token;
@@ -503,22 +803,12 @@ public class Vala.GirParser : CodeVisitor {
 
        ArrayList<Metadata> metadata_stack;
        Metadata metadata;
-       ArrayList<Map<string,string>> girdata_stack;
-       Map<string,string> girdata;
-
-       ArrayList<SymbolInfo> current_symbols_info;
+       ArrayList<Node> tree_stack;
+       Node current;
+       Node old_current;
 
        HashMap<UnresolvedSymbol,Symbol> unresolved_symbols_map = new HashMap<UnresolvedSymbol,Symbol> (unresolved_symbol_hash, unresolved_symbol_equal);
-       HashMap<Symbol,Symbol> concrete_symbols_map = new HashMap<Symbol,Symbol> ();
-
        ArrayList<UnresolvedSymbol> unresolved_gir_symbols = new ArrayList<UnresolvedSymbol> ();
-       HashMap<UnresolvedSymbol,ArrayList<Symbol>> symbol_reparent_map = new HashMap<UnresolvedSymbol,ArrayList<Symbol>> (unresolved_symbol_hash, unresolved_symbol_equal);
-       ArrayList<CallableInfo> callable_info_list = new ArrayList<CallableInfo> ();
-       HashMap<Namespace,ArrayList<Method>> namespace_methods = new HashMap<Namespace,ArrayList<Method>> ();
-       ArrayList<Alias> aliases = new ArrayList<Alias> ();
-       ArrayList<Interface> interfaces = new ArrayList<Interface> ();
-
-       HashMap<UnresolvedSymbol,ArrayList<Delegate>> gtype_callbacks;
 
        /**
         * Parses all .gir source files in the specified code
@@ -529,15 +819,22 @@ public class Vala.GirParser : CodeVisitor {
        public void parse (CodeContext context) {
                this.context = context;
                glib_ns = context.root.scope.lookup ("GLib") as Namespace;
+
+               root = new Node (null);
+               root.symbol = context.root;
+               tree_stack = new ArrayList<Node> ();
+               current = root;
+
                context.accept (this);
 
                resolve_gir_symbols ();
+               create_new_namespaces ();
 
-               postprocess_interfaces ();
-               postprocess_reparenting ();
-               postprocess_aliases ();
-               postprocess_namespace_methods ();
-               postprocess_callables ();
+               root.process (this);
+
+               foreach (var node in root.members) {
+                       report_unused_metadata (node.metadata);
+               }
        }
 
        public override void visit_source_file (SourceFile source_file) {
@@ -568,7 +865,6 @@ public class Vala.GirParser : CodeVisitor {
        public void parse_file (SourceFile source_file) {
                metadata_stack = new ArrayList<Metadata> ();
                metadata = Metadata.empty;
-               girdata_stack = new ArrayList<HashMap<string,string>> ();
 
                // load metadata, first look into metadata directories then in the same directory of the .gir.
                string? metadata_filename = context.get_metadata_path (source_file.filename);
@@ -622,16 +918,7 @@ public class Vala.GirParser : CodeVisitor {
 
        const string GIR_VERSION = "1.2";
 
-       void add_symbol_to_container (Symbol container, Symbol sym) {
-               var name = sym.name;
-               if (name == null && sym is CreationMethod) {
-                       name = ".new";
-               }
-               if (container.scope.lookup (name) != null) {
-                       // overridden by -custom.vala
-                       return;
-               }
-
+       static void add_symbol_to_container (Symbol container, Symbol sym) {
                if (container is Class) {
                        unowned Class cl = (Class) container;
 
@@ -720,11 +1007,23 @@ public class Vala.GirParser : CodeVisitor {
                        } else if (sym is Property) {
                                st.add_property ((Property) sym);
                        }
+               } else if (container is ErrorDomain) {
+                       unowned ErrorDomain ed = (ErrorDomain) container;
+
+                       if (sym is ErrorCode) {
+                               ed.add_code ((ErrorCode) sym);
+                       } else if (sym is Method) {
+                               ed.add_method ((Method) sym);
+                       }
                } else {
-                       Report.error (sym.source_reference, "impossible to add to container `%s'".printf (container.name));
+                       Report.error (sym.source_reference, "impossible to add `%s' to container `%s'".printf (sym.name, container.name));
                }
        }
 
+       static bool is_container (Symbol sym) {
+               return sym is ObjectTypeSymbol || sym is Struct || sym is Namespace || sym is ErrorDomain || sym is Enum;
+       }
+
        UnresolvedSymbol? parse_symbol_from_string (string symbol_string, SourceReference? source_reference = null) {
                UnresolvedSymbol? sym = null;
                foreach (unowned string s in symbol_string.split (".")) {
@@ -736,26 +1035,10 @@ public class Vala.GirParser : CodeVisitor {
                return sym;
        }
 
-       UnresolvedSymbol get_unresolved_symbol (Symbol symbol) {
-               if (symbol is UnresolvedSymbol) {
-                       return (UnresolvedSymbol) symbol;
-               }
-               var sym = new UnresolvedSymbol (null, symbol.name);
-               var result = sym;
-               var cur = symbol.parent_node as Symbol;
-               while (cur != null && cur.name != null) {
-                       sym = new UnresolvedSymbol (sym, cur.name);
-                       cur = cur.parent_node as Symbol;
-               }
-               return result;
-       }
-
-       void set_symbol_mapping (Symbol map_from, Symbol map_to) {
+       void set_symbol_mapping (UnresolvedSymbol map_from, Symbol map_to) {
                // last mapping is the most up-to-date
                if (map_from is UnresolvedSymbol) {
                        unresolved_symbols_map[(UnresolvedSymbol) map_from] = map_to;
-               } else {
-                       concrete_symbols_map[map_from] = map_to;
                }
        }
 
@@ -783,318 +1066,35 @@ public class Vala.GirParser : CodeVisitor {
                }
        }
 
-       SymbolInfo? add_symbol_info (Symbol symbol) {
-               var name = symbol.name;
-               if (symbol is CreationMethod && name == null) {
-                       name = ".new";
-               }
-
-               var info = new SymbolInfo ();
-               info.symbol = symbol;
-               info.metadata = metadata;
-               info.girdata = girdata;
-               current_symbols_info.add (info);
-               return info;
-       }
-
-       ArrayList<SymbolInfo> get_colliding_symbols_info (SymbolInfo info) {
-               var name = info.symbol.name;
-               if (name == null && info.symbol is CreationMethod) {
-                       name = ".new";
-               }
-               var result = new ArrayList<SymbolInfo> ();
-               foreach (var cinfo in current_symbols_info) {
-                       if (cinfo.symbol.name == name) {
-                               result.add (cinfo);
-                       }
-               }
-               return result;
-       }
-
-       SymbolInfo? get_current_first_symbol_info (string name) {
-               foreach (var info in current_symbols_info) {
-                       if (info.symbol.name == name) {
-                               return info;
-                       }
-               }
-               return null;
-       }
-
-       Symbol? get_current_first_symbol (string name) {
-               var info = get_current_first_symbol_info (name);
-               if (info != null) {
-                       return info.symbol;
-               }
-               return null;
-       }
-
-       SymbolInfo? find_invoker (Method method) {
+       Node? find_invoker (Node node) {
                /* most common use case is invoker has at least the given method prefix
                   and the same parameter names */
-               var prefix = "%s_".printf (method.name);
-               foreach (var info in current_symbols_info) {
-                       if (!info.symbol.name.has_prefix (prefix)) {
+               var m = (Method) node.symbol;
+               var prefix = "%s_".printf (m.name);
+               foreach (var n in node.parent.members) {
+                       if (!n.symbol.name.has_prefix (prefix)) {
                                continue;
                        }
-                       Method? invoker = info.symbol as Method;
-                       if (invoker == null || (method.get_parameters ().size != invoker.get_parameters ().size)) {
+                       Method? invoker = n.symbol as Method;
+                       if (invoker == null || (m.get_parameters().size != invoker.get_parameters().size)) {
                                continue;
                        }
                        var iter = invoker.get_parameters ().iterator ();
-                       foreach (var param in method.get_parameters ()) {
+                       foreach (var param in m.get_parameters ()) {
                                assert (iter.next ());
-                               if (param.name != iter.get ().name)     {
+                               if (param.name != iter.get().name)      {
                                        invoker = null;
                                        break;
                                }
                        }
                        if (invoker != null) {
-                               return info;
+                               return n;
                        }
                }
 
                return null;
        }
 
-       void merge (SymbolInfo info, ArrayList<SymbolInfo> colliding, HashSet<SymbolInfo> merged) {
-               if (info.symbol is Struct) {
-                       var gtype_struct_for = info.girdata["glib:is-gtype-struct-for"];
-                       if (gtype_struct_for != null) {
-                               var iface = get_current_first_symbol (gtype_struct_for) as Interface;
-                               if (iface != null) {
-                                       // set the interface struct name
-                                       iface.set_type_cname (((Struct) info.symbol).get_cname ());
-                               }
-                               merged.add (info);
-                       }
-               } else if (info.symbol is Property) {
-                       var prop = (Property) info.symbol;
-                       var getter_name = "get_%s".printf (prop.name);
-                       var setter_name = "set_%s".printf (prop.name);
-                       foreach (var cinfo in colliding) {
-                               var sym = cinfo.symbol;
-                               if (sym is Signal || sym is Field) {
-                                       // properties take precedence
-                                       merged.add (cinfo);
-                               } else if (sym is Method) {
-                                       // assume method is getter
-                                       merged.add (cinfo);
-                                       getter_name = sym.name;
-                               }
-                       }
-                       if (prop.get_accessor != null) {
-                               var getter_method = get_current_first_symbol (getter_name) as Method;
-                               if (getter_method != null) {
-                                       prop.no_accessor_method = false;
-                                       prop.get_accessor.value_type.value_owned = getter_method.return_type.value_owned;
-                               }
-                       } else if (prop.set_accessor != null && get_current_first_symbol_info (setter_name) != null) {
-                               prop.no_accessor_method = false;
-                       }
-               } else if (info.symbol is Signal) {
-                       var sig = (Signal) info.symbol;
-                       foreach (var cinfo in colliding) {
-                               var sym = cinfo.symbol;
-                               if (sym is Method) {
-                                       var method = (Method) sym;
-                                       if (method.is_virtual) {
-                                               sig.is_virtual = true;
-                                       } else {
-                                               sig.has_emitter = true;
-                                       }
-                                       assume_parameter_names (sig, method, false);
-                                       merged.add (cinfo);
-                               } else if (sym is Field) {
-                                       merged.add (cinfo);
-                               }
-                       }
-               } else if (info.symbol is Method && !(info.symbol is CreationMethod)) {
-                       var m = (Method) info.symbol;
-                       foreach (var cinfo in colliding) {
-                               var sym = cinfo.symbol;
-                               if (sym != m && m.is_virtual && sym is Method) {
-                                       bool different_invoker = false;
-                                       foreach (var attr in m.attributes) {
-                                               if (attr.name == "NoWrapper") {
-                                                       /* no invoker but this method has the same name,
-                                                          most probably the invoker has a different name
-                                                          and g-ir-scanner missed it */
-                                                       var invoker = find_invoker (m);
-                                                       if (invoker != null) {
-                                                               m.vfunc_name = m.name;
-                                                               m.name = invoker.symbol.name;
-                                                               m.attributes.remove (attr);
-                                                               merged.add (invoker);
-                                                               different_invoker = true;
-                                                       }
-                                                       break;
-                                               }
-                                       }
-                                       if (!different_invoker) {
-                                               merged.add (cinfo);
-                                       }
-                               }
-                       }
-                       // merge custom vfunc
-                       if (info.metadata.has_argument (ArgumentType.VFUNC_NAME)) {
-                               var vfunc = get_current_first_symbol_info (info.metadata.get_string (ArgumentType.VFUNC_NAME));
-                               if (vfunc != null && vfunc != info) {
-                                       merged.add (vfunc);
-                               }
-                       }
-                       if (m.coroutine) {
-                               // handle async methods
-                               string finish_method_base;
-                               if (m.name.has_suffix ("_async")) {
-                                       finish_method_base = m.name.substring (0, m.name.length - "_async".length);
-                               } else {
-                                       finish_method_base = m.name;
-                               }
-                               var finish_method_info = get_current_first_symbol_info (finish_method_base + "_finish");
-
-                               // check if the method is using non-standard finish method name
-                               if (finish_method_info == null) {
-                                       var method_cname = m.get_finish_cname ();
-                                       foreach (var minfo in current_symbols_info) {
-                                               if (minfo.symbol is Method && ((Method) minfo.symbol).get_cname () == method_cname) {
-                                                       finish_method_info = minfo;
-                                                       break;
-                                               }
-                                       }
-                               }
-
-                               if (finish_method_info != null && finish_method_info.symbol is Method) {
-                                       var finish_method = (Method) finish_method_info.symbol;
-                                       Method method;
-                                       if (finish_method is CreationMethod) {
-                                               method = new CreationMethod (((CreationMethod) finish_method).class_name, null, m.source_reference);
-                                               method.access = m.access;
-                                               method.binding = m.binding;
-                                               method.external = true;
-                                               method.coroutine = true;
-                                               method.has_construct_function = finish_method.has_construct_function;
-                                               method.attributes = m.attributes.copy ();
-                                               method.set_cname (m.get_cname ());
-                                               if (finish_method_base == "new") {
-                                                       method.name = null;
-                                               } else if (finish_method_base.has_prefix ("new_")) {
-                                                       method.name = m.name.substring ("new_".length);
-                                               }
-                                               foreach (var param in m.get_parameters ()) {
-                                                       method.add_parameter (param);
-                                               }
-                                               info.symbol = method;
-                                       } else {
-                                               method = m;
-                                       }
-                                       method.return_type = finish_method.return_type.copy ();
-                                       method.no_array_length = finish_method.no_array_length;
-                                       method.array_null_terminated = finish_method.array_null_terminated;
-                                       foreach (var param in finish_method.get_parameters ()) {
-                                               if (param.direction == ParameterDirection.OUT) {
-                                                       var async_param = param.copy ();
-                                                       if (method.scope.lookup (param.name) != null) {
-                                                               // parameter name conflict
-                                                               async_param.name += "_out";
-                                                       }
-                                                       method.add_parameter (async_param);
-                                               }
-                                       }
-                                       foreach (DataType error_type in finish_method.get_error_types ()) {
-                                               method.add_error_type (error_type.copy ());
-                                       }
-                                       merged.add (finish_method_info);
-                               }
-                       }
-               } else if (info.symbol is Field) {
-                       foreach (var cinfo in colliding) {
-                               var sym = cinfo.symbol;
-                               if (sym is Method) {
-                                       // assume method is getter
-                                       merged.add (cinfo);
-                               }
-                       }
-
-                       var field = (Field) info.symbol;
-                       if (field.variable_type is ArrayType) {
-                               var array_length = get_current_first_symbol_info ("n_%s".printf (field.name));
-                               if (array_length == null) {
-                                       array_length = get_current_first_symbol_info ("%s_length".printf (field.name));
-                               }
-                               if (array_length != null) {
-                                       // array has length
-                                       field.set_array_length_cname (array_length.symbol.name);
-                                       field.no_array_length = false;
-                                       field.array_null_terminated = false;
-                                       merged.add (array_length);
-                               }
-                       }
-               }
-       }
-
-       void postprocess_symbol (Symbol sym, Metadata metadata, Map<string,string> girdata) {
-               // deprecation
-               sym.replacement = metadata.get_string (ArgumentType.REPLACEMENT);
-               sym.deprecated_since = metadata.get_string (ArgumentType.DEPRECATED_SINCE);
-               if (sym.deprecated_since == null) {
-                       sym.deprecated_since = girdata.get ("deprecated-version");
-               }
-               sym.deprecated = metadata.get_bool (ArgumentType.DEPRECATED) || sym.replacement != null || sym.deprecated_since != null;
-
-               // cheader filename
-               var cheader_filename = metadata.get_string (ArgumentType.CHEADER_FILENAME);
-               if (cheader_filename != null) {
-                       foreach (string filename in cheader_filename.split (",")) {
-                               sym.add_cheader_filename (filename);
-                       }
-               }
-
-               // mark to be reparented
-               if (metadata.has_argument (ArgumentType.PARENT)) {
-                       var target_symbol = parse_symbol_from_string (metadata.get_string (ArgumentType.PARENT), metadata.get_source_reference (ArgumentType.PARENT));
-                       var reparent_list = symbol_reparent_map[target_symbol];
-                       if (reparent_list == null) {
-                               reparent_list = new ArrayList<Symbol>();
-                               symbol_reparent_map[target_symbol] = reparent_list;
-                       }
-                       reparent_list.add (sym);
-
-                       // if referenceable, map unresolved references to point to the new place
-                       if (sym is Namespace || sym is TypeSymbol) {
-                               set_symbol_mapping (sym, new UnresolvedSymbol (target_symbol, sym.name));
-                       }
-               }
-
-               if (sym is Class) {
-                       var cl = (Class) sym;
-                       if (cl.default_construction_method == null) {
-                               // always provide constructor in generated bindings
-                               // to indicate that implicit Object () chainup is allowed
-                               var cm = new CreationMethod (null, null, cl.source_reference);
-                               cm.has_construct_function = false;
-                               cm.access = SymbolAccessibility.PROTECTED;
-                               cl.add_method (cm);
-                       }
-               }
-       }
-
-       void merge_add_process (Symbol container) {
-               var merged = new HashSet<SymbolInfo> ();
-               foreach (var info in current_symbols_info) {
-                       merge (info, get_colliding_symbols_info (info), merged);
-               }
-
-               foreach (var info in current_symbols_info) {
-                       if (merged.contains (info) || info.metadata.get_bool (ArgumentType.HIDDEN)) {
-                               continue;
-                       }
-                       if (!(current_symbol is Namespace && info.symbol is Method) && !info.metadata.has_argument (ArgumentType.PARENT)) {
-                               add_symbol_to_container (container, info.symbol);
-                       }
-                       postprocess_symbol (info.symbol, info.metadata, info.girdata);
-               }
-       }
-
        Metadata get_current_metadata () {
                var selector = reader.name;
                var child_name = reader.get_attribute ("name");
@@ -1124,8 +1124,6 @@ public class Vala.GirParser : CodeVisitor {
 
                metadata_stack.add (metadata);
                metadata = new_metadata;
-               girdata_stack.add (girdata);
-               girdata = reader.get_attributes ();
 
                return true;
        }
@@ -1133,8 +1131,6 @@ public class Vala.GirParser : CodeVisitor {
        void pop_metadata () {
                metadata = metadata_stack[metadata_stack.size - 1];
                metadata_stack.remove_at (metadata_stack.size - 1);
-               girdata = girdata_stack[girdata_stack.size - 1];
-               girdata_stack.remove_at (girdata_stack.size - 1);
        }
 
        bool parse_type_arguments_from_string (DataType parent_type, string type_arguments, SourceReference? source_reference = null) {
@@ -1310,9 +1306,11 @@ public class Vala.GirParser : CodeVisitor {
                return type;
        }
 
-       string? element_get_name (bool remap = false) {
-               var name = reader.get_attribute ("name");
-               var orig_name = name;
+       string? element_get_name (string? gir_name = null) {
+               var name = gir_name;
+               if (name == null) {
+                       name = reader.get_attribute ("name");
+               }
                var pattern = metadata.get_string (ArgumentType.NAME);
                if (pattern != null) {
                        try {
@@ -1336,9 +1334,6 @@ public class Vala.GirParser : CodeVisitor {
                                name = name.substring (0, name.length - "Enum".length);
                        }
                }
-               if (name != orig_name && remap) {
-                       set_symbol_mapping (parse_symbol_from_string (orig_name), parse_symbol_from_string (name));
-               }
 
                return name;
        }
@@ -1355,16 +1350,16 @@ public class Vala.GirParser : CodeVisitor {
                        param.carray_length_parameter_position = info.vala_idx;
                        param.set_array_length_cname (info.param.name);
                }
-               if (info.param.variable_type.to_qualified_string () != "int") {
-                       var unresolved_type = (UnresolvedType) info.param.variable_type;
-                       var resolved_struct = resolve_symbol (glib_ns.scope, unresolved_type.unresolved_symbol) as Struct;
-                       if (resolved_struct != null) {
+               var type_name = info.param.variable_type.to_qualified_string ();
+               if (type_name != "int") {
+                       var st = context.root.scope.lookup (type_name) as Struct;
+                       if (st != null) {
                                if (sym is Method) {
                                        var m = (Method) sym;
-                                       m.array_length_type = resolved_struct.get_cname ();
+                                       m.array_length_type = st.get_cname ();
                                } else {
                                        var param = (Parameter) sym;
-                                       param.array_length_type = resolved_struct.get_cname ();
+                                       param.array_length_type = st.get_cname ();
                                }
                        }
                }
@@ -1379,10 +1374,7 @@ public class Vala.GirParser : CodeVisitor {
                next ();
                while (current_token == MarkupTokenType.START_ELEMENT) {
                        if (reader.name == "namespace") {
-                               var ns = parse_namespace ();
-                               if (ns != null) {
-                                       context.root.add_namespace (ns);
-                               }
+                               parse_namespace ();
                        } else if (reader.name == "include") {
                                parse_include ();
                        } else if (reader.name == "package") {
@@ -1402,8 +1394,6 @@ public class Vala.GirParser : CodeVisitor {
                        }
                }
                end_element ("repository");
-
-               report_unused_metadata (metadata);
        }
 
        void parse_include () {
@@ -1451,38 +1441,97 @@ public class Vala.GirParser : CodeVisitor {
                }
        }
 
-       Namespace? parse_namespace () {
+       Node? resolve_node (Node parent_scope, UnresolvedSymbol unresolved_sym, bool create_namespace = false) {
+               if (unresolved_sym.inner == null) {
+                       var scope = parent_scope;
+                       while (scope != null) {
+                               var node = scope.lookup (unresolved_sym.name, create_namespace, unresolved_sym.source_reference);
+                               if (node != null) {
+                                       return node;
+                               }
+                               scope = scope.parent;
+                       }
+               } else {
+                       var inner = resolve_node (parent_scope, unresolved_sym.inner, create_namespace);
+                       if (inner != null) {
+                               return inner.lookup (unresolved_sym.name, create_namespace, unresolved_sym.source_reference);
+                       }
+               }
+               return null;
+       }
+
+       Symbol? resolve_symbol (Node parent_scope, UnresolvedSymbol unresolved_sym) {
+               var node = resolve_node (parent_scope, unresolved_sym);
+               if (node != null) {
+                       return node.symbol;
+               }
+               return null;
+       }
+
+       void push_node (string name, bool merge) {
+               var parent = current;
+               if (metadata.has_argument (ArgumentType.PARENT)) {
+                       var target = parse_symbol_from_string (metadata.get_string (ArgumentType.PARENT), metadata.get_source_reference (ArgumentType.PARENT));
+                       parent = resolve_node (root, target, true);
+               }
+
+               var node = parent.lookup (name);
+               if (node == null || (node.symbol != null && !merge)) {
+                       node = new Node (name);
+                       node.new_symbol = true;
+               }
+               node.element_type = reader.name;
+               node.girdata = reader.get_attributes ();
+               node.metadata = metadata;
+               node.source_reference = get_current_src ();
+               parent.add_member (node);
+
+               var gir_name = node.girdata["name"];
+               if (gir_name == null) {
+                       gir_name = node.girdata["glib:name"];
+               }
+               if (parent != current || gir_name != name) {
+                       set_symbol_mapping (new UnresolvedSymbol (null, gir_name), node.get_unresolved_symbol ());
+               }
+
+               tree_stack.add (current);
+               current = node;
+       }
+
+       void pop_node () {
+               old_current = current;
+               current = tree_stack[tree_stack.size - 1];
+               tree_stack.remove_at (tree_stack.size - 1);
+       }
+
+       void parse_namespace () {
                start_element ("namespace");
 
-               bool new_namespace = false;
                string? cprefix = reader.get_attribute ("c:identifier-prefixes");
-               string namespace_name = cprefix;
+               string vala_namespace = cprefix;
                string gir_namespace = reader.get_attribute ("name");
                string gir_version = reader.get_attribute ("version");
-               if (namespace_name == null) {
-                       namespace_name = gir_namespace;
-               }
-               current_source_file.gir_namespace = gir_namespace;
-               current_source_file.gir_version = gir_version;
 
                var ns_metadata = metadata.match_child (gir_namespace);
                if (ns_metadata.has_argument (ArgumentType.NAME)) {
-                       namespace_name = ns_metadata.get_string (ArgumentType.NAME);
+                       vala_namespace = ns_metadata.get_string (ArgumentType.NAME);
                }
-
-               var ns = context.root.scope.lookup (namespace_name) as Namespace;
-               if (ns == null) {
-                       ns = new Namespace (namespace_name, get_current_src ());
-                       new_namespace = true;
-               } else {
-                       if (ns.external_package) {
-                               ns.attributes = null;
-                               ns.source_reference = get_current_src ();
-                       }
+               if (vala_namespace == null) {
+                       vala_namespace = gir_namespace;
                }
 
-               if (gir_namespace != ns.name) {
-                       set_symbol_mapping (new UnresolvedSymbol (null, gir_namespace), ns);
+               current_source_file.gir_namespace = gir_namespace;
+               current_source_file.gir_version = gir_version;
+
+               Namespace ns;
+               push_node (vala_namespace, true);
+               if (current.new_symbol) {
+                       ns = new Namespace (vala_namespace, current.source_reference);
+                       current.symbol = ns;
+               } else {
+                       ns = (Namespace) current.symbol;
+                       ns.attributes = null;
+                       ns.source_reference = current.source_reference;
                }
 
                if (cprefix != null) {
@@ -1502,16 +1551,6 @@ public class Vala.GirParser : CodeVisitor {
                }
 
                next ();
-               var current_namespace_methods = namespace_methods[ns];
-               if (current_namespace_methods == null) {
-                       current_namespace_methods = new ArrayList<Method> ();
-                       namespace_methods[ns] = current_namespace_methods;
-               }
-               var old_symbols_info = current_symbols_info;
-               var old_symbol = current_symbol;
-               current_symbols_info = new ArrayList<SymbolInfo> ();
-               current_symbol = ns;
-               gtype_callbacks = new HashMap<UnresolvedSymbol,ArrayList<Delegate>> (unresolved_symbol_hash, unresolved_symbol_equal);
                while (current_token == MarkupTokenType.START_ELEMENT) {
                        if (!push_metadata ()) {
                                skip_element ();
@@ -1519,44 +1558,39 @@ public class Vala.GirParser : CodeVisitor {
                        }
 
                        if (reader.name == "alias") {
-                               var alias = parse_alias ();
-                               aliases.add (alias);
+                               parse_alias ();
                        } else if (reader.name == "enumeration") {
                                if (reader.get_attribute ("glib:error-quark") != null) {
-                                       add_symbol_info (parse_error_domain ());
+                                       parse_error_domain ();
                                } else {
-                                       add_symbol_info (parse_enumeration ());
+                                       parse_enumeration ();
                                }
                        } else if (reader.name == "bitfield") {
-                               add_symbol_info (parse_bitfield ());
+                               parse_bitfield ();
                        } else if (reader.name == "function") {
-                               var method = parse_method ("function");
-                               add_symbol_info (method);
-                               current_namespace_methods.add (method);
+                               parse_method ("function");
                        } else if (reader.name == "callback") {
-                               add_symbol_info (parse_callback ());
+                               parse_callback ();
                        } else if (reader.name == "record") {
                                if (reader.get_attribute ("glib:get-type") != null && !metadata.get_bool (ArgumentType.STRUCT)) {
-                                       add_symbol_info (parse_boxed ("record"));
+                                       parse_boxed ("record");
                                } else {
                                        if (!reader.get_attribute ("name").has_suffix ("Private")) {
-                                               add_symbol_info (parse_record ());
+                                               parse_record ();
                                        } else {
                                                skip_element ();
                                        }
                                }
                        } else if (reader.name == "class") {
-                               add_symbol_info (parse_class ());
+                               parse_class ();
                        } else if (reader.name == "interface") {
-                               var iface = parse_interface ();
-                               add_symbol_info (iface);
-                               interfaces.add (iface);
+                               parse_interface ();
                        } else if (reader.name == "glib:boxed") {
-                               add_symbol_info (parse_boxed ("glib:boxed"));
+                               parse_boxed ("glib:boxed");
                        } else if (reader.name == "union") {
-                               add_symbol_info (parse_union ());
+                               parse_union ();
                        } else if (reader.name == "constant") {
-                               add_symbol_info (parse_constant ());
+                               parse_constant ();
                        } else {
                                // error
                                Report.error (get_current_src (), "unknown child element `%s' in `namespace'".printf (reader.name));
@@ -1565,34 +1599,20 @@ public class Vala.GirParser : CodeVisitor {
 
                        pop_metadata ();
                }
+               pop_node ();
                end_element ("namespace");
-
-               merge_add_process (ns);
-               current_symbols_info = old_symbols_info;
-               current_symbol = old_symbol;
-               postprocess_gtype_callbacks (ns);
-
-               if (!new_namespace) {
-                       ns = null;
-               }
-
-               return ns;
        }
 
-       Alias parse_alias () {
-               // alias has no type information
+       void parse_alias () {
                start_element ("alias");
-               var alias = new Alias ();
-               alias.source_reference = get_current_src ();
-               alias.name = reader.get_attribute ("name");
-               alias.cname = reader.get_attribute ("c:type");
-               alias.parent_symbol = current_symbol;
-               next ();
+               push_node (element_get_name (), true);
+               // not enough information, symbol will be created while processing the tree
 
-               alias.base_type = element_get_type (parse_type (null, null, true), true);
+               next ();
+               current.base_type = element_get_type (parse_type (null, null, true), true);
 
+               pop_node ();
                end_element ("alias");
-               return alias;
        }
 
        private void calculate_common_prefix (ref string common_prefix, string cname) {
@@ -1614,19 +1634,26 @@ public class Vala.GirParser : CodeVisitor {
                }
        }
 
-       Symbol parse_enumeration (string element_name = "enumeration", bool error_domain = false) {
+       void parse_enumeration (string element_name = "enumeration", bool error_domain = false) {
                start_element (element_name);
+               push_node (element_get_name (), true);
 
                Symbol sym;
-               if (error_domain) {
-                       sym = new ErrorDomain (element_get_name (true), get_current_src ());
-               } else {
-                       var en = new Enum (element_get_name (), get_current_src ());
-                       if (element_name == "bitfield") {
-                               en.is_flags = true;
+               if (current.new_symbol) {
+                       if (error_domain) {
+                               sym = new ErrorDomain (current.name, current.source_reference);
+                       } else {
+                               var en = new Enum (current.name, current.source_reference);
+                               if (element_name == "bitfield") {
+                                       en.is_flags = true;
+                               }
+                               sym = en;
                        }
-                       sym = en;
+                       current.symbol = sym;
+               } else {
+                       sym = current.symbol;
                }
+               sym.external = true;
                sym.access = SymbolAccessibility.PUBLIC;
 
                string cname = reader.get_attribute ("c:type");
@@ -1634,8 +1661,6 @@ public class Vala.GirParser : CodeVisitor {
 
                next ();
                
-               var old_symbol = current_symbol;
-               current_symbol = sym;
                while (current_token == MarkupTokenType.START_ELEMENT) {
                        if (!push_metadata ()) {
                                skip_element ();
@@ -1644,12 +1669,10 @@ public class Vala.GirParser : CodeVisitor {
 
                        if (reader.name == "member") {
                                if (error_domain) {
-                                       ErrorCode ec = parse_error_member ();
-                                       ((ErrorDomain) sym).add_code (ec);
+                                       var ec = parse_error_member ();
                                        calculate_common_prefix (ref common_prefix, ec.get_cname ());
                                } else {
                                        var ev = parse_enumeration_member ();
-                                       ((Enum) sym).add_value (ev);
                                        calculate_common_prefix (ref common_prefix, ev.get_cname ());
                                }
                        } else {
@@ -1671,48 +1694,61 @@ public class Vala.GirParser : CodeVisitor {
                        }
                }
 
+               pop_node ();
                end_element (element_name);
-               current_symbol = old_symbol;
-               return sym;
        }
 
-       ErrorDomain parse_error_domain () {
-               return parse_enumeration ("enumeration", true) as ErrorDomain;
+       void parse_error_domain () {
+               parse_enumeration ("enumeration", true);
        }
 
-       Enum parse_bitfield () {
-               return parse_enumeration ("bitfield") as Enum;
+       void parse_bitfield () {
+               parse_enumeration ("bitfield");
        }
 
        EnumValue parse_enumeration_member () {
                start_element ("member");
-               var ev = new EnumValue (reader.get_attribute ("name").up ().replace ("-", "_"), null, get_current_src ());
-               ev.set_cname (reader.get_attribute ("c:identifier"));
+               push_node (element_get_name().up().replace ("-", "_"), false);
+
+               var ev = new EnumValue (current.name, metadata.get_expression (ArgumentType.DEFAULT), current.source_reference);
+               var cname = reader.get_attribute ("c:identifier");
+               if (cname != null) {
+                       ev.set_cname (cname);
+               }
+               current.symbol = ev;
                next ();
+
+               pop_node ();
                end_element ("member");
                return ev;
        }
 
        ErrorCode parse_error_member () {
                start_element ("member");
+               push_node (element_get_name().up().replace ("-", "_"), false);
 
                ErrorCode ec;
-               string name = reader.get_attribute ("name").up ().replace ("-", "_");
                string value = reader.get_attribute ("value");
                if (value != null) {
-                       ec = new ErrorCode.with_value (name, new IntegerLiteral (value));
+                       ec = new ErrorCode.with_value (current.name, new IntegerLiteral (value));
                } else {
-                       ec = new ErrorCode (name);
+                       ec = new ErrorCode (current.name);
+               }
+               current.symbol = ec;
+               var cname = reader.get_attribute ("c:identifier");
+               if (cname != null) {
+                       ec.set_cname (cname);
                }
-               ec.set_cname (reader.get_attribute ("c:identifier"));
-
                next ();
+
+               pop_node ();
                end_element ("member");
                return ec;
        }
 
        DataType parse_return_value (out string? ctype = null) {
                start_element ("return-value");
+
                string transfer = reader.get_attribute ("transfer-ownership");
                string allow_none = reader.get_attribute ("allow-none");
                next ();
@@ -1841,8 +1877,8 @@ public class Vala.GirParser : CodeVisitor {
                                return new ArrayType (element_type, 1, null);
                        }
                } else if (reader.name == "callback"){
-                       var callback = parse_callback ();
-                       return new DelegateType (callback);
+                       parse_callback ();
+                       return new DelegateType ((Delegate) old_current.symbol);
                } else {
                        start_element ("type");
                }
@@ -1967,23 +2003,27 @@ public class Vala.GirParser : CodeVisitor {
                return type;
        }
 
-       Struct parse_record () {
+       void parse_record () {
                start_element ("record");
-               var st = new Struct (reader.get_attribute ("name"), get_current_src ());
-               st.external = true;
-               st.access = SymbolAccessibility.PUBLIC;
+               push_node (element_get_name (), true);
 
-               string cname = reader.get_attribute ("c:type");
-               if (cname != null) {
-                       st.set_cname (cname);
+               Struct st;
+               if (current.new_symbol) {
+                       st = new Struct (reader.get_attribute ("name"), current.source_reference);
+                       var cname = reader.get_attribute ("c:type");
+                       if (cname != null) {
+                               st.set_cname (cname);
+                       }
+                       current.symbol = st;
+               } else {
+                       st = (Struct) current.symbol;
                }
-               current_gtype_struct_for = reader.get_attribute ("glib:is-gtype-struct-for");
+               st.external = true;
+               st.access = SymbolAccessibility.PUBLIC;
 
+               var gtype_struct_for = reader.get_attribute ("glib:is-gtype-struct-for");
+               bool first_field = true;
                next ();
-               var old_symbols_info = current_symbols_info;
-               var old_symbol = current_symbol;
-               current_symbols_info = new ArrayList<SymbolInfo> ();
-               current_symbol = st;
                while (current_token == MarkupTokenType.START_ELEMENT) {
                        if (!push_metadata ()) {
                                skip_element ();
@@ -1991,23 +2031,18 @@ public class Vala.GirParser : CodeVisitor {
                        }
 
                        if (reader.name == "field") {
-                               if (reader.get_attribute ("name") != "priv") {
-                                       add_symbol_info (parse_field ());
+                               if (reader.get_attribute ("name") != "priv" && !(first_field && gtype_struct_for != null)) {
+                                       parse_field ();
                                } else {
                                        skip_element ();
                                }
+                               first_field = false;
                        } else if (reader.name == "constructor") {
                                parse_constructor ();
                        } else if (reader.name == "method") {
-                               add_symbol_info (parse_method ("method"));
+                               parse_method ("method");
                        } else if (reader.name == "union") {
-                               Struct s = parse_union ();
-                               var s_fields = s.get_fields ();
-                               foreach (var f in s_fields) {
-                                       f.set_cname (s.get_cname () + "." + f.get_cname ());
-                                       f.name = s.name + "_" + f.name;
-                                       st.add_field (f);
-                               }
+                               parse_union ();
                        } else {
                                // error
                                Report.error (get_current_src (), "unknown child element `%s' in `record'".printf (reader.name));
@@ -2016,43 +2051,37 @@ public class Vala.GirParser : CodeVisitor {
 
                        pop_metadata ();
                }
-               end_element ("record");
-
-               merge_add_process (st);
-               current_symbols_info = old_symbols_info;
-               current_symbol = old_symbol;
-               current_gtype_struct_for = null;
 
-               return st;
+               pop_node ();
+               end_element ("record");
        }
 
-       Class parse_class () {
+       void parse_class () {
                start_element ("class");
-               var name = element_get_name ();
-               string cname = reader.get_attribute ("c:type");
-               string parent = reader.get_attribute ("parent");
-               var cl = current_symbol.scope.lookup (name) as Class;
-               if (cl == null) {
-                       cl = new Class (name, get_current_src ());
-                       cl.access = SymbolAccessibility.PUBLIC;
-                       cl.external = true;
-
+               push_node (element_get_name (), true);
+
+               Class cl;
+               var parent = reader.get_attribute ("parent");
+               if (current.new_symbol) {
+                       cl = new Class (current.name, current.source_reference);
+                       cl.set_type_id ("%s ()".printf (reader.get_attribute ("glib:get-type")));
+                       var cname = reader.get_attribute ("c:type");
                        if (cname != null) {
                                cl.set_cname (cname);
                        }
-               }
-               if (parent != null) {
-                       cl.add_base_type (parse_type_from_gir_name (parent));
-               }
 
-               cl.set_type_id ("%s ()".printf (reader.get_attribute ("glib:get-type")));
+                       if (parent != null) {
+                               cl.add_base_type (parse_type_from_gir_name (parent));
+                       }
+                       current.symbol = cl;
+               } else {
+                       cl = (Class) current.symbol;
+               }
+               cl.access = SymbolAccessibility.PUBLIC;
+               cl.external = true;
 
                next ();
                var first_field = true;
-               var old_symbol = current_symbol;
-               var old_symbols_info = current_symbols_info;
-               current_symbols_info = new ArrayList<SymbolInfo> ();
-               current_symbol = cl;
                while (current_token == MarkupTokenType.START_ELEMENT) {
                        if (!push_metadata ()) {
                                skip_element ();
@@ -2065,39 +2094,33 @@ public class Vala.GirParser : CodeVisitor {
                                next ();
                                end_element ("implements");
                        } else if (reader.name == "constant") {
-                               add_symbol_info (parse_constant ());
+                               parse_constant ();
                        } else if (reader.name == "field") {
                                if (first_field && parent != null) {
                                        // first field is guaranteed to be the parent instance
                                        skip_element ();
                                } else {
                                        if (reader.get_attribute ("name") != "priv") {
-                                               add_symbol_info (parse_field ());
+                                               parse_field ();
                                        } else {
                                                skip_element ();
                                        }
                                }
                                first_field = false;
                        } else if (reader.name == "property") {
-                               add_symbol_info (parse_property ());
+                               parse_property ();
                        } else if (reader.name == "constructor") {
-                               add_symbol_info (parse_constructor ());
+                               parse_constructor ();
                        } else if (reader.name == "function") {
-                               add_symbol_info (parse_method ("function"));
+                               parse_method ("function");
                        } else if (reader.name == "method") {
-                               add_symbol_info (parse_method ("method"));
+                               parse_method ("method");
                        } else if (reader.name == "virtual-method") {
-                               add_symbol_info (parse_method ("virtual-method"));
+                               parse_method ("virtual-method");
                        } else if (reader.name == "union") {
-                               Struct s = parse_union ();
-                               var s_fields = s.get_fields ();
-                               foreach (var f in s_fields) {
-                                       f.set_cname (s.get_cname () + "." + f.get_cname ());
-                                       f.name = s.name + "_" + f.name;
-                                       add_symbol_info (f);
-                               }
+                               parse_union ();
                        } else if (reader.name == "glib:signal") {
-                               add_symbol_info (parse_signal ());
+                               parse_signal ();
                        } else {
                                // error
                                Report.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader.name));
@@ -2107,31 +2130,36 @@ public class Vala.GirParser : CodeVisitor {
                        pop_metadata ();
                }
 
-               merge_add_process (cl);
-               current_symbols_info = old_symbols_info;
-               current_symbol = old_symbol;
-
+               pop_node ();
                end_element ("class");
-               return cl;
        }
 
-       Interface parse_interface () {
+       void parse_interface () {
                start_element ("interface");
-               var iface = new Interface (element_get_name (), get_current_src ());
+               push_node (element_get_name (), true);
+
+               Interface iface;
+               if (current.new_symbol) {
+                       iface = new Interface (current.name, current.source_reference);
+                       var cname = reader.get_attribute ("c:type");
+                       if (cname != null) {
+                               iface.set_cname (cname);
+                       }
+                       var typeid = reader.get_attribute ("glib:get-type");
+                       if (typeid != null) {
+                               iface.set_type_id ("%s ()".printf (typeid));
+                       }
+
+                       current.symbol = iface;
+               } else {
+                       iface = (Interface) current.symbol;
+               }
+
                iface.access = SymbolAccessibility.PUBLIC;
                iface.external = true;
 
-               string cname = reader.get_attribute ("c:type");
-               if (cname != null) {
-                       iface.set_cname (cname);
-               }
-               iface.set_type_id ("%s ()".printf (reader.get_attribute ("glib:get-type")));
 
                next ();
-               var old_symbol = current_symbol;
-               var old_symbols_info = current_symbols_info;
-               current_symbol = iface;
-               current_symbols_info = new ArrayList<SymbolInfo> ();
                while (current_token == MarkupTokenType.START_ELEMENT) {
                        if (!push_metadata ()) {
                                skip_element ();
@@ -2144,17 +2172,17 @@ public class Vala.GirParser : CodeVisitor {
                                next ();
                                end_element ("prerequisite");
                        } else if (reader.name == "field") {
-                               add_symbol_info (parse_field ());
+                               parse_field ();
                        } else if (reader.name == "property") {
-                               add_symbol_info (parse_property ());
+                               parse_property ();
                        } else if (reader.name == "virtual-method") {
-                               add_symbol_info (parse_method ("virtual-method"));
+                               parse_method ("virtual-method");
                        } else if (reader.name == "function") {
-                               add_symbol_info (parse_method ("function"));
+                               parse_method ("function");
                        } else if (reader.name == "method") {
-                               add_symbol_info (parse_method ("method"));
+                               parse_method ("method");
                        } else if (reader.name == "glib:signal") {
-                               add_symbol_info (parse_signal ());
+                               parse_signal ();
                        } else {
                                // error
                                Report.error (get_current_src (), "unknown child element `%s' in `interface'".printf (reader.name));
@@ -2164,45 +2192,36 @@ public class Vala.GirParser : CodeVisitor {
                        pop_metadata ();
                }
 
-               merge_add_process (iface);
-               current_symbol = old_symbol;
-               current_symbols_info = old_symbols_info;
-
+               pop_node ();
                end_element ("interface");
-               return iface;
        }
 
-       Field parse_field () {
+       void parse_field () {
                start_element ("field");
-               string name = reader.get_attribute ("name");
+               push_node (element_get_name (), false);
+
                string allow_none = reader.get_attribute ("allow-none");
                next ();
                var type = parse_type ();
                type = element_get_type (type, true);
-               if (type is DelegateType && current_gtype_struct_for != null) {
-                       // virtual
-                       var gtype_struct_for = parse_symbol_from_string (current_gtype_struct_for);
-                       ArrayList<Delegate> callbacks = gtype_callbacks.get (gtype_struct_for);
-                       if (callbacks == null) {
-                               callbacks = new ArrayList<Delegate> ();
-                               gtype_callbacks.set (gtype_struct_for, callbacks);
-                       }
-                       callbacks.add (((DelegateType) type).delegate_symbol);
-               }
-               var field = new Field (name, type, null, get_current_src ());
+
+               var field = new Field (current.name, type, null, current.source_reference);
                field.access = SymbolAccessibility.PUBLIC;
                field.no_array_length = true;
                field.array_null_terminated = true;
                if (allow_none == "1") {
                        type.nullable = true;
                }
+               current.symbol = field;
+
+               pop_node ();
                end_element ("field");
-               return field;
        }
 
        Property parse_property () {
                start_element ("property");
-               string name = reader.get_attribute ("name").replace ("-", "_");
+               push_node (element_get_name().replace ("-", "_"), false);
+
                string readable = reader.get_attribute ("readable");
                string writable = reader.get_attribute ("writable");
                string construct_ = reader.get_attribute ("construct");
@@ -2211,7 +2230,7 @@ public class Vala.GirParser : CodeVisitor {
                bool no_array_length;
                bool array_null_terminated;
                var type = parse_type (null, null, false, out no_array_length, out array_null_terminated);
-               var prop = new Property (name, type, null, null, get_current_src ());
+               var prop = new Property (current.name, type, null, null, current.source_reference);
                prop.access = SymbolAccessibility.PUBLIC;
                prop.external = true;
                prop.no_accessor_method = true;
@@ -2224,32 +2243,19 @@ public class Vala.GirParser : CodeVisitor {
                if (writable == "1" || construct_only == "1") {
                        prop.set_accessor = new PropertyAccessor (false, (construct_only != "1") && (writable == "1"), (construct_only == "1") || (construct_ == "1"), prop.property_type.copy (), null, null);
                }
+               current.symbol = prop;
+
+               pop_node ();
                end_element ("property");
                return prop;
        }
 
-       Delegate parse_callback () {
-               return this.parse_function ("callback") as Delegate;
-       }
-
-       CreationMethod parse_constructor () {
-               return parse_function ("constructor") as CreationMethod;
+       void parse_callback () {
+               parse_function ("callback");
        }
 
-       class CallableInfo {
-               public Symbol symbol;
-               public List<ParameterInfo> parameters;
-               public Metadata metadata;
-
-               public ArrayList<int> array_length_parameters = new ArrayList<int> ();
-               public ArrayList<int> closure_parameters = new ArrayList<int> ();
-               public ArrayList<int> destroy_parameters = new ArrayList<int> ();
-
-               public CallableInfo (Symbol symbol, List<ParameterInfo> parameters, Metadata metadata) {
-                       this.symbol = symbol;
-                       this.parameters = parameters;
-                       this.metadata = metadata;
-               }
+       void parse_constructor () {
+               parse_function ("constructor");
        }
 
        class ParameterInfo {
@@ -2270,10 +2276,11 @@ public class Vala.GirParser : CodeVisitor {
                public bool keep;
        }
 
-       Symbol parse_function (string element_name) {
+       void parse_function (string element_name) {
                start_element (element_name);
-               // replace is needed for signal names
-               string name = element_get_name ().replace ("-", "_");
+               push_node (element_get_name (reader.get_attribute ("invoker")).replace ("-", "_"), false);
+
+               string name = current.name;
                string cname = reader.get_attribute ("c:identifier");
                string throws_string = reader.get_attribute ("throws");
                string invoker = reader.get_attribute ("invoker");
@@ -2291,28 +2298,28 @@ public class Vala.GirParser : CodeVisitor {
                Symbol s;
 
                if (element_name == "callback") {
-                       s = new Delegate (name, return_type, get_current_src ());
+                       s = new Delegate (name, return_type, current.source_reference);
                } else if (element_name == "constructor") {
                        if (name == "new") {
                                name = null;
                        } else if (name.has_prefix ("new_")) {
                                name = name.substring ("new_".length);
                        }
-                       var m = new CreationMethod (null, name, get_current_src ());
+                       var m = new CreationMethod (null, name, current.source_reference);
                        m.has_construct_function = false;
 
                        string parent_ctype = null;
-                       if (current_symbol is Class) {
-                               parent_ctype = ((Class) current_symbol).get_cname ();
+                       if (current.parent.symbol is Class) {
+                               parent_ctype = ((Class) current.parent.symbol).get_cname ();
                        }
                        if (return_ctype != null && (parent_ctype == null || return_ctype != parent_ctype + "*")) {
                                m.custom_return_type_cname = return_ctype;
                        }
                        s = m;
                } else if (element_name == "glib:signal") {
-                       s = new Signal (name, return_type, get_current_src ());
+                       s = new Signal (name, return_type, current.source_reference);
                } else {
-                       s = new Method (name, return_type, get_current_src ());
+                       s = new Method (name, return_type, current.source_reference);
                }
 
                s.access = SymbolAccessibility.PUBLIC;
@@ -2333,10 +2340,6 @@ public class Vala.GirParser : CodeVisitor {
                                        s.attributes.append (new Attribute ("NoWrapper", s.source_reference));
                                }
                        }
-
-                       if (invoker != null) {
-                               s.name = invoker;
-                       }
                } else if (element_name == "function") {
                        ((Method) s).binding = MemberBinding.STATIC;
                }
@@ -2360,9 +2363,12 @@ public class Vala.GirParser : CodeVisitor {
                        s.add_error_type (new ErrorType (null, null));
                }
 
+               current.symbol = s;
+
                var parameters = new ArrayList<ParameterInfo> ();
-               var callable = new CallableInfo (s, parameters, metadata);
-               callable_info_list.add (callable);
+               current.array_length_parameters = new ArrayList<int> ();
+               current.closure_parameters = new ArrayList<int> ();
+               current.destroy_parameters = new ArrayList<int> ();
                if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "parameters") {
                        start_element ("parameters");
                        next ();
@@ -2379,13 +2385,13 @@ public class Vala.GirParser : CodeVisitor {
                                default_param_name = "arg%d".printf (parameters.size);
                                var param = parse_parameter (out array_length_idx, out closure_idx, out destroy_idx, out scope, default_param_name);
                                if (array_length_idx != -1) {
-                                       callable.array_length_parameters.add (array_length_idx);
+                                       current.array_length_parameters.add (array_length_idx);
                                }
                                if (closure_idx != -1) {
-                                       callable.closure_parameters.add (closure_idx);
+                                       current.closure_parameters.add (closure_idx);
                                }
                                if (destroy_idx != -1) {
-                                       callable.destroy_parameters.add (destroy_idx);
+                                       current.destroy_parameters.add (destroy_idx);
                                }
 
                                var info = new ParameterInfo (param, array_length_idx, closure_idx, destroy_idx);
@@ -2404,44 +2410,51 @@ public class Vala.GirParser : CodeVisitor {
                        }
                        end_element ("parameters");
                }
+               current.parameters = parameters;
 
+               pop_node ();
                end_element (element_name);
-               return s;
        }
 
-       Method parse_method (string element_name) {
-               return this.parse_function (element_name) as Method;
+       void parse_method (string element_name) {
+               parse_function (element_name);
        }
 
-       Signal parse_signal () {
-               return this.parse_function ("glib:signal") as Signal;
+       void parse_signal () {
+               parse_function ("glib:signal");
        }
 
-       Class parse_boxed (string element_name) {
+       void parse_boxed (string element_name) {
                start_element (element_name);
                string name = reader.get_attribute ("name");
                if (name == null) {
                        name = reader.get_attribute ("glib:name");
                }
-               var cl = new Class (name, get_current_src ());
-               cl.access = SymbolAccessibility.PUBLIC;
-               cl.external = true;
-               cl.is_compact = true;
+               push_node (element_get_name (name), true);
 
-               string cname = reader.get_attribute ("c:type");
-               if (cname != null) {
-                       cl.set_cname (cname);
-               }
+               Class cl;
+               if (current.new_symbol) {
+                       cl = new Class (current.name, current.source_reference);
+                       cl.is_compact = true;
+                       var cname = reader.get_attribute ("c:type");
+                       if (cname != null) {
+                               cl.set_cname (reader.get_attribute ("c:type"));
+                       }
+                       var typeid = reader.get_attribute ("glib:get-type");
+                       if (typeid != null) {
+                               cl.set_type_id ("%s ()".printf (typeid));
+                       }
+                       cl.set_free_function ("g_boxed_free");
+                       cl.set_dup_function ("g_boxed_copy");
 
-               cl.set_type_id ("%s ()".printf (reader.get_attribute ("glib:get-type")));
-               cl.set_free_function ("g_boxed_free");
-               cl.set_dup_function ("g_boxed_copy");
+                       current.symbol = cl;
+               } else {
+                       cl = (Class) current.symbol;
+               }
+               cl.access = SymbolAccessibility.PUBLIC;
+               cl.external = true;
 
                next ();
-               var old_symbols_info = current_symbols_info;
-               var old_symbol = current_symbol;
-               current_symbols_info = new ArrayList<SymbolInfo> ();
-               current_symbol = cl;
                while (current_token == MarkupTokenType.START_ELEMENT) {
                        if (!push_metadata ()) {
                                skip_element ();
@@ -2449,11 +2462,11 @@ public class Vala.GirParser : CodeVisitor {
                        }
 
                        if (reader.name == "field") {
-                               add_symbol_info (parse_field ());
+                               parse_field ();
                        } else if (reader.name == "constructor") {
-                               add_symbol_info (parse_constructor ());
+                               parse_constructor ();
                        } else if (reader.name == "method") {
-                               add_symbol_info (parse_method ("method"));
+                               parse_method ("method");
                        } else {
                                // error
                                Report.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader.name));
@@ -2462,24 +2475,26 @@ public class Vala.GirParser : CodeVisitor {
 
                        pop_metadata ();
                }
-               end_element (element_name);
 
-               merge_add_process (cl);
-               current_symbols_info = old_symbols_info;
-               current_symbol = old_symbol;
-
-               return cl;
+               pop_node ();
+               end_element (element_name);
        }
 
-       Struct parse_union () {
+       void parse_union () {
                start_element ("union");
-               var st = new Struct (reader.get_attribute ("name"), get_current_src ());
+               push_node (element_get_name (), true);
+
+               Struct st;
+               if (current.new_symbol) {
+                       st = new Struct (reader.get_attribute ("name"), current.source_reference);
+                       current.symbol = st;
+               } else {
+                       st = (Struct) current.symbol;
+               }
                st.access = SymbolAccessibility.PUBLIC;
                st.external = true;
-               next ();
 
-               var old_symbol = current_symbol;
-               current_symbol = st;
+               next ();
                while (current_token == MarkupTokenType.START_ELEMENT) {
                        if (!push_metadata ()) {
                                skip_element ();
@@ -2487,19 +2502,13 @@ public class Vala.GirParser : CodeVisitor {
                        }
 
                        if (reader.name == "field") {
-                               st.add_field (parse_field ());
+                               parse_field ();
                        } else if (reader.name == "constructor") {
                                parse_constructor ();
                        } else if (reader.name == "method") {
-                               st.add_method (parse_method ("method"));
+                               parse_method ("method");
                        } else if (reader.name == "record") {
-                               Struct s = parse_record ();
-                               var fs = s.get_fields ();
-                               foreach (var f in fs) {
-                                       f.set_cname (s.get_cname () + "." + f.get_cname ());
-                                       f.name = s.name + "_" + f.name;
-                                       st.add_field (f);
-                               }
+                               parse_record ();
                        } else {
                                // error
                                Report.error (get_current_src (), "unknown child element `%s' in `union'".printf (reader.name));
@@ -2509,22 +2518,23 @@ public class Vala.GirParser : CodeVisitor {
                        pop_metadata ();
                }
 
+               pop_node ();
                end_element ("union");
-               current_symbol = old_symbol;
-
-               return st;
        }
 
-       Constant parse_constant () {
+       void parse_constant () {
                start_element ("constant");
-               string name = element_get_name ();
+               push_node (element_get_name (), false);
+
                next ();
                var type = parse_type ();
-               var c = new Constant (name, type, null, get_current_src ());
+               var c = new Constant (current.name, type, null, current.source_reference);
+               current.symbol = c;
                c.access = SymbolAccessibility.PUBLIC;
                c.external = true;
+
+               pop_node ();
                end_element ("constant");
-               return c;
        }
 
        /* Reporting */
@@ -2558,11 +2568,6 @@ public class Vala.GirParser : CodeVisitor {
        /* Post-parsing */
 
        void resolve_gir_symbols () {
-               // we are remapping unresolved symbols, so create them from concrete symbols
-               foreach (var map_from in concrete_symbols_map.get_keys ()) {
-                       unresolved_symbols_map[get_unresolved_symbol(map_from)] = concrete_symbols_map[map_from];
-               }
-
                // gir has simple namespaces, we won't get deeper than 2 levels here, except reparenting
                foreach (var map_from in unresolved_gir_symbols) {
                        while (map_from != null) {
@@ -2592,184 +2597,231 @@ public class Vala.GirParser : CodeVisitor {
                }
        }
 
-       Symbol? resolve_symbol (Scope parent_scope, UnresolvedSymbol unresolved_symbol) {
-               // simple symbol resolver, enough for gir
-               if (unresolved_symbol.inner == null) {
-                       var scope = parent_scope;
-                       while (scope != null) {
-                               var sym = scope.lookup (unresolved_symbol.name);
-                               if (sym != null) {
-                                       return sym;
-                               }
-                               scope = scope.parent_scope;
-                       }
-               } else {
-                       var inner = resolve_symbol (parent_scope, unresolved_symbol.inner);
-                       if (inner != null) {
-                               return inner.scope.lookup (unresolved_symbol.name);
+       void create_new_namespaces () {
+               foreach (var node in Node.new_namespaces) {
+                       if (node.symbol == null) {
+                               node.symbol = new Namespace (node.name, node.source_reference);
                        }
                }
-               return null;
        }
 
-       void postprocess_interfaces () {
-               foreach (var iface in interfaces) {
-                       /* Temporarily workaround G-I bug not adding GLib.Object prerequisite:
-                          ensure we have at least one instantiable prerequisite */
-                       bool has_instantiable_prereq = false;
-                       foreach (DataType prereq in iface.get_prerequisites ()) {
-                               Symbol sym = null;
-                               if (prereq is UnresolvedType) {
-                                       var unresolved_symbol = ((UnresolvedType) prereq).unresolved_symbol;
-                                       sym = resolve_symbol (iface.parent_symbol.scope, unresolved_symbol);
-                               } else {
-                                       sym = prereq.data_type;
-                               }
-                               if (sym is Class) {
-                                       has_instantiable_prereq = true;
-                                       break;
-                               }
+       void process_interface (Node iface_node) {
+               /* Temporarily workaround G-I bug not adding GLib.Object prerequisite:
+                  ensure we have at least one instantiable prerequisite */
+               Interface iface = (Interface) iface_node.symbol;
+               bool has_instantiable_prereq = false;
+               foreach (DataType prereq in iface.get_prerequisites ()) {
+                       Symbol sym = null;
+                       if (prereq is UnresolvedType) {
+                               var unresolved_symbol = ((UnresolvedType) prereq).unresolved_symbol;
+                               sym = resolve_symbol (iface_node.parent, unresolved_symbol);
+                       } else {
+                               sym = prereq.data_type;
                        }
-
-                       if (!has_instantiable_prereq) {
-                               iface.add_prerequisite (new ObjectType ((ObjectTypeSymbol) glib_ns.scope.lookup ("Object")));
+                       if (sym is Class) {
+                               has_instantiable_prereq = true;
+                               break;
                        }
                }
-       }
 
-       void postprocess_reparenting () {
-               foreach (UnresolvedSymbol target_unresolved_symbol in symbol_reparent_map.get_keys ()) {
-                       var target_symbol = resolve_symbol (context.root.scope, target_unresolved_symbol);
-                       if (target_symbol == null) {
-                               // create namespaces backward
-                               var sym = target_unresolved_symbol;
-                               var ns = new Namespace (sym.name, sym.source_reference);
-                               var result = ns;
-                               sym = sym.inner;
-                               while (sym != null) {
-                                       var res = resolve_symbol (context.root.scope, sym);
-                                       if (res != null && !(res is Namespace)) {
-                                               result = null;
-                                               break;
-                                       }
-                                       var parent = res as Namespace;
-                                       if (res == null) {
-                                               parent = new Namespace (sym.name, sym.source_reference);
-                                       }
-                                       if (parent.scope.lookup (ns.name) == null) {
-                                               parent.add_namespace (ns);
-                                       }
-                                       ns = parent;
-                                       sym = sym.inner;
-                               }
-                               if (result != null && sym == null && context.root.scope.lookup (ns.name) == null) {
-                                       // a new root namespace, helpful for a possible non-gobject gir?
-                                       context.root.add_namespace (ns);
-                               }
-                               target_symbol = result;
-                       }
-                       if (target_symbol == null) {
-                               Report.error (null, "unable to reparent into `%s'".printf (target_unresolved_symbol.to_string ()));
-                               continue;
-                       }
-                       var symbols = symbol_reparent_map[target_unresolved_symbol];
-                       foreach (var symbol in symbols) {
-                               add_symbol_to_container (target_symbol, symbol);
-                       }
+               if (!has_instantiable_prereq) {
+                       iface.add_prerequisite (new ObjectType ((ObjectTypeSymbol) glib_ns.scope.lookup ("Object")));
                }
        }
 
-       void postprocess_gtype_callbacks (Namespace ns) {
-               foreach (UnresolvedSymbol gtype_struct_for in gtype_callbacks.get_keys ()) {
-                       // parent symbol is the record, therefore use parent of parent symbol
-                       var gtype = resolve_symbol (ns.scope, gtype_struct_for) as ObjectTypeSymbol;
-                       if (gtype == null) {
-                               Report.error (null, "unknown symbol `%s' while postprocessing callbacks".printf (gtype_struct_for.name));
-                               continue;
+       void process_alias (Node alias) {
+               /* this is unfortunate because <alias> tag has no type information, thus we have
+                  to guess it from the base type */
+               DataType base_type = null;
+               Symbol type_sym = null;
+               bool simple_type = false;
+               if (alias.base_type is UnresolvedType) {
+                       base_type = alias.base_type;
+                       type_sym = resolve_symbol (alias.parent, ((UnresolvedType) base_type).unresolved_symbol);
+               } else if (alias.base_type is PointerType && ((PointerType) alias.base_type).base_type is VoidType) {
+                       // gpointer, if it's a struct make it a simpletype
+                       simple_type = true;
+               } else {
+                       base_type = alias.base_type;
+                       type_sym = base_type.data_type;
+               }
+
+               if (type_sym is Struct && ((Struct) type_sym).is_simple_type ()) {
+                       simple_type = true;
+               }
+
+               if (base_type == null || type_sym == null || type_sym is Struct) {
+                       var st = new Struct (alias.name, alias.source_reference);
+                       st.access = SymbolAccessibility.PUBLIC;
+                       if (base_type != null) {
+                               // threat target="none" as a new struct
+                               st.base_type = base_type;
                        }
-                       ArrayList<Delegate> callbacks = gtype_callbacks.get (gtype_struct_for);
-                       foreach (Delegate d in callbacks) {
-                               var symbol = gtype.scope.lookup (d.name);
-                               if (symbol == null) {
-                                       continue;
-                               } else if (symbol is Method)  {
-                                       var meth = (Method) symbol;
-                                       if (gtype is Class) {
-                                               meth.is_virtual = true;
-                                       } else if (gtype is Interface) {
-                                               meth.is_abstract = true;
+                       st.external = true;
+                       st.set_cname (alias.girdata["c:type"]);
+                       if (simple_type) {
+                               st.set_simple_type (true);
+                       }
+                       alias.symbol = st;
+               } else if (type_sym is Class) {
+                       var cl = new Class (alias.name, alias.source_reference);
+                       cl.access = SymbolAccessibility.PUBLIC;
+                       if (base_type != null) {
+                               cl.add_base_type (base_type);
+                       }
+                       cl.external = true;
+                       cl.set_cname (alias.girdata["c:type"]);
+                       alias.symbol = cl;
+               }
+       }
+
+       void process_callable (Node node) {
+               var s = node.symbol;
+               List<ParameterInfo> parameters = node.parameters;
+               Metadata metadata = node.metadata;
+
+               DataType return_type = null;
+               if (s is Method) {
+                       return_type = ((Method) s).return_type;
+               } else if (s is Delegate) {
+                       return_type = ((Delegate) s).return_type;
+               } else if (s is Signal) {
+                       return_type = ((Signal) s).return_type;
+               }
+
+               var array_length_idx = -1;
+               if (return_type is ArrayType && metadata.has_argument (ArgumentType.ARRAY_LENGTH_IDX)) {
+                       array_length_idx = metadata.get_integer (ArgumentType.ARRAY_LENGTH_IDX);
+                       parameters[array_length_idx].keep = false;
+                       node.array_length_parameters.add (array_length_idx);
+               } else if (return_type is VoidType && parameters.size > 0) {
+                       int n_out_parameters = 0;
+                       foreach (var info in parameters) {
+                               if (info.param.direction == ParameterDirection.OUT) {
+                                       n_out_parameters++;
+                               }
+                       }
+
+                       if (n_out_parameters == 1) {
+                               ParameterInfo last_param = parameters[parameters.size-1];
+                               if (last_param.param.direction == ParameterDirection.OUT) {
+                                       // use last out real-non-null-struct parameter as return type
+                                       if (last_param.param.variable_type is UnresolvedType) {
+                                               var st = resolve_symbol (node.parent, ((UnresolvedType) last_param.param.variable_type).unresolved_symbol) as Struct;
+                                               if (st != null && !st.is_simple_type () && !last_param.param.variable_type.nullable) {
+                                                       last_param.keep = false;
+                                                       return_type = last_param.param.variable_type.copy ();
+                                               }
                                        }
-                               } else if (symbol is Signal) {
-                                       var sig = (Signal) symbol;
-                                       sig.is_virtual = true;
-                                       assume_parameter_names (sig, d, true);
-                               } else if (symbol is Property) {
-                                       var prop = (Property) symbol;
-                                       prop.is_virtual = true;
-                               } else {
-                                       Report.error (get_current_src (), "unknown member type `%s' in `%s'".printf (d.name, gtype.name));
                                }
                        }
                }
-       }
 
-       void postprocess_aliases () {
-               /* this is unfortunate because <alias> tag has no type information, thus we have
-                  to guess it from the base type */
-               foreach (var alias in aliases) {
-                       DataType base_type = null;
-                       Symbol type_sym = null;
-                       bool simple_type = false;
-                       if (alias.base_type is UnresolvedType) {
-                               base_type = alias.base_type;
-                               type_sym = resolve_symbol (alias.parent_symbol.scope, ((UnresolvedType) base_type).unresolved_symbol);
-                       } else if (alias.base_type is PointerType && ((PointerType) alias.base_type).base_type is VoidType) {
-                               // gpointer, if it's a struct make it a simpletype
-                               simple_type = true;
+               int i = 0, j=1;
+
+               int last = -1;
+               foreach (ParameterInfo info in parameters) {
+                       if (s is Delegate && info.closure_idx == i) {
+                               var d = (Delegate) s;
+                               d.has_target = true;
+                               d.cinstance_parameter_position = (float) j - 0.1;
+                               info.keep = false;
+                       } else if (info.keep
+                                          && !node.array_length_parameters.contains (i)
+                                          && !node.closure_parameters.contains (i)
+                                          && !node.destroy_parameters.contains (i)) {
+                               info.vala_idx = (float) j;
+                               info.keep = true;
+
+                               /* interpolate for vala_idx between this and last*/
+                               float last_idx = 0.0F;
+                               if (last != -1) {
+                                       last_idx = parameters[last].vala_idx;
+                               }
+                               for (int k=last+1; k < i; k++) {
+                                       parameters[k].vala_idx =  last_idx + (((j - last_idx) / (i-last)) * (k-last));
+                               }
+                               last = i;
+                               j++;
                        } else {
-                               base_type = alias.base_type;
-                               type_sym = base_type.data_type;
+                               info.keep = false;
+                               // make sure that vala_idx is always set
+                               // the above if branch does not set vala_idx for
+                               // hidden parameters at the end of the parameter list
+                               info.vala_idx = (j - 1) + (i - last) * 0.1F;
                        }
+                       i++;
+               }
 
-                       if (type_sym is Struct && ((Struct) type_sym).is_simple_type ()) {
-                               simple_type = true;
-                       }
+               foreach (ParameterInfo info in parameters) {
+                       if (info.keep) {
 
-                       if (base_type == null || type_sym == null || type_sym is Struct) {
-                               var st = new Struct (alias.name, alias.source_reference);
-                               st.access = SymbolAccessibility.PUBLIC;
-                               if (base_type != null) {
-                                       // threat target="none" as a new struct
-                                       st.base_type = base_type;
-                               }
-                               st.external = true;
-                               if (alias.cname != null) {
-                                       st.set_cname (alias.cname);
+                               /* add_parameter sets carray_length_parameter_position and cdelegate_target_parameter_position
+                                  so do it first*/
+                               if (s is Method) {
+                                       ((Method) s).add_parameter (info.param);
+                               } else if (s is Delegate) {
+                                       ((Delegate) s).add_parameter (info.param);
+                               } else if (s is Signal) {
+                                       ((Signal) s).add_parameter (info.param);
                                }
-                               if (simple_type) {
-                                       st.set_simple_type (true);
+
+                               if (info.array_length_idx != -1) {
+                                       if ((info.array_length_idx) >= parameters.size) {
+                                               Report.error (get_current_src (), "invalid array_length index");
+                                               continue;
+                                       }
+                                       set_array_ccode (info.param, parameters[info.array_length_idx]);
                                }
-                               add_symbol_to_container (alias.parent_symbol, st);
-                       } else if (type_sym is Class) {
-                               var cl = new Class (alias.name, alias.source_reference);
-                               cl.access = SymbolAccessibility.PUBLIC;
-                               if (base_type != null) {
-                                       cl.add_base_type (base_type);
+
+                               if (info.closure_idx != -1) {
+                                       if ((info.closure_idx) >= parameters.size) {
+                                               Report.error (get_current_src (), "invalid closure index");
+                                               continue;
+                                       }
+                                       info.param.cdelegate_target_parameter_position = parameters[info.closure_idx].vala_idx;
                                }
-                               cl.external = true;
-                               if (alias.cname != null) {
-                                       cl.set_cname (alias.cname);
+                               if (info.destroy_idx != -1) {
+                                       if (info.destroy_idx >= parameters.size) {
+                                               Report.error (get_current_src (), "invalid destroy index");
+                                               continue;
+                                       }
+                                       info.param.cdestroy_notify_parameter_position = parameters[info.destroy_idx].vala_idx;
                                }
-                               add_symbol_to_container (alias.parent_symbol, cl);
                        }
                }
+               if (array_length_idx != -1) {
+                       if (array_length_idx >= parameters.size) {
+                               Report.error (get_current_src (), "invalid array_length index");
+                       } else {
+                               set_array_ccode (s, parameters[array_length_idx]);
+                       }
+               } else if (return_type is ArrayType) {
+                       if (s is Method) {
+                               var m = (Method) s;
+                               m.no_array_length = true;
+                               m.array_null_terminated = true;
+                       } else if (s is Delegate) {
+                               var d = (Delegate) s;
+                               d.no_array_length = true;
+                               d.array_null_terminated = true;
+                       }
+               }
+
+               if (s is Method) {
+                       ((Method) s).return_type = return_type;
+               } else if (s is Delegate) {
+                       ((Delegate) s).return_type = return_type;
+               } else if (s is Signal) {
+                       ((Signal) s).return_type = return_type;
+               }
        }
 
-       void find_static_method_parent (string cname, Symbol current, ref Symbol best, ref double match, double match_char) {
+       void find_static_method_parent (string cname, Symbol current, ref Symbol best, ref int match, int match_char) {
                var old_best = best;
-               if (current.scope.get_symbol_table () != null) {
+               if (current is Namespace && current.scope.get_symbol_table () != null) {
                        foreach (var child in current.scope.get_symbol_table().get_values ()) {
-                               if (child is Struct || child is ObjectTypeSymbol || child is Namespace) {
+                               if (is_container (child) && cname.has_prefix (child.get_lower_case_cprefix ())) {
                                        find_static_method_parent (cname, child, ref best, ref match, match_char);
                                }
                        }
@@ -2779,207 +2831,185 @@ public class Vala.GirParser : CodeVisitor {
                        return;
                }
 
-               var current_cprefix = current.get_lower_case_cprefix ();
-               if (cname.has_prefix (current_cprefix)) {
-                       var current_match = match_char * current_cprefix.length;
-                       if (current_match > match) {
-                               match = current_match;
-                               best = current;
-                       }
+               var current_match = match_char * current.get_lower_case_cprefix().length;
+               if (current_match > match) {
+                       match = current_match;
+                       best = current;
                }
        }
 
-       void postprocess_callables () {
-               foreach (var callable in callable_info_list) {
-                       var s = callable.symbol;
-                       List<ParameterInfo> parameters = callable.parameters;
-                       Metadata metadata = callable.metadata;
-
-                       DataType return_type = null;
-                       if (s is Method) {
-                               return_type = ((Method) s).return_type;
-                       } else if (s is Delegate) {
-                               return_type = ((Delegate) s).return_type;
-                       } else if (s is Signal) {
-                               return_type = ((Signal) s).return_type;
-                       }
-
-                       var array_length_idx = -1;
-                       if (return_type is ArrayType && metadata.has_argument (ArgumentType.ARRAY_LENGTH_IDX)) {
-                               array_length_idx = metadata.get_integer (ArgumentType.ARRAY_LENGTH_IDX);
-                               parameters[array_length_idx].keep = false;
-                               callable.array_length_parameters.add (array_length_idx);
-                       } else if (return_type is VoidType && parameters.size > 0) {
-                               int n_out_parameters = 0;
-                               foreach (var info in parameters) {
-                                       if (info.param.direction == ParameterDirection.OUT) {
-                                               n_out_parameters++;
-                                       }
-                               }
-
-                               if (n_out_parameters == 1) {
-                                       ParameterInfo last_param = parameters[parameters.size-1];
-                                       if (last_param.param.direction == ParameterDirection.OUT) {
-                                               // use last out real-non-null-struct parameter as return type
-                                               if (last_param.param.variable_type is UnresolvedType) {
-                                                       var st = resolve_symbol (s.parent_symbol.scope, ((UnresolvedType) last_param.param.variable_type).unresolved_symbol) as Struct;
-                                                       if (st != null && !st.is_simple_type () && !last_param.param.variable_type.nullable) {
-                                                               last_param.keep = false;
-                                                               return_type = last_param.param.variable_type.copy ();
-                                                       }
-                                               }
-                                       }
+       void process_namespace_method (Namespace ns, Method method) {
+               /* transform static methods into instance methods if possible.
+                  In most of cases this is a .gir fault we are going to fix */
+               var ns_cprefix = ns.get_lower_case_cprefix ();
+               var cname = method.get_cname ();
+
+               Parameter first_param = null;
+               if (method.get_parameters ().size > 0) {
+                       first_param = method.get_parameters()[0];
+               }
+               if (first_param != null && first_param.variable_type is UnresolvedType) {
+                       // check if it's a missed instance method (often happens for structs)
+                       var sym = ((UnresolvedType) first_param.variable_type).unresolved_symbol;
+                       Symbol parent = ns;
+                       if (sym.inner != null) {
+                               parent = context.root.scope.lookup (sym.inner.name);
+                       }
+                       // ensure we don't get out of the GIR namespace
+                       if (parent == ns) {
+                               parent = parent.scope.lookup (sym.name);
+                       }
+                       if (parent != null && is_container (parent) && cname.has_prefix (parent.get_lower_case_cprefix ())) {
+                               // instance method
+                               var new_name = method.name.substring (parent.get_lower_case_cprefix().length - ns_cprefix.length);
+                               if (parent.scope.lookup (new_name) == null) {
+                                       method.name = new_name;
+                                       method.get_parameters().remove_at (0);
+                                       method.binding = MemberBinding.INSTANCE;
+                                       add_symbol_to_container (parent, method);
+                               } else {
+                                       ns.add_method (method);
                                }
+                               return;
                        }
+               }
 
-                       int i = 0, j=1;
-
-                       int last = -1;
-                       foreach (ParameterInfo info in parameters) {
-                               if (s is Delegate && info.closure_idx == i) {
-                                       var d = (Delegate) s;
-                                       d.has_target = true;
-                                       d.cinstance_parameter_position = (float) j - 0.1;
-                                       info.keep = false;
-                               } else if (info.keep
-                                                  && !callable.array_length_parameters.contains (i)
-                                                  && !callable.closure_parameters.contains (i)
-                                                  && !callable.destroy_parameters.contains (i)) {
-                                       info.vala_idx = (float) j;
-                                       info.keep = true;
-
-                                       /* interpolate for vala_idx between this and last*/
-                                       float last_idx = 0.0F;
-                                       if (last != -1) {
-                                               last_idx = parameters[last].vala_idx;
-                                       }
-                                       for (int k=last+1; k < i; k++) {
-                                               parameters[k].vala_idx =  last_idx + (((j - last_idx) / (i-last)) * (k-last));
-                                       }
-                                       last = i;
-                                       j++;
-                               } else {
-                                       info.keep = false;
-                                       // make sure that vala_idx is always set
-                                       // the above if branch does not set vala_idx for
-                                       // hidden parameters at the end of the parameter list
-                                       info.vala_idx = (j - 1) + (i - last) * 0.1F;
-                               }
-                               i++;
-                       }
-
-                       foreach (ParameterInfo info in parameters) {
-                               if (info.keep) {
-
-                                       /* add_parameter sets carray_length_parameter_position and cdelegate_target_parameter_position
-                                          so do it first*/
-                                       if (s is Method) {
-                                               ((Method) s).add_parameter (info.param);
-                                       } else if (s is Delegate) {
-                                               ((Delegate) s).add_parameter (info.param);
-                                       } else if (s is Signal) {
-                                               ((Signal) s).add_parameter (info.param);
-                                       }
-
-                                       if (info.array_length_idx != -1) {
-                                               if ((info.array_length_idx) >= parameters.size) {
-                                                       Report.error (get_current_src (), "invalid array_length index");
-                                                       continue;
-                                               }
-                                               set_array_ccode (info.param, parameters[info.array_length_idx]);
-                                       }
+               int match = 0;
+               Symbol parent = ns;
+               find_static_method_parent (cname, ns, ref parent, ref match, cname.length);
+               var new_name = method.name.substring (parent.get_lower_case_cprefix().length - ns_cprefix.length);
+               if (parent.scope.lookup (new_name) == null) {
+                       method.name = new_name;
+                       add_symbol_to_container (parent, method);
+               } else {
+                       ns.add_method (method);
+               }
+       }
 
-                                       if (info.closure_idx != -1) {
-                                               if ((info.closure_idx) >= parameters.size) {
-                                                       Report.error (get_current_src (), "invalid closure index");
-                                                       continue;
-                                               }
-                                               info.param.cdelegate_target_parameter_position = parameters[info.closure_idx].vala_idx;
-                                       }
-                                       if (info.destroy_idx != -1) {
-                                               if (info.destroy_idx >= parameters.size) {
-                                                       Report.error (get_current_src (), "invalid destroy index");
-                                                       continue;
-                                               }
-                                               info.param.cdestroy_notify_parameter_position = parameters[info.destroy_idx].vala_idx;
-                                       }
-                               }
+       void process_virtual_method_field (Node node, Delegate d, UnresolvedSymbol gtype_struct_for) {
+               var gtype_node = resolve_node (node.parent, gtype_struct_for);
+               if (gtype_node == null || !(gtype_node.symbol is ObjectTypeSymbol)) {
+                       Report.error (gtype_struct_for.source_reference, "Unknown symbol `%s' for virtual method field `%s'".printf (gtype_struct_for.to_string (), node.to_string ()));
+               }
+               var gtype = (ObjectTypeSymbol) gtype_node.symbol;
+               var nodes = gtype_node.lookup_all (d.name);
+               if (nodes == null) {
+                       return;
+               }
+               foreach (var n in nodes) {
+                       if (node != n) {
+                               n.process (this);
                        }
-                       if (array_length_idx != -1) {
-                               if (array_length_idx >= parameters.size) {
-                                       Report.error (get_current_src (), "invalid array_length index");
-                               } else {
-                                       set_array_ccode (s, parameters[array_length_idx]);
-                               }
-                       } else if (return_type is ArrayType) {
-                               if (s is Method) {
-                                       var m = (Method) s;
-                                       m.no_array_length = true;
-                                       m.array_null_terminated = true;
-                               } else if (s is Delegate) {
-                                       var d = (Delegate) s;
-                                       d.no_array_length = true;
-                                       d.array_null_terminated = true;
-                               }
+               }
+               foreach (var n in nodes) {
+                       if (n.merged) {
+                               continue;
                        }
-
-                       if (s is Method) {
-                               ((Method) s).return_type = return_type;
-                       } else if (s is Delegate) {
-                               ((Delegate) s).return_type = return_type;
-                       } else if (s is Signal) {
-                               ((Signal) s).return_type = return_type;
+                       var sym = n.symbol;
+                       if (sym is Signal) {
+                               var sig = (Signal) sym;
+                               sig.is_virtual = true;
+                               assume_parameter_names (sig, d, true);
+                       } else if (sym is Property) {
+                               var prop = (Property) sym;
+                               prop.is_virtual = true;
+                       } else if (sym is Method)  {
+                               var meth = (Method) sym;
+                               if (gtype is Class) {
+                                       meth.is_virtual = true;
+                               } else if (gtype is Interface) {
+                                       meth.is_abstract = true;
+                               }
+                       } else {
+                               Report.error (get_current_src (), "Unknown type for member `%s'".printf (node.to_string ()));
                        }
                }
        }
 
-       void postprocess_namespace_methods () {
-               /* transform static methods into instance methods if possible.
-                  In most of cases this is a .gir fault we are going to fix */
-               foreach (var ns in namespace_methods.get_keys ()) {
-                       var ns_cprefix = ns.get_lower_case_cprefix ();
-                       var methods = namespace_methods[ns];
-                       foreach (var method in methods) {
-                               if (method.parent_symbol != null) {
-                                       // fixed earlier by metadata
-                                       continue;
+       void process_async_method (Node node) {
+               var m = (Method) node.symbol;
+               string finish_method_base;
+               if (m.name.has_suffix ("_async")) {
+                       finish_method_base = m.name.substring (0, m.name.length - "_async".length);
+               } else {
+                       finish_method_base = m.name;
+               }
+               var finish_method_node = node.parent.lookup (finish_method_base + "_finish");
+
+               // check if the method is using non-standard finish method name
+               if (finish_method_node == null) {
+                       var method_cname = m.get_finish_cname ();
+                       foreach (var n in node.parent.members) {
+                               if (n.symbol is Method && ((Method) n.symbol).get_cname () == method_cname) {
+                                       finish_method_node = n;
+                                       break;
                                }
+                       }
+               }
 
-                               var cname = method.get_cname ();
-
-                               Parameter first_param = null;
-                               if (method.get_parameters ().size > 0) {
-                                       first_param = method.get_parameters()[0];
-                               }
-                               if (first_param != null && first_param.variable_type is UnresolvedType) {
-                                       // check if it's a missed instance method (often happens for structs)
-                                       var parent = resolve_symbol (ns.scope, ((UnresolvedType) first_param.variable_type).unresolved_symbol);
-                                       if (parent != null && (parent is Struct || parent is ObjectTypeSymbol || parent is Namespace)
-                                               && cname.has_prefix (parent.get_lower_case_cprefix ())) {
-                                               // instance method
-                                               var new_name = method.name.substring (parent.get_lower_case_cprefix().length - ns_cprefix.length);
-                                               if (parent.scope.lookup (new_name) == null) {
-                                                       method.name = new_name;
-                                                       method.get_parameters().remove_at (0);
-                                                       method.binding = MemberBinding.INSTANCE;
-                                                       add_symbol_to_container (parent, method);
-                                               } else {
-                                                       ns.add_method (method);
+               if (finish_method_node != null && finish_method_node.symbol is Method) {
+                       finish_method_node.process (this);
+                       var finish_method = (Method) finish_method_node.symbol;
+                       Method method;
+                       if (finish_method is CreationMethod) {
+                               method = new CreationMethod (((CreationMethod) finish_method).class_name, null, m.source_reference);
+                               method.access = m.access;
+                               method.binding = m.binding;
+                               method.external = true;
+                               method.coroutine = true;
+                               method.has_construct_function = finish_method.has_construct_function;
+                               method.attributes = m.attributes.copy ();
+                               method.set_cname (m.get_cname ());
+                               if (finish_method_base == "new") {
+                                       method.name = null;
+                               } else if (finish_method_base.has_prefix ("new_")) {
+                                       method.name = m.name.substring ("new_".length);
+                               }
+                               foreach (var param in m.get_parameters ()) {
+                                       method.add_parameter (param);
+                               }
+                               node.symbol = method;
+                       } else {
+                               method = m;
+                               method.return_type = finish_method.return_type.copy ();
+                               method.no_array_length = finish_method.no_array_length;
+                               method.array_null_terminated = finish_method.array_null_terminated;
+                               // put cancellable as last parameter
+                               Parameter cancellable = null;
+                               foreach (var param in method.get_parameters ()) {
+                                       if (param.name == "cancellable" && param.variable_type.to_qualified_string () == "GLib.Cancellable?" && param.direction == ParameterDirection.IN) {
+                                               cancellable = param;
+                                               cancellable.initializer = new NullLiteral (param.source_reference);
+                                       } else if (cancellable != null) {
+                                               param.cparameter_position--;
+                                               param.carray_length_parameter_position--;
+                                               param.cdelegate_target_parameter_position--;
+                                               param.cdestroy_notify_parameter_position--;
+                                       }
+                               }
+                               if (cancellable != null) {
+                                       method.get_parameters().remove (cancellable);
+                                       method.scope.remove (cancellable.name);
+                               }
+                               foreach (var param in finish_method.get_parameters ()) {
+                                       if (param.direction == ParameterDirection.OUT) {
+                                               var async_param = param.copy ();
+                                               if (method.scope.lookup (param.name) != null) {
+                                                       // parameter name conflict
+                                                       async_param.name += "_out";
                                                }
-                                               continue;
+                                               method.add_parameter (async_param);
                                        }
                                }
+                               if (cancellable != null) {
+                                       method.add_parameter (cancellable);
+                               }
 
-                               double match = 0;
-                               Symbol parent = ns;
-                               find_static_method_parent (cname, ns, ref parent, ref match, 1.0/cname.length);
-                               var new_name = method.name.substring (parent.get_lower_case_cprefix().length - ns_cprefix.length);
-                               if (parent.scope.lookup (new_name) == null) {
-                                       method.name = new_name;
-                                       add_symbol_to_container (parent, method);
-                               } else {
-                                       ns.add_method (method);
+                               foreach (DataType error_type in finish_method.get_error_types ()) {
+                                       method.add_error_type (error_type.copy ());
                                }
+                               finish_method_node.processed = true;
+                               finish_method_node.merged = true;
                        }
                }
        }