LCOV - code coverage report
Current view: top level - codegen - valagirwriter.vala (source / functions) Coverage Total Hit
Test: vala 0.57.0.298-a8cae1 Lines: 93.2 % 1140 1062
Test Date: 2024-04-25 11:34:36 Functions: - 0 0

            Line data    Source code
       1              : /* valagirwriter.vala
       2              :  *
       3              :  * Copyright (C) 2008-2012  Jürg Billeter
       4              :  *
       5              :  * This library is free software; you can redistribute it and/or
       6              :  * modify it under the terms of the GNU Lesser General Public
       7              :  * License as published by the Free Software Foundation; either
       8              :  * version 2.1 of the License, or (at your option) any later version.
       9              : 
      10              :  * This library is distributed in the hope that it will be useful,
      11              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13              :  * Lesser General Public License for more details.
      14              : 
      15              :  * You should have received a copy of the GNU Lesser General Public
      16              :  * License along with this library; if not, write to the Free Software
      17              :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
      18              :  *
      19              :  * Author:
      20              :  *      Jürg Billeter <j@bitron.ch>
      21              :  */
      22              : 
      23              : using GLib;
      24              : 
      25              : /**
      26              :  * Code visitor generating .gir file for the public interface.
      27              :  */
      28           15 : public class Vala.GIRWriter : CodeVisitor {
      29            3 :         private CodeContext context;
      30            3 :         private string directory;
      31            3 :         private string gir_namespace;
      32            3 :         private string gir_version;
      33            3 :         private string gir_shared_library;
      34              : 
      35            8 :         protected virtual string? get_interface_comment (Interface iface) {
      36              :                 return null;
      37              :         }
      38              : 
      39            8 :         protected virtual string? get_struct_comment (Struct st) {
      40              :                 return null;
      41              :         }
      42              : 
      43           14 :         protected virtual string? get_enum_comment (Enum en) {
      44              :                 return null;
      45              :         }
      46              : 
      47           30 :         protected virtual string? get_class_comment (Class c) {
      48              :                 return null;
      49              :         }
      50              : 
      51           14 :         protected virtual string? get_error_code_comment (ErrorCode ecode) {
      52              :                 return null;
      53              :         }
      54              : 
      55           26 :         protected virtual string? get_enum_value_comment (EnumValue ev) {
      56              :                 return null;
      57              :         }
      58              : 
      59           18 :         protected virtual string? get_constant_comment (Constant c) {
      60              :                 return null;
      61              :         }
      62              : 
      63            6 :         protected virtual string? get_error_domain_comment (ErrorDomain edomain) {
      64              :                 return null;
      65              :         }
      66              : 
      67           34 :         protected virtual string? get_field_comment (Field f) {
      68              :                 return null;
      69              :         }
      70              : 
      71           10 :         protected virtual string? get_delegate_comment (Delegate cb) {
      72              :                 return null;
      73              :         }
      74              : 
      75          272 :         protected virtual string? get_method_comment (Method m) {
      76              :                 return null;
      77              :         }
      78              : 
      79           10 :         protected virtual string? get_property_comment (Property prop) {
      80              :                 return null;
      81              :         }
      82              : 
      83           10 :         protected virtual string? get_delegate_return_comment (Delegate cb) {
      84              :                 return null;
      85              :         }
      86              : 
      87            8 :         protected virtual string? get_signal_return_comment (Signal sig) {
      88              :                 return null;
      89              :         }
      90              : 
      91          272 :         protected virtual string? get_method_return_comment (Method m) {
      92              :                 return null;
      93              :         }
      94              : 
      95            8 :         protected virtual string? get_signal_comment (Signal sig) {
      96              :                 return null;
      97              :         }
      98              : 
      99          358 :         protected virtual string? get_parameter_comment (Parameter param) {
     100              :                 return null;
     101              :         }
     102              : 
     103            6 :         StringBuilder buffer = new StringBuilder();
     104            3 :         FileStream stream;
     105            6 :         Vala.HashSet<Namespace> unannotated_namespaces = new Vala.HashSet<Namespace>();
     106            6 :         Vala.HashSet<Namespace> our_namespaces = new Vala.HashSet<Namespace>();
     107            6 :         Vala.ArrayList<Vala.Symbol> hierarchy = new Vala.ArrayList<Vala.Symbol>();
     108            6 :         Vala.ArrayList<Vala.CodeNode> deferred = new Vala.ArrayList<Vala.CodeNode>();
     109              : 
     110              :         int indent;
     111              : 
     112            3 :         private TypeSymbol gobject_type;
     113            3 :         private TypeSymbol ginitiallyunowned_type;
     114            3 :         private TypeSymbol gtypeinterface_type;
     115            3 :         private TypeSymbol gtypeinstance_type;
     116            3 :         private TypeSymbol gtype_type;
     117              : 
     118           90 :         private struct GIRNamespace {
     119          533 :                 public GIRNamespace (string ns, string version) {
     120         1599 :                         this.ns = ns; this.version = version;
     121              :                 }
     122         1084 :                 public string ns;
     123         1084 :                 public string version;
     124         1179 :                 public bool equal (GIRNamespace g) {
     125         1179 :                         return ((ns == g.ns) && (version == g.version));
     126              :                 }
     127              : 
     128           12 :                 public static GIRNamespace for_symbol (Symbol sym) {
     129           24 :                         while (sym.parent_symbol != null && sym.parent_symbol.name != null) {
     130           12 :                                 sym = sym.parent_symbol;
     131              :                         }
     132           12 :                         assert (sym is Namespace);
     133           12 :                         string gir_namespace = sym.get_attribute_string ("CCode", "gir_namespace");
     134           12 :                         string gir_version = sym.get_attribute_string ("CCode", "gir_version");
     135           12 :                         return GIRNamespace (gir_namespace, gir_version);
     136              :                 }
     137              :         }
     138              : 
     139            6 :         private ArrayList<GIRNamespace?> externals = new ArrayList<GIRNamespace?> ((EqualFunc<GIRNamespace>) GIRNamespace.equal);
     140              : 
     141            3 :         public void write_includes() {
     142           19 :                 foreach (var i in externals) {
     143            9 :                         if (i.ns != this.gir_namespace) {
     144            7 :                                 write_indent_stream ();
     145            7 :                                 stream.printf ("<include name=\"%s\" version=\"%s\"/>\n", i.ns, i.version);
     146              :                         }
     147              :                 }
     148              :         }
     149              : 
     150              : 
     151              :         /**
     152              :          * Writes the public interface of the specified code context into the
     153              :          * specified file.
     154              :          *
     155              :          * @param context      a code context
     156              :          * @param gir_filename a relative or absolute filename
     157              :          */
     158            6 :         public void write_file (CodeContext context, string directory, string gir_filename, string gir_namespace, string gir_version, string package, string? gir_shared_library = null) {
     159            3 :                 this.context = context;
     160            6 :                 this.directory = directory;
     161            6 :                 this.gir_namespace = gir_namespace;
     162            6 :                 this.gir_version = gir_version;
     163            6 :                 this.gir_shared_library = gir_shared_library;
     164              : 
     165         2158 :                 var root_symbol = context.root;
     166            3 :                 var glib_ns = root_symbol.scope.lookup ("GLib");
     167            3 :                 gobject_type = (TypeSymbol) glib_ns.scope.lookup ("Object");
     168            3 :                 ginitiallyunowned_type = (TypeSymbol) glib_ns.scope.lookup ("InitiallyUnowned");
     169            3 :                 gtypeinterface_type = (TypeSymbol) glib_ns.scope.lookup ("TypeInterface");
     170            3 :                 gtypeinstance_type = (TypeSymbol) glib_ns.scope.lookup ("TypeInstance");
     171            3 :                 gtype_type = (TypeSymbol) glib_ns.scope.lookup ("Type");
     172              : 
     173            3 :                 write_package (package);
     174              : 
     175              :                 // Make sure to initialize external files with their gir_namespace/version
     176           29 :                 foreach (var file in context.get_source_files ()) {
     177           13 :                         file.accept (this);
     178              :                 }
     179              : 
     180            3 :                 context.accept (this);
     181              : 
     182            3 :                 indent--;
     183            3 :                 buffer.append_printf ("</repository>\n");
     184              : 
     185            3 :                 string filename = "%s%c%s".printf (directory, Path.DIR_SEPARATOR, gir_filename);
     186            3 :                 var file_exists = FileUtils.test (filename, FileTest.EXISTS);
     187            3 :                 var temp_filename = "%s.valatmp".printf (filename);
     188              : 
     189            3 :                 if (file_exists) {
     190            0 :                         stream = FileStream.open (temp_filename, "w");
     191              :                 } else {
     192            3 :                         stream = FileStream.open (filename, "w");
     193              :                 }
     194              : 
     195            3 :                 if (stream == null) {
     196            0 :                         Report.error (null, "unable to open `%s' for writing", filename);
     197            0 :                         this.context = null;
     198            0 :                         return;
     199              :                 }
     200              : 
     201            3 :                 stream.printf ("<?xml version=\"1.0\"?>\n");
     202              : 
     203            6 :                 var header = context.version_header ?
     204            0 :                         "<!-- %s generated by %s %s, do not modify. -->".printf (Path.get_basename (filename), Environment.get_prgname (), Vala.BUILD_VERSION) :
     205            3 :                         "<!-- %s generated by %s, do not modify. -->".printf (Path.get_basename (filename), Environment.get_prgname ());
     206            3 :                 stream.printf ("%s\n", header);
     207              : 
     208            3 :                 stream.printf ("<repository version=\"1.2\"");
     209            3 :                 stream.printf (" xmlns=\"http://www.gtk.org/introspection/core/1.0\"");
     210            3 :                 stream.printf (" xmlns:c=\"http://www.gtk.org/introspection/c/1.0\"");
     211            3 :                 stream.printf (" xmlns:glib=\"http://www.gtk.org/introspection/glib/1.0\"");
     212            3 :                 stream.printf (">\n");
     213            3 :                 indent++;
     214              : 
     215            3 :                 write_includes();
     216            3 :                 indent--;
     217              : 
     218            3 :                 stream.puts (buffer.str);
     219            3 :                 stream = null;
     220              : 
     221            3 :                 if (file_exists) {
     222            0 :                         var changed = true;
     223              : 
     224            0 :                         try {
     225            0 :                                 var old_file = new MappedFile (filename, false);
     226            0 :                                 var new_file = new MappedFile (temp_filename, false);
     227            0 :                                 var len = old_file.get_length ();
     228            0 :                                 if (len == new_file.get_length ()) {
     229            0 :                                         if (Memory.cmp (old_file.get_contents (), new_file.get_contents (), len) == 0) {
     230            0 :                                                 changed = false;
     231              :                                         }
     232              :                                 }
     233            0 :                                 old_file = null;
     234            0 :                                 new_file = null;
     235              :                         } catch (FileError e) {
     236              :                                 // assume changed if mmap comparison doesn't work
     237              :                         }
     238              : 
     239            0 :                         if (changed) {
     240            0 :                                 FileUtils.rename (temp_filename, filename);
     241              :                         } else {
     242            0 :                                 FileUtils.unlink (temp_filename);
     243              :                         }
     244              :                 }
     245              : 
     246            6 :                 foreach (var ns in unannotated_namespaces) {
     247            0 :                         if (!our_namespaces.contains(ns)) {
     248            0 :                                 Report.warning (ns.source_reference, "Namespace `%s' does not have a GIR namespace and version annotation", ns.name);
     249              :                         }
     250              :                 }
     251           12 :                 foreach (var ns in our_namespaces) {
     252            3 :                         ns.source_reference.file.gir_namespace = gir_namespace;
     253            3 :                         ns.source_reference.file.gir_version = gir_version;
     254              :                 }
     255              : 
     256            3 :                 if (our_namespaces.size == 0) {
     257            0 :                         Report.error (null, "No suitable namespace found to export for GIR");
     258              :                 }
     259              : 
     260            3 :                 this.context = null;
     261              :         }
     262              : 
     263          812 :         private void write_doc (string? comment, Comment? symbol = null) {
     264          812 :                 if (comment != null) {
     265            0 :                         write_indent ();
     266            0 :                         if (symbol != null) {
     267            0 :                                 var filename = symbol.source_reference.file.get_relative_filename();
     268            0 :                                 var line = symbol.source_reference.begin.line;
     269            0 :                                 var column = symbol.source_reference.begin.column;
     270              : 
     271            0 :                                 buffer.append_printf ("<doc xml:space=\"preserve\" filename=\"%s\" line=\"%d\" column=\"%d\">", filename, line, column);
     272              :                         } else {
     273            0 :                                 buffer.append ("<doc xml:space=\"preserve\">");
     274              :                         }
     275            0 :                         buffer.append (comment);
     276            0 :                         buffer.append ("</doc>\n");
     277              :                 }
     278              :         }
     279              : 
     280            3 :         private void write_package (string package) {
     281            3 :                 write_indent ();
     282            3 :                 buffer.append_printf ("<package name=\"%s\"/>\n", package);
     283              :         }
     284              : 
     285            6 :         private void write_c_includes (Namespace ns) {
     286              :                 // Collect C header filenames
     287            3 :                 Set<string> header_filenames = new HashSet<string> (str_hash, str_equal);
     288           15 :                 foreach (unowned string c_header_filename in get_ccode_header_filenames (ns).split (",")) {
     289            3 :                         header_filenames.add (c_header_filename);
     290              :                 }
     291          122 :                 foreach (Symbol symbol in ns.scope.get_symbol_table ().get_values ()) {
     292           58 :                         if (symbol.external_package) {
     293            0 :                                 continue;
     294              :                         }
     295          290 :                         foreach (unowned string c_header_filename in get_ccode_header_filenames (symbol).split (",")) {
     296           58 :                                 header_filenames.add (c_header_filename);
     297              :                         }
     298              :                 }
     299              : 
     300              :                 // Generate c:include tags
     301            6 :                 foreach (string c_header_filename in header_filenames) {
     302            3 :                         write_c_include (c_header_filename);
     303              :                 }
     304              :         }
     305              : 
     306            3 :         private void write_c_include (string name) {
     307            3 :                 write_indent ();
     308            3 :                 buffer.append_printf ("<c:include name=\"%s\"/>\n", name);
     309              :         }
     310              : 
     311           26 :         public override void visit_source_file (SourceFile source_file) {
     312           26 :                 if (source_file.file_type != SourceFileType.PACKAGE) {
     313              :                         return;
     314              :                 }
     315              : 
     316              :                 // Populate gir_namespace/version of source-file like in Namespace.check()
     317        18144 :                 foreach (var node in source_file.get_nodes ()) {
     318         9070 :                         if (node is Namespace && ((Namespace) node).parent_symbol == context.root) {
     319            8 :                                 var a = node.get_attribute ("CCode");
     320           16 :                                 if (a != null && a.has_argument ("gir_namespace")) {
     321            8 :                                         var new_gir = a.get_string ("gir_namespace");
     322            8 :                                         var old_gir = source_file.gir_namespace;
     323            8 :                                         if (old_gir != null && old_gir != new_gir) {
     324            1 :                                                 source_file.gir_ambiguous = true;
     325              :                                         }
     326            8 :                                         source_file.gir_namespace = new_gir;
     327              :                                 }
     328            8 :                                 if (a != null && a.has_argument ("gir_version")) {
     329            8 :                                         source_file.gir_version = a.get_string ("gir_version");
     330              :                                 }
     331            8 :                                 break;
     332              :                         }
     333              :                 }
     334              :         }
     335              : 
     336           17 :         public override void visit_namespace (Namespace ns) {
     337           14 :                 if (ns.external_package) {
     338              :                         return;
     339              :                 }
     340              : 
     341            8 :                 if (!is_visibility (ns)) {
     342              :                         return;
     343              :                 }
     344              : 
     345            8 :                 if (ns.name == null)  {
     346              :                         // global namespace
     347            3 :                         hierarchy.insert (0, ns);
     348            3 :                         ns.accept_children (this);
     349            3 :                         hierarchy.remove_at (0);
     350            3 :                         return;
     351              :                 }
     352              : 
     353            5 :                 if (ns.parent_symbol.name != null) {
     354            2 :                         ns.accept_children (this);
     355            2 :                         return;
     356              :                 }
     357              : 
     358            3 :                 if (our_namespaces.size > 0) {
     359            0 :                         Report.error (ns.source_reference, "Secondary top-level namespace `%s' is not supported by GIR format", ns.name);
     360            0 :                         return;
     361              :                 }
     362              : 
     363              :                 // Use given gir_namespace and gir_version for our top-level namespace
     364            3 :                 var old_gir_namespace = ns.get_attribute_string ("CCode", "gir_namespace");
     365            3 :                 var old_gir_version = ns.get_attribute_string ("CCode", "gir_version");
     366            3 :                 if ((old_gir_namespace != null && old_gir_namespace != gir_namespace)
     367            3 :                     || (old_gir_version != null && old_gir_version != gir_version)) {
     368            0 :                         Report.warning (ns.source_reference, "Replace conflicting CCode.gir_* attributes for namespace `%s'", ns.name);
     369              :                 }
     370            3 :                 ns.set_attribute_string ("CCode", "gir_namespace", gir_namespace);
     371            3 :                 ns.set_attribute_string ("CCode", "gir_version", gir_version);
     372              : 
     373            3 :                 write_c_includes (ns);
     374              : 
     375            3 :                 write_indent ();
     376            3 :                 buffer.append_printf ("<namespace name=\"%s\" version=\"%s\"", gir_namespace, gir_version);
     377            3 :                 string? cprefix = get_ccode_prefix (ns);
     378            3 :                 if (gir_shared_library != null) {
     379            1 :                         buffer.append_printf(" shared-library=\"%s\"", gir_shared_library);
     380              :                 }
     381            3 :                 if (cprefix != null) {
     382            3 :                         buffer.append_printf (" c:prefix=\"%s\"", cprefix);
     383            3 :                         buffer.append_printf (" c:identifier-prefixes=\"%s\"", cprefix);
     384              :                 }
     385            3 :                 string? csymbol_prefix = get_ccode_lower_case_suffix (ns);
     386            3 :                 if (csymbol_prefix != null) {
     387            3 :                         buffer.append_printf (" c:symbol-prefixes=\"%s\"", csymbol_prefix);
     388              :                 }
     389            3 :                 buffer.append_printf (">\n");
     390            3 :                 indent++;
     391              : 
     392            3 :                 hierarchy.insert (0, ns);
     393            3 :                 ns.accept_children (this);
     394            3 :                 hierarchy.remove_at (0);
     395              : 
     396            3 :                 indent--;
     397            3 :                 write_indent ();
     398            3 :                 buffer.append_printf ("</namespace>\n");
     399            3 :                 our_namespaces.add(ns);
     400              : 
     401            3 :                 visit_deferred ();
     402              :         }
     403              : 
     404          284 :         private void write_symbol_attributes (Symbol symbol) {
     405          284 :                 if (!is_introspectable (symbol)) {
     406           33 :                         buffer.append_printf (" introspectable=\"0\"");
     407              :                 }
     408          284 :                 if (symbol.version.deprecated) {
     409            1 :                         buffer.append_printf (" deprecated=\"1\"");
     410            1 :                         if (symbol.version.deprecated_since != null) {
     411            1 :                                 buffer.append_printf (" deprecated-version=\"%s\"", symbol.version.deprecated_since);
     412              :                         }
     413              :                 }
     414          284 :                 if (symbol.version.since != null) {
     415            1 :                         buffer.append_printf (" version=\"%s\"", symbol.version.since);
     416              :                 }
     417              :         }
     418              : 
     419           25 :         public override void visit_class (Class cl) {
     420           25 :                 if (cl.external_package) {
     421              :                         return;
     422              :                 }
     423              : 
     424           16 :                 if (!check_accessibility (cl)) {
     425              :                         return;
     426              :                 }
     427              : 
     428           16 :                 if (!has_namespace (cl)) {
     429              :                         return;
     430              :                 }
     431              : 
     432           15 :                 if (!(hierarchy[0] is Namespace)) {
     433            0 :                         deferred.add (cl);
     434            0 :                         return;
     435              :                 }
     436              : 
     437           15 :                 if (!cl.is_compact) {
     438           13 :                         string gtype_struct_name = get_gir_name (cl) + "Class";
     439              : 
     440           13 :                         write_indent ();
     441           13 :                         buffer.append_printf ("<class name=\"%s\"", get_gir_name (cl));
     442           13 :                         write_gtype_attributes (cl, true);
     443           13 :                         buffer.append_printf (" glib:type-struct=\"%s\"", gtype_struct_name);
     444           13 :                         if (cl.base_class == null) {
     445            6 :                                 buffer.append_printf (" glib:fundamental=\"1\"");
     446            6 :                                 buffer.append_printf (" glib:ref-func=\"%s\"", get_ccode_ref_function (cl));
     447            6 :                                 buffer.append_printf (" glib:unref-func=\"%s\"", get_ccode_unref_function (cl));
     448            6 :                                 buffer.append_printf (" glib:set-value-func=\"%s\"", get_ccode_set_value_function (cl));
     449            6 :                                 buffer.append_printf (" glib:get-value-func=\"%s\"", get_ccode_get_value_function (cl));
     450              :                         } else {
     451            7 :                                 buffer.append_printf (" parent=\"%s\"", gi_type_name (cl.base_class));
     452              :                         }
     453           13 :                         if (cl.is_abstract) {
     454            1 :                                 buffer.append_printf (" abstract=\"1\"");
     455              :                         }
     456           13 :                         if (cl.is_sealed) {
     457            2 :                                 buffer.append_printf (" final=\"1\"");
     458              :                         }
     459           13 :                         write_symbol_attributes (cl);
     460           13 :                         buffer.append_printf (">\n");
     461           13 :                         indent++;
     462              : 
     463           13 :                         write_doc (get_class_comment (cl), cl.comment);
     464              : 
     465              :                         // write implemented interfaces
     466           29 :                         foreach (DataType base_type in cl.get_base_types ()) {
     467            8 :                                 var object_type = (ObjectType) base_type;
     468            8 :                                 if (object_type.type_symbol is Interface) {
     469            1 :                                         write_indent ();
     470            1 :                                         buffer.append_printf ("<implements name=\"%s\"/>\n", gi_type_name (object_type.type_symbol));
     471              :                                 }
     472              :                         }
     473              : 
     474           13 :                         write_indent ();
     475           13 :                         buffer.append_printf ("<field name=\"parent_instance\" readable=\"0\" private=\"1\">\n");
     476           13 :                         indent++;
     477           13 :                         write_indent ();
     478           13 :                         if (cl.base_class == null) {
     479            6 :                                 buffer.append_printf ("<type name=\"%s\" c:type=\"%s\"/>\n", gi_type_name (gtypeinstance_type), get_ccode_name (gtypeinstance_type));
     480              :                         } else {
     481            7 :                                 buffer.append_printf ("<type name=\"%s\" c:type=\"%s\"/>\n", gi_type_name (cl.base_class), get_ccode_name (cl.base_class));
     482              :                         }
     483           13 :                         indent--;
     484           13 :                         write_indent ();
     485           13 :                         buffer.append_printf("</field>\n");
     486              : 
     487           13 :                         if (cl.base_class == null) {
     488            6 :                                 write_indent ();
     489            6 :                                 buffer.append_printf ("<field name=\"ref_count\">\n");
     490            6 :                                 indent++;
     491            6 :                                 write_indent ();
     492            6 :                                 buffer.append_printf ("<type name=\"gint\" c:type=\"volatile int\"/>\n");
     493            6 :                                 indent--;
     494            6 :                                 write_indent ();
     495            6 :                                 buffer.append_printf("</field>\n");
     496              :                         }
     497              : 
     498           13 :                         if (!context.abi_stability) {
     499           13 :                                 write_indent ();
     500           13 :                                 buffer.append_printf ("<field name=\"priv\" readable=\"0\" private=\"1\">\n");
     501           13 :                                 indent++;
     502           13 :                                 write_indent ();
     503           13 :                                 buffer.append_printf ("<type name=\"%sPrivate\" c:type=\"%sPrivate*\"/>\n", get_gir_name (cl), get_ccode_name (cl));
     504           13 :                                 indent--;
     505           13 :                                 write_indent ();
     506           13 :                                 buffer.append_printf("</field>\n");
     507              :                         }
     508              : 
     509           13 :                         if (cl.base_class != null && cl.base_class.is_subtype_of (gobject_type)) {
     510            9 :                                 foreach (var p in cl.get_type_parameters ()) {
     511            2 :                                         write_type_parameter (p, "property");
     512              :                                 }
     513              :                         }
     514              : 
     515           13 :                         hierarchy.insert (0, cl);
     516           13 :                         cl.accept_children (this);
     517           13 :                         hierarchy.remove_at (0);
     518              : 
     519           13 :                         if (context.abi_stability) {
     520            0 :                                 write_indent ();
     521            0 :                                 buffer.append_printf ("<field name=\"priv\" readable=\"0\" private=\"1\">\n");
     522            0 :                                 indent++;
     523            0 :                                 write_indent ();
     524            0 :                                 buffer.append_printf ("<type name=\"%sPrivate\" c:type=\"%sPrivate*\"/>\n", get_gir_name (cl), get_ccode_name (cl));
     525            0 :                                 indent--;
     526            0 :                                 write_indent ();
     527            0 :                                 buffer.append_printf("</field>\n");
     528              :                         }
     529              : 
     530           13 :                         indent--;
     531           13 :                         write_indent ();
     532           13 :                         buffer.append_printf ("</class>\n");
     533              : 
     534           13 :                         write_indent ();
     535           13 :                         buffer.append_printf ("<record name=\"%s\"", gtype_struct_name);
     536           13 :                         write_ctype_attributes (cl, "Class");
     537           13 :                         buffer.append_printf (" glib:is-gtype-struct-for=\"%s\"", get_gir_name (cl));
     538           13 :                         buffer.append_printf (">\n");
     539           13 :                         indent++;
     540              : 
     541           13 :                         write_indent ();
     542           13 :                         buffer.append_printf ("<field name=\"parent_class\" readable=\"0\" private=\"1\">\n");
     543           13 :                         indent++;
     544           13 :                         write_indent ();
     545           13 :                         if (cl.base_class == null) {
     546              :                                 //FIXME GObject.TypeClass vs GType
     547            6 :                                 buffer.append_printf ("<type name=\"%sClass\" c:type=\"%sClass\"/>\n", "GObject.Type", get_ccode_name (gtype_type));
     548              :                         } else {
     549            7 :                                 buffer.append_printf ("<type name=\"%sClass\" c:type=\"%sClass\"/>\n", gi_type_name (cl.base_class), get_ccode_name (cl.base_class));
     550              :                         }
     551           13 :                         indent--;
     552           13 :                         write_indent ();
     553           13 :                         buffer.append_printf ("</field>\n");
     554              : 
     555          153 :                         foreach (Method m in cl.get_methods ()) {
     556           70 :                                 if (m.is_abstract || m.is_virtual) {
     557           23 :                                         if (m.coroutine) {
     558            5 :                                                 string finish_name = m.name;
     559            5 :                                                 if (finish_name.has_suffix ("_async")) {
     560            3 :                                                         finish_name = finish_name.substring (0, finish_name.length - "_async".length);
     561              :                                                 }
     562            5 :                                                 finish_name += "_finish";
     563              : 
     564            5 :                                                 write_indent ();
     565            5 :                                                 buffer.append_printf("<field name=\"%s\"", m.name);
     566            5 :                                                 write_symbol_attributes (m);
     567            5 :                                                 buffer.append_printf (">\n");
     568            5 :                                                 indent++;
     569            5 :                                                 do_write_signature (m, "callback", true, m.name, get_ccode_name (m), m.get_async_begin_parameters (), new VoidType (), false, false, false);
     570            5 :                                                 indent--;
     571            5 :                                                 write_indent ();
     572            5 :                                                 buffer.append_printf ("</field>\n");
     573              : 
     574            5 :                                                 write_indent ();
     575            5 :                                                 buffer.append_printf("<field name=\"%s\"", finish_name);
     576            5 :                                                 write_symbol_attributes (m);
     577            5 :                                                 buffer.append_printf (">\n");
     578            5 :                                                 indent++;
     579            5 :                                                 do_write_signature (m, "callback", true, finish_name, get_ccode_finish_name (m), m.get_async_end_parameters (), m.return_type, m.tree_can_fail, false, false);
     580            5 :                                                 indent--;
     581            5 :                                                 write_indent ();
     582            5 :                                                 buffer.append_printf ("</field>\n");
     583              :                                         } else {
     584           13 :                                                 write_indent ();
     585           13 :                                                 buffer.append_printf("<field name=\"%s\"", m.name);
     586           13 :                                                 write_symbol_attributes (m);
     587           13 :                                                 buffer.append_printf (">\n");
     588           13 :                                                 indent++;
     589           13 :                                                 do_write_signature (m, "callback", true, m.name, get_ccode_name (m), m.get_parameters (), m.return_type, m.tree_can_fail, false, false);
     590           13 :                                                 indent--;
     591           13 :                                                 write_indent ();
     592           13 :                                                 buffer.append_printf ("</field>\n");
     593              :                                         }
     594              :                                 }
     595              :                         }
     596              : 
     597           19 :                         foreach (Signal sig in cl.get_signals ()) {
     598            3 :                                 if (sig.default_handler != null) {
     599            1 :                                         write_indent ();
     600            1 :                                         buffer.append_printf ("<field name=\"%s\"", get_ccode_lower_case_name (sig));
     601            1 :                                         write_symbol_attributes (sig);
     602            1 :                                         buffer.append_printf (">\n");
     603            1 :                                         indent++;
     604            1 :                                         write_signature (sig.default_handler, "callback", false, true, false);
     605            1 :                                         indent--;
     606            1 :                                         write_indent ();
     607            1 :                                         buffer.append_printf ("</field>\n");
     608              :                                 }
     609              :                         }
     610              : 
     611           13 :                         indent--;
     612           13 :                         write_indent ();
     613           13 :                         buffer.append_printf ("</record>\n");
     614              : 
     615           13 :                         write_indent ();
     616           13 :                         buffer.append_printf ("<record name=\"%sPrivate\" c:type=\"%sPrivate\" disguised=\"1\"/>\n", get_gir_name (cl), get_ccode_name (cl));
     617              :                 } else {
     618            2 :                         write_indent ();
     619            2 :                         buffer.append_printf ("<record name=\"%s\"", get_gir_name (cl));
     620            2 :                         write_ctype_attributes (cl);
     621            2 :                         write_symbol_attributes (cl);
     622            2 :                         buffer.append_printf (">\n");
     623            2 :                         indent++;
     624              : 
     625            2 :                         write_doc (get_class_comment (cl), cl.comment);
     626              : 
     627            2 :                         hierarchy.insert (0, cl);
     628            2 :                         cl.accept_children (this);
     629            2 :                         hierarchy.remove_at (0);
     630              : 
     631            2 :                         indent--;
     632            2 :                         write_indent ();
     633            2 :                         buffer.append_printf ("</record>\n");
     634              :                 }
     635              : 
     636           15 :                 visit_deferred ();
     637              :         }
     638              : 
     639          104 :         public override void visit_struct (Struct st) {
     640          104 :                 if (st.external_package) {
     641              :                         return;
     642              :                 }
     643              : 
     644            5 :                 if (!check_accessibility (st)) {
     645              :                         return;
     646              :                 }
     647              : 
     648            5 :                 if (!has_namespace (st)) {
     649              :                         return;
     650              :                 }
     651              : 
     652            4 :                 if (!(hierarchy[0] is Namespace)) {
     653            0 :                         deferred.add (st);
     654            0 :                         return;
     655              :                 }
     656              : 
     657            4 :                 write_indent ();
     658            4 :                 buffer.append_printf ("<record name=\"%s\"", get_gir_name (st));
     659            4 :                 if (get_ccode_has_type_id (st)) {
     660            3 :                         write_gtype_attributes (st, true);
     661              :                 } else {
     662            1 :                         write_ctype_attributes (st, "", true);
     663              :                 }
     664            4 :                 write_symbol_attributes (st);
     665            4 :                 buffer.append_printf (">\n");
     666            4 :                 indent++;
     667              : 
     668            4 :                 write_doc (get_struct_comment (st), st.comment);
     669              : 
     670            4 :                 hierarchy.insert (0, st);
     671            4 :                 st.accept_children (this);
     672            4 :                 hierarchy.remove_at (0);
     673              : 
     674            4 :                 indent--;
     675            4 :                 write_indent ();
     676            4 :                 buffer.append_printf ("</record>\n");
     677              : 
     678            4 :                 visit_deferred ();
     679              :         }
     680              : 
     681            9 :         public override void visit_interface (Interface iface) {
     682            5 :                 if (iface.external_package) {
     683              :                         return;
     684              :                 }
     685              : 
     686            5 :                 if (!check_accessibility (iface)) {
     687              :                         return;
     688              :                 }
     689              : 
     690            5 :                 if (!has_namespace (iface)) {
     691              :                         return;
     692              :                 }
     693              : 
     694            4 :                 if (!(hierarchy[0] is Namespace)) {
     695            0 :                         deferred.add (iface);
     696            0 :                         return;
     697              :                 }
     698              : 
     699            4 :                 string gtype_struct_name = get_gir_name (iface) + "Iface";
     700              : 
     701            4 :                 write_indent ();
     702            4 :                 buffer.append_printf ("<interface name=\"%s\"", get_gir_name (iface));
     703            4 :                 write_gtype_attributes (iface, true);
     704            4 :                 buffer.append_printf (" glib:type-struct=\"%s\"", gtype_struct_name);
     705            4 :                 write_symbol_attributes (iface);
     706            4 :                 buffer.append_printf (">\n");
     707            4 :                 indent++;
     708              : 
     709            4 :                 write_doc (get_interface_comment (iface), iface.comment);
     710              : 
     711              :                 // write prerequisites
     712            4 :                 if (iface.get_prerequisites ().size > 0) {
     713            9 :                         foreach (DataType base_type in iface.get_prerequisites ()) {
     714            3 :                                 write_indent ();
     715            3 :                                 buffer.append_printf ("<prerequisite name=\"%s\"/>\n", gi_type_name (((ObjectType) base_type).type_symbol));
     716              :                         }
     717              :                 }
     718              : 
     719            4 :                 hierarchy.insert (0, iface);
     720            4 :                 iface.accept_children (this);
     721            4 :                 hierarchy.remove_at (0);
     722              : 
     723            4 :                 indent--;
     724            4 :                 write_indent ();
     725            4 :                 buffer.append_printf ("</interface>\n");
     726              : 
     727            4 :                 write_indent ();
     728            4 :                 buffer.append_printf ("<record name=\"%s\"", gtype_struct_name);
     729            4 :                 write_ctype_attributes (iface, "Iface");
     730            4 :                 buffer.append_printf (" glib:is-gtype-struct-for=\"%s\"", get_gir_name (iface));
     731            4 :                 buffer.append_printf (">\n");
     732            4 :                 indent++;
     733              : 
     734            4 :                 write_indent ();
     735            4 :                 buffer.append_printf ("<field name=\"parent_iface\" readable=\"0\" private=\"1\">\n");
     736            4 :                 indent++;
     737            4 :                 write_indent ();
     738            4 :                 buffer.append_printf ("<type name=\"%s\" c:type=\"%s\"/>\n", gi_type_name (gtypeinterface_type), get_ccode_name (gtypeinterface_type));
     739            4 :                 indent--;
     740            4 :                 write_indent ();
     741            4 :                 buffer.append_printf ("</field>\n");
     742              : 
     743           22 :                 foreach (Method m in iface.get_methods ()) {
     744            9 :                         if (m.is_abstract || m.is_virtual) {
     745           11 :                                 if (m.coroutine) {
     746            3 :                                         string finish_name = m.name;
     747            3 :                                         if (finish_name.has_suffix ("_async")) {
     748            2 :                                                 finish_name = finish_name.substring (0, finish_name.length - "_async".length);
     749              :                                         }
     750            3 :                                         finish_name += "_finish";
     751              : 
     752            3 :                                         write_indent ();
     753            3 :                                         buffer.append_printf("<field name=\"%s\"", m.name);
     754            3 :                                         write_symbol_attributes (m);
     755            3 :                                         buffer.append_printf (">\n");
     756            3 :                                         indent++;
     757            3 :                                         do_write_signature (m, "callback", true, m.name, get_ccode_name (m), m.get_async_begin_parameters (), new VoidType (), false, false, false);
     758            3 :                                         indent--;
     759            3 :                                         write_indent ();
     760            3 :                                         buffer.append_printf ("</field>\n");
     761              : 
     762            3 :                                         write_indent ();
     763            3 :                                         buffer.append_printf("<field name=\"%s\"", finish_name);
     764            3 :                                         write_symbol_attributes (m);
     765            3 :                                         buffer.append_printf (">\n");
     766            3 :                                         indent++;
     767            3 :                                         do_write_signature (m, "callback", true, finish_name, get_ccode_finish_name (m), m.get_async_end_parameters (), m.return_type, m.tree_can_fail, false, false);
     768            3 :                                         indent--;
     769            3 :                                         write_indent ();
     770            3 :                                         buffer.append_printf ("</field>\n");
     771              :                                 } else {
     772            5 :                                         write_indent ();
     773            5 :                                         buffer.append_printf("<field name=\"%s\"", m.name);
     774            5 :                                         write_symbol_attributes (m);
     775            5 :                                         buffer.append_printf (">\n");
     776            5 :                                         indent++;
     777            5 :                                         do_write_signature (m, "callback", true, m.name, get_ccode_name (m), m.get_parameters (), m.return_type, m.tree_can_fail, false, false);
     778            5 :                                         indent--;
     779            5 :                                         write_indent ();
     780            5 :                                         buffer.append_printf ("</field>\n");
     781              :                                 }
     782              :                         }
     783              :                 }
     784              : 
     785            8 :                 foreach (var prop in iface.get_properties ()) {
     786            2 :                         if (prop.is_abstract || prop.is_virtual) {
     787            4 :                                 if (prop.get_accessor != null && prop.get_accessor.readable) {
     788            2 :                                         var m = prop.get_accessor.get_method ();
     789            2 :                                         write_indent ();
     790            2 :                                         buffer.append_printf("<field name=\"%s\"", m.name);
     791            2 :                                         write_symbol_attributes (m);
     792            2 :                                         buffer.append_printf (">\n");
     793            2 :                                         indent++;
     794            2 :                                         do_write_signature (m, "callback", true, m.name, get_ccode_name (m), m.get_parameters (), m.return_type, m.tree_can_fail, false, false);
     795            2 :                                         indent--;
     796            2 :                                         write_indent ();
     797            2 :                                         buffer.append_printf ("</field>\n");
     798              :                                 }
     799              : 
     800            4 :                                 if (prop.set_accessor != null && prop.set_accessor.writable) {
     801            2 :                                         var m = prop.set_accessor.get_method ();
     802            2 :                                         write_indent ();
     803            2 :                                         buffer.append_printf("<field name=\"%s\"", m.name);
     804            2 :                                         write_symbol_attributes (m);
     805            2 :                                         buffer.append_printf (">\n");
     806            2 :                                         indent++;
     807            2 :                                         do_write_signature (m, "callback", true, m.name, get_ccode_name (m), m.get_parameters (), m.return_type, m.tree_can_fail, false, false);
     808            2 :                                         indent--;
     809            2 :                                         write_indent ();
     810            2 :                                         buffer.append_printf ("</field>\n");
     811              :                                 }
     812              :                         }
     813              :                 }
     814              : 
     815            4 :                 indent--;
     816            4 :                 write_indent ();
     817            4 :                 buffer.append_printf ("</record>\n");
     818              : 
     819            4 :                 visit_deferred ();
     820              :         }
     821              : 
     822           72 :         private void visit_deferred () {
     823          446 :                 var nodes = this.deferred;
     824           36 :                 this.deferred = new Vala.ArrayList<Vala.CodeNode>();
     825              : 
     826           36 :                 foreach (var node in nodes) {
     827            0 :                         node.accept (this);
     828              :                 }
     829              :         }
     830              : 
     831          107 :         private string? get_gir_name (Symbol symbol) {
     832          107 :                 string? gir_name = null;
     833          107 :                 var h0 = hierarchy[0];
     834              : 
     835          565 :                 for (Symbol? cur_sym = symbol ; cur_sym != null ; cur_sym = cur_sym.parent_symbol) {
     836          224 :                         if (cur_sym == h0) {
     837              :                                 break;
     838              :                         }
     839              : 
     840          117 :                         var cur_name = cur_sym.get_attribute_string ("GIR", "name");
     841          117 :                         if (cur_name == null) {
     842          204 :                                 cur_name = cur_sym.name;
     843              :                         }
     844          117 :                         gir_name = cur_name.concat (gir_name);
     845              :                 }
     846              : 
     847          107 :                 return gir_name;
     848              :         }
     849              : 
     850           15 :         public override void visit_enum (Enum en) {
     851            8 :                 if (en.external_package) {
     852              :                         return;
     853              :                 }
     854              : 
     855            8 :                 if (!check_accessibility (en)) {
     856              :                         return;
     857              :                 }
     858              : 
     859            8 :                 if (!has_namespace (en)) {
     860              :                         return;
     861              :                 }
     862              : 
     863            7 :                 if (!(hierarchy[0] is Namespace)) {
     864            0 :                         deferred.add (en);
     865            0 :                         return;
     866              :                 }
     867              : 
     868            7 :                 string element_name = (en.is_flags) ? "bitfield" : "enumeration";
     869              : 
     870            7 :                 write_indent ();
     871            7 :                 buffer.append_printf ("<%s name=\"%s\"", element_name, get_gir_name (en));
     872            7 :                 if (get_ccode_has_type_id (en)) {
     873            6 :                         write_gtype_attributes (en);
     874              :                 } else {
     875            1 :                         write_ctype_attributes (en);
     876              :                 }
     877            7 :                 write_symbol_attributes (en);
     878            7 :                 buffer.append_printf (">\n");
     879            7 :                 indent++;
     880              : 
     881            7 :                 write_doc (get_enum_comment (en), en.comment);
     882              : 
     883            7 :                 enum_value = 0;
     884            7 :                 hierarchy.insert (0, en);
     885            7 :                 en.accept_children (this);
     886            7 :                 hierarchy.remove_at (0);
     887              : 
     888            7 :                 indent--;
     889            7 :                 write_indent ();
     890            7 :                 buffer.append_printf ("</%s>\n", element_name);
     891              : 
     892            7 :                 visit_deferred ();
     893              :         }
     894              : 
     895              :         private int enum_value;
     896              : 
     897           26 :         public override void visit_enum_value (EnumValue ev) {
     898           13 :                 write_indent ();
     899           13 :                 var en = (Enum) hierarchy[0];
     900           13 :                 buffer.append_printf ("<member name=\"%s\" c:identifier=\"%s\"", ev.name.ascii_down (), get_ccode_name (ev));
     901           15 :                 if (ev.value != null) {
     902            2 :                         string value = literal_expression_to_value_string (ev.value);
     903            2 :                         buffer.append_printf (" value=\"%s\"", value);
     904              :                 } else {
     905           11 :                         if (en.is_flags) {
     906            5 :                                 buffer.append_printf (" value=\"%d\"", 1 << enum_value++);
     907              :                         } else {
     908            6 :                                 buffer.append_printf (" value=\"%d\"", enum_value++);
     909              :                         }
     910              :                 }
     911           13 :                 write_symbol_attributes (ev);
     912              : 
     913           13 :                 string? comment = get_enum_value_comment (ev);
     914           13 :                 if (comment == null) {
     915           13 :                         buffer.append_printf ("/>\n");
     916              :                 } else {
     917            0 :                         buffer.append_printf (">\n");
     918            0 :                         indent++;
     919              : 
     920            0 :                         write_doc (comment, ev.comment);
     921              : 
     922            0 :                         indent--;
     923            0 :                         write_indent ();
     924            0 :                         buffer.append_printf ("</member>\n");
     925              :                 }
     926              :         }
     927              : 
     928            4 :         public override void visit_error_domain (ErrorDomain edomain) {
     929            4 :                 if (edomain.external_package) {
     930              :                         return;
     931              :                 }
     932              : 
     933            4 :                 if (!check_accessibility (edomain)) {
     934              :                         return;
     935              :                 }
     936              : 
     937            4 :                 if (!has_namespace (edomain)) {
     938              :                         return;
     939              :                 }
     940              : 
     941            3 :                 write_indent ();
     942            3 :                 buffer.append_printf ("<enumeration name=\"%s\"", get_gir_name (edomain));
     943            3 :                 if (get_ccode_has_type_id (edomain)) {
     944            2 :                         write_gtype_attributes (edomain);
     945              :                 } else {
     946            1 :                         write_ctype_attributes (edomain);
     947              :                 }
     948            3 :                 buffer.append_printf (" glib:error-domain=\"%s\"", get_ccode_quark_name (edomain));
     949            3 :                 write_symbol_attributes (edomain);
     950            3 :                 buffer.append_printf (">\n");
     951            3 :                 indent++;
     952              : 
     953            3 :                 write_doc (get_error_domain_comment (edomain), edomain.comment);
     954              : 
     955            3 :                 enum_value = 0;
     956            3 :                 hierarchy.insert (0, edomain);
     957            3 :                 edomain.accept_children (this);
     958            3 :                 hierarchy.remove_at (0);
     959              : 
     960            3 :                 indent--;
     961            3 :                 write_indent ();
     962            3 :                 buffer.append_printf ("</enumeration>\n");
     963              : 
     964            3 :                 visit_deferred ();
     965              :         }
     966              : 
     967           14 :         public override void visit_error_code (ErrorCode ecode) {
     968            7 :                 write_indent ();
     969            7 :                 buffer.append_printf ("<member name=\"%s\" c:identifier=\"%s\"", ecode.name.ascii_down (), get_ccode_name (ecode));
     970            9 :                 if (ecode.value != null) {
     971            2 :                         string value = literal_expression_to_value_string (ecode.value);
     972            2 :                         buffer.append_printf (" value=\"%s\"", value);
     973              :                 } else {
     974            5 :                         buffer.append_printf (" value=\"%d\"", enum_value++);
     975              :                 }
     976            7 :                 write_symbol_attributes (ecode);
     977              : 
     978            7 :                 string? comment = get_error_code_comment (ecode);
     979            7 :                 if (comment == null) {
     980            7 :                         buffer.append_printf ("/>\n");
     981              :                 } else {
     982            0 :                         buffer.append_printf (">\n");
     983            0 :                         indent++;
     984              : 
     985            0 :                         write_doc (comment, ecode.comment);
     986              : 
     987            0 :                         indent--;
     988            0 :                         write_indent ();
     989            0 :                         buffer.append_printf ("</member>\n");
     990              :                 }
     991              :         }
     992              : 
     993           25 :         public override void visit_constant (Constant c) {
     994           16 :                 if (c.external_package) {
     995              :                         return;
     996              :                 }
     997              : 
     998           10 :                 if (!check_accessibility (c)) {
     999              :                         return;
    1000              :                 }
    1001              : 
    1002           10 :                 if (!has_namespace (c)) {
    1003              :                         return;
    1004              :                 }
    1005              : 
    1006              :                 //TODO Add better constant evaluation
    1007            9 :                 var initializer = c.value;
    1008            9 :                 string value = literal_expression_to_value_string (initializer);
    1009              : 
    1010            9 :                 write_indent ();
    1011            9 :                 buffer.append_printf ("<constant name=\"%s\" c:identifier=\"%s\"", get_gir_name (c), get_ccode_name (c));
    1012            9 :                 buffer.append_printf (" value=\"%s\"", value);
    1013            9 :                 write_symbol_attributes (c);
    1014            9 :                 buffer.append_printf (">\n");
    1015            9 :                 indent++;
    1016              : 
    1017            9 :                 write_doc (get_constant_comment (c), c.comment);
    1018              : 
    1019            9 :                 write_type (initializer.value_type);
    1020              : 
    1021            9 :                 indent--;
    1022            9 :                 write_indent ();
    1023            9 :                 buffer.append_printf ("</constant>\n");
    1024              :         }
    1025              : 
    1026           31 :         public override void visit_field (Field f) {
    1027           31 :                 if (f.external_package) {
    1028              :                         return;
    1029              :                 }
    1030              : 
    1031           28 :                 if (!check_accessibility (f)) {
    1032              :                         return;
    1033              :                 }
    1034              : 
    1035           18 :                 if (!has_namespace (f)) {
    1036              :                         return;
    1037              :                 }
    1038              : 
    1039           17 :                 write_indent ();
    1040           17 :                 buffer.append_printf ("<field name=\"%s\" writable=\"1\"", get_ccode_name (f));
    1041           17 :                 if (f.variable_type.nullable) {
    1042            1 :                         buffer.append_printf (" nullable=\"1\"");
    1043              :                 }
    1044           17 :                 write_symbol_attributes (f);
    1045           17 :                 buffer.append_printf (">\n");
    1046           17 :                 indent++;
    1047              : 
    1048           17 :                 write_doc (get_field_comment (f), f.comment);
    1049              : 
    1050           17 :                 write_type (f.variable_type);
    1051              : 
    1052           17 :                 indent--;
    1053           17 :                 write_indent ();
    1054           17 :                 buffer.append_printf ("</field>\n");
    1055              : 
    1056           19 :                 if (f.variable_type is ArrayType && get_ccode_array_length (f)) {
    1057            2 :                         var array_type = (ArrayType) f.variable_type;
    1058            2 :                         if (!array_type.fixed_length) {
    1059            2 :                                 for (var i = 0; i < array_type.rank; i++) {
    1060            1 :                                         write_indent ();
    1061            1 :                                         buffer.append_printf ("<field name=\"%s_length%i\"", get_ccode_name (f), i + 1);
    1062            1 :                                         write_symbol_attributes (f);
    1063            1 :                                         buffer.append_printf (">\n");
    1064            1 :                                         indent++;
    1065            1 :                                         write_type (array_type.length_type);
    1066            1 :                                         indent--;
    1067            1 :                                         write_indent ();
    1068            1 :                                         buffer.append_printf ("</field>\n");
    1069              :                                 }
    1070              :                         }
    1071           16 :                 } else if (f.variable_type is DelegateType) {
    1072            1 :                         var deleg_type = (DelegateType) f.variable_type;
    1073            1 :                         if (deleg_type.delegate_symbol.has_target) {
    1074            1 :                                 write_indent ();
    1075            1 :                                 buffer.append_printf ("<field name=\"%s\"", get_ccode_delegate_target_name (f));
    1076            1 :                                 write_symbol_attributes (f);
    1077            1 :                                 buffer.append_printf (">\n");
    1078            1 :                                 indent++;
    1079            1 :                                 write_indent ();
    1080            1 :                                 buffer.append_printf ("<type name=\"gpointer\" c:type=\"gpointer\"/>\n");
    1081            1 :                                 indent--;
    1082            1 :                                 write_indent ();
    1083            1 :                                 buffer.append_printf ("</field>\n");
    1084            1 :                                 if (deleg_type.is_disposable ()) {
    1085            1 :                                         write_indent ();
    1086            1 :                                         buffer.append_printf ("<field name=\"%s\"", get_ccode_delegate_target_destroy_notify_name (f));
    1087            1 :                                         write_symbol_attributes (f);
    1088            1 :                                         buffer.append_printf (">\n");
    1089            1 :                                         indent++;
    1090            1 :                                         write_indent ();
    1091            1 :                                         buffer.append_printf ("<type name=\"GLib.DestroyNotify\" c:type=\"GDestroyNotify\"/>\n");
    1092            1 :                                         indent--;
    1093            1 :                                         write_indent ();
    1094            1 :                                         buffer.append_printf ("</field>\n");
    1095              :                                 }
    1096              :                         }
    1097              :                 }
    1098              :         }
    1099              : 
    1100          343 :         private void write_implicit_params (DataType? type, ref int index, bool has_array_length, string? name, ParameterDirection direction) {
    1101          343 :                 if (type is ArrayType && has_array_length) {
    1102           48 :                         for (var i = 0; i < ((ArrayType) type).rank; i++) {
    1103           24 :                                 write_param_or_return (((ArrayType) type).length_type, "parameter", ref index, has_array_length, "%s_length%i".printf (name, i + 1), null, null, direction);
    1104              :                         }
    1105          358 :                 } else if (type is DelegateType) {
    1106           39 :                         var deleg_type = (DelegateType) type;
    1107           77 :                         if (deleg_type.delegate_symbol.has_target) {
    1108           38 :                                 var data_type = new PointerType (new VoidType ());
    1109           38 :                                 write_param_or_return (data_type, "parameter", ref index, false, "%s_target".printf (name), null, null, direction);
    1110           52 :                                 if (deleg_type.is_disposable ()) {
    1111           14 :                                         var notify_type = new DelegateType (context.root.scope.lookup ("GLib").scope.lookup ("DestroyNotify") as Delegate);
    1112           14 :                                         write_param_or_return (notify_type, "parameter", ref index, false, "%s_target_destroy_notify".printf (name), null, null, direction);
    1113              :                                 }
    1114              :                         }
    1115              :                 }
    1116              :         }
    1117              : 
    1118          320 :         void skip_implicit_params (DataType? type, ref int index, bool has_array_length) {
    1119          320 :                 if (type is ArrayType && has_array_length) {
    1120           24 :                         index += ((ArrayType) type).rank;
    1121          335 :                 } else if (type is DelegateType) {
    1122           39 :                         index++;
    1123           39 :                         var deleg_type = (DelegateType) type;
    1124           39 :                         if (deleg_type.is_disposable ()) {
    1125           14 :                                 index++;
    1126              :                         }
    1127              :                 }
    1128              :         }
    1129              : 
    1130           11 :         private void write_type_parameter (TypeParameter type_parameter, string tag_type) {
    1131           11 :                 write_indent ();
    1132           11 :                 if (tag_type == "property") {
    1133            2 :                         buffer.append_printf ("<%s name=\"%s\" writable=\"1\" construct-only=\"1\">\n", tag_type, get_ccode_type_id (type_parameter).replace ("_", "-"));
    1134              :                 } else {
    1135            9 :                         buffer.append_printf ("<%s name=\"%s\" transfer-ownership=\"none\">\n", tag_type, get_ccode_type_id (type_parameter));
    1136              :                 }
    1137           11 :                 indent++;
    1138           11 :                 write_indent ();
    1139           11 :                 buffer.append_printf ("<type name=\"GType\" c:type=\"GType\"/>\n");
    1140           11 :                 indent--;
    1141           11 :                 write_indent ();
    1142           11 :                 buffer.append_printf ("</%s>\n", tag_type);
    1143           11 :                 write_indent ();
    1144           11 :                 if (tag_type == "property") {
    1145            2 :                         buffer.append_printf ("<%s name=\"%s\" writable=\"1\" construct-only=\"1\">\n", tag_type, get_ccode_copy_function (type_parameter).replace ("_", "-"));
    1146              :                 } else {
    1147            9 :                         buffer.append_printf ("<%s name=\"%s\" transfer-ownership=\"none\">\n", tag_type, get_ccode_copy_function (type_parameter));
    1148              :                 }
    1149           11 :                 indent++;
    1150           11 :                 write_indent ();
    1151           11 :                 buffer.append_printf ("<type name=\"GObject.BoxedCopyFunc\" c:type=\"GBoxedCopyFunc\"/>\n");
    1152           11 :                 indent--;
    1153           11 :                 write_indent ();
    1154           11 :                 buffer.append_printf ("</%s>\n", tag_type);
    1155           11 :                 write_indent ();
    1156           11 :                 if (tag_type == "property") {
    1157            2 :                         buffer.append_printf ("<%s name=\"%s\" writable=\"1\" construct-only=\"1\">\n", tag_type, get_ccode_destroy_function (type_parameter).replace ("_", "-"));
    1158              :                 } else {
    1159            9 :                         buffer.append_printf ("<%s name=\"%s\" transfer-ownership=\"none\">\n", tag_type, get_ccode_destroy_function (type_parameter));
    1160              :                 }
    1161           11 :                 indent++;
    1162           11 :                 write_indent ();
    1163           11 :                 buffer.append_printf ("<type name=\"GLib.DestroyNotify\" c:type=\"GDestroyNotify\"/>\n");
    1164           11 :                 indent--;
    1165           11 :                 write_indent ();
    1166           11 :                 buffer.append_printf ("</%s>\n", tag_type);
    1167              :         }
    1168              : 
    1169          197 :         private void write_params_and_return (Callable symbol, string tag_name, List<Parameter> params, List<TypeParameter>? type_params, DataType? return_type, bool return_array_length, string? return_comment = null, bool constructor = false, Parameter? instance_param = null, bool user_data = false) {
    1170          197 :                 int last_index = 0;
    1171          197 :                 bool ret_is_struct = return_type != null && return_type.is_real_non_null_struct_type ();
    1172              : 
    1173          197 :                 if (params.size != 0 || (return_type is ArrayType && return_array_length) || (return_type is DelegateType) || ret_is_struct) {
    1174          147 :                         int index = 0;
    1175              : 
    1176          505 :                         foreach (Parameter param in params) {
    1177          179 :                                 index++;
    1178              : 
    1179          179 :                                 skip_implicit_params (param.variable_type, ref index, get_ccode_array_length (param));
    1180              :                         }
    1181              : 
    1182          147 :                         if (ret_is_struct) {
    1183            6 :                                 index++;
    1184              :                         } else {
    1185          141 :                                 skip_implicit_params (return_type, ref index, return_array_length);
    1186          141 :                                 if (return_type is ArrayType && return_array_length) {
    1187            6 :                                         index -= ((ArrayType) return_type).rank - 1;
    1188              :                                 }
    1189              :                         }
    1190              : 
    1191          147 :                         last_index = index - 1;
    1192              :                 }
    1193              : 
    1194          197 :                 if (return_type != null && !ret_is_struct) {
    1195          191 :                         write_param_or_return (return_type, "return-value", ref last_index, return_array_length, null, symbol.comment, return_comment, ParameterDirection.IN, constructor);
    1196            6 :                 } else if (ret_is_struct) {
    1197            6 :                         write_param_or_return (new VoidType (), "return-value", ref last_index, false, null, symbol.comment, return_comment, ParameterDirection.IN);
    1198              :                 }
    1199              : 
    1200          197 :                 if (params.size != 0 || (type_params != null && type_params.size > 0) || instance_param != null || (return_type is ArrayType && return_array_length) || (return_type is DelegateType) || ret_is_struct) {
    1201          177 :                         write_indent ();
    1202          177 :                         buffer.append_printf ("<parameters>\n");
    1203          177 :                         indent++;
    1204          177 :                         int index = 0;
    1205              : 
    1206          322 :                         if (instance_param != null) {
    1207          145 :                                 var type = instance_param.variable_type.copy ();
    1208          145 :                                 unowned Struct? st = type.type_symbol as Struct;
    1209            6 :                                 if (st != null && !st.is_simple_type ()) {
    1210            6 :                                         type.nullable = true;
    1211              :                                 }
    1212          145 :                                 int skip = 0;
    1213          145 :                                 if (tag_name == "callback") {
    1214           39 :                                         write_param_or_return (type, "parameter", ref skip, false, "self");
    1215           39 :                                         index++;
    1216              :                                 } else {
    1217          106 :                                         write_param_or_return (type, "instance-parameter", ref skip, false, "self");
    1218              :                                 }
    1219              :                         }
    1220              : 
    1221          177 :                         if (constructor && ret_is_struct) {
    1222              :                                 // struct constructor has a caller-allocates / out-parameter as instance
    1223            4 :                                 write_param_or_return (return_type, "instance-parameter", ref index, false, "self", symbol.comment, return_comment, ParameterDirection.OUT, constructor, true);
    1224              :                         }
    1225              : 
    1226          177 :                         if (type_params != null) {
    1227          187 :                                 foreach (var p in type_params) {
    1228            9 :                                         write_type_parameter (p, "parameter");
    1229            9 :                                         index += 3;
    1230              :                                 }
    1231              :                         }
    1232              : 
    1233          535 :                         foreach (Parameter param in params) {
    1234          179 :                                 write_param_or_return (param.variable_type, "parameter", ref index, get_ccode_array_length (param), get_ccode_name (param), param.parent_symbol.comment, get_parameter_comment (param), param.direction, false, false, param.ellipsis || param.params_array);
    1235              : 
    1236          179 :                                 write_implicit_params (param.variable_type, ref index, get_ccode_array_length (param), get_ccode_name (param), param.direction);
    1237              :                         }
    1238              : 
    1239          177 :                         if (!constructor && ret_is_struct) {
    1240              :                                 // struct returns are converted to parameters
    1241            2 :                                 write_param_or_return (return_type, "parameter", ref index, false, "result", symbol.comment, return_comment, ParameterDirection.OUT, constructor, true);
    1242          175 :                         } else if (!constructor) {
    1243          164 :                                 write_implicit_params (return_type, ref index, return_array_length, "result", ParameterDirection.OUT);
    1244              :                         }
    1245              : 
    1246          177 :                         if (user_data) {
    1247            2 :                                 write_indent ();
    1248            2 :                                 buffer.append_printf ("<parameter name=\"user_data\" transfer-ownership=\"none\" closure=\"%d\">\n", index);
    1249            2 :                                 indent++;
    1250            2 :                                 write_indent ();
    1251            2 :                                 buffer.append_printf ("<type name=\"gpointer\" c:type=\"void*\"/>\n");
    1252            2 :                                 indent--;
    1253            2 :                                 write_indent ();
    1254            2 :                                 buffer.append_printf ("</parameter>\n");
    1255              :                         }
    1256              : 
    1257          177 :                         indent--;
    1258          177 :                         write_indent ();
    1259          177 :                         buffer.append_printf ("</parameters>\n");
    1260              :                 }
    1261              :         }
    1262              : 
    1263            6 :         public override void visit_delegate (Delegate cb) {
    1264            6 :                 if (cb.external_package) {
    1265              :                         return;
    1266              :                 }
    1267              : 
    1268            6 :                 if (!check_accessibility (cb)) {
    1269              :                         return;
    1270              :                 }
    1271              : 
    1272            6 :                 if (!has_namespace (cb)) {
    1273              :                         return;
    1274              :                 }
    1275              : 
    1276            5 :                 write_indent ();
    1277            5 :                 buffer.append_printf ("<callback name=\"%s\"", get_gir_name (cb));
    1278            5 :                 buffer.append_printf (" c:type=\"%s\"", get_ccode_name (cb));
    1279            5 :                 if (cb.tree_can_fail) {
    1280            1 :                         buffer.append_printf (" throws=\"1\"");
    1281              :                 }
    1282            5 :                 write_symbol_attributes (cb);
    1283            5 :                 buffer.append_printf (">\n");
    1284            5 :                 indent++;
    1285              : 
    1286            5 :                 write_doc (get_delegate_comment (cb), cb.comment);
    1287              : 
    1288            5 :                 write_params_and_return (cb, "callback", cb.get_parameters (), cb.get_type_parameters (), cb.return_type, get_ccode_array_length (cb), get_delegate_return_comment (cb), false, null, cb.has_target);
    1289              : 
    1290            5 :                 indent--;
    1291            5 :                 write_indent ();
    1292            5 :                 buffer.append_printf ("</callback>\n");
    1293              :         }
    1294              : 
    1295          181 :         public override void visit_method (Method m) {
    1296           91 :                 if (m.external_package) {
    1297              :                         return;
    1298              :                 }
    1299              : 
    1300              :                 // don't write interface implementation unless it's an abstract or virtual method
    1301           91 :                 if (!check_accessibility (m) || m.overrides || (m.base_interface_method != null && !m.is_abstract && !m.is_virtual)) {
    1302            0 :                         return;
    1303              :                 }
    1304              : 
    1305           91 :                 if (!has_namespace (m)) {
    1306              :                         return;
    1307              :                 }
    1308              : 
    1309           90 :                 string tag_name = "method";
    1310           90 :                 var parent = this.hierarchy.get (0);
    1311           90 :                 if (parent is Enum) {
    1312            0 :                         deferred.add (m);
    1313            0 :                         return;
    1314              :                 }
    1315              : 
    1316           90 :                 if (parent is Namespace || m.binding == MemberBinding.STATIC || parent != m.parent_symbol) {
    1317           20 :                         tag_name = "function";
    1318              :                 }
    1319              : 
    1320           90 :                 if (!get_ccode_no_wrapper (m) && m.signal_reference == null) {
    1321           83 :                         write_signature (m, tag_name, true);
    1322              :                 }
    1323              : 
    1324           90 :                 if (m.is_abstract || m.is_virtual) {
    1325           29 :                         write_signature (m, "virtual-method", true, false);
    1326              :                 }
    1327              :         }
    1328              : 
    1329          323 :         bool is_type_introspectable (DataType type) {
    1330              :                 // gobject-introspection does not currently support va_list parameters
    1331          323 :                 if (get_ccode_name (type) == "va_list") {
    1332              :                         return false;
    1333              :                 }
    1334              : 
    1335              :                 return true;
    1336              :         }
    1337              : 
    1338          187 :         bool is_method_introspectable (Method m) {
    1339          187 :                 if (!is_type_introspectable (m.return_type)) {
    1340           10 :                         return false;
    1341              :                 }
    1342          443 :                 foreach (var param in m.get_parameters ()) {
    1343          138 :                         if (param.ellipsis || param.params_array || !is_type_introspectable (param.variable_type)) {
    1344           10 :                                 return false;
    1345              :                         }
    1346              :                 }
    1347          187 :                 return true;
    1348              :         }
    1349              : 
    1350          284 :         bool is_introspectable (Symbol sym) {
    1351          284 :                 if (sym is Method && !is_method_introspectable ((Method) sym)) {
    1352           10 :                         return false;
    1353              :                 }
    1354              : 
    1355          274 :                 return is_visibility (sym);
    1356              :         }
    1357              : 
    1358          226 :         private void write_signature (Method m, string tag_name, bool write_doc, bool instance = false, bool write_attributes = true) {
    1359          113 :                 var parent = this.hierarchy.get (0);
    1360              :                 string name;
    1361          115 :                 if (m.parent_symbol != parent) {
    1362            2 :                         instance = false;
    1363            2 :                         name = get_ccode_name (m);
    1364            2 :                         var parent_prefix = get_ccode_lower_case_prefix (parent);
    1365            2 :                         if (name.has_prefix (parent_prefix)) {
    1366            2 :                                 name = name.substring (parent_prefix.length);
    1367              :                         }
    1368              :                 } else {
    1369          222 :                         name = m.name;
    1370              :                 }
    1371              : 
    1372          113 :                 if (m.coroutine) {
    1373           14 :                         string finish_name = name;
    1374           14 :                         if (finish_name.has_suffix ("_async")) {
    1375            8 :                                 finish_name = finish_name.substring (0, finish_name.length - "_async".length);
    1376              :                         }
    1377           14 :                         finish_name += "_finish";
    1378           14 :                         do_write_signature (m, tag_name, instance, name, get_ccode_name (m), m.get_async_begin_parameters (), new VoidType (), false, true, write_attributes);
    1379           14 :                         do_write_signature (m, tag_name, instance, finish_name, get_ccode_finish_name (m), m.get_async_end_parameters (), m.return_type, m.tree_can_fail, false, write_attributes);
    1380              :                 } else {
    1381           99 :                         do_write_signature (m, tag_name, instance, name, get_ccode_name (m), m.get_parameters (), m.return_type, m.tree_can_fail, true, write_attributes);
    1382              :                 }
    1383              :         }
    1384              : 
    1385          330 :         private void do_write_signature (Method m, string tag_name, bool instance, string name, string cname, List<Vala.Parameter> params, DataType return_type, bool can_fail, bool write_comment, bool write_attributes = true) {
    1386          165 :                 write_indent ();
    1387          165 :                 buffer.append_printf ("<%s name=\"%s\"", tag_name, name);
    1388          165 :                 if (tag_name == "virtual-method") {
    1389           37 :                         if (!get_ccode_no_wrapper (m)) {
    1390           28 :                                 buffer.append_printf (" invoker=\"%s\"", name);
    1391              :                         }
    1392          128 :                 } else if (tag_name == "callback") {
    1393              :                         /* this is only used for vfuncs */
    1394           39 :                         buffer.append_printf (" c:type=\"%s\"", name);
    1395              :                 } else {
    1396           89 :                         buffer.append_printf (" c:identifier=\"%s\"", cname);
    1397              :                 }
    1398          165 :                 if (can_fail) {
    1399           10 :                         buffer.append_printf (" throws=\"1\"");
    1400              :                 }
    1401          165 :                 if (write_attributes) {
    1402          126 :                         write_symbol_attributes (m);
    1403              :                 }
    1404          165 :                 buffer.append_printf (">\n");
    1405          165 :                 indent++;
    1406              : 
    1407          165 :                 string? return_comment = null;
    1408          165 :                 if (write_comment) {
    1409          113 :                         return_comment = get_method_return_comment (m);
    1410          113 :                         write_doc (get_method_comment (m), m.comment);
    1411              :                 }
    1412              : 
    1413          165 :                 write_params_and_return (m, tag_name, params, m.get_type_parameters (), return_type, get_ccode_array_length (m), return_comment, false, m.this_parameter);
    1414              : 
    1415          165 :                 indent--;
    1416          165 :                 write_indent ();
    1417          165 :                 buffer.append_printf ("</%s>\n", tag_name);
    1418              :         }
    1419              : 
    1420           47 :         public override void visit_creation_method (CreationMethod m) {
    1421           24 :                 if (m.external_package) {
    1422              :                         return;
    1423              :                 }
    1424              : 
    1425           24 :                 if (!check_accessibility (m)) {
    1426              :                         return;
    1427              :                 }
    1428              : 
    1429           24 :                 if (m.parent_symbol is Class && ((Class) m.parent_symbol).is_abstract) {
    1430              :                         return;
    1431              :                 }
    1432              : 
    1433           23 :                 write_indent ();
    1434              : 
    1435           23 :                 bool is_struct = m.parent_symbol is Struct;
    1436              :                 // GI doesn't like constructors that return void type
    1437           23 :                 string tag_name = is_struct ? "method" : "constructor";
    1438              : 
    1439           23 :                 if (m.parent_symbol is Class && m == ((Class)m.parent_symbol).default_construction_method ||
    1440            9 :                         m.parent_symbol is Struct && m == ((Struct)m.parent_symbol).default_construction_method) {
    1441           16 :                         string m_name = is_struct ? "init" : "new";
    1442           16 :                         buffer.append_printf ("<%s name=\"%s\" c:identifier=\"%s\"", tag_name, m_name, get_ccode_name (m));
    1443            7 :                 } else if (is_struct) {
    1444            2 :                         buffer.append_printf ("<%s name=\"init_%s\" c:identifier=\"%s\"", tag_name, m.name, get_ccode_name (m));
    1445              :                 } else {
    1446            5 :                         buffer.append_printf ("<%s name=\"%s\" c:identifier=\"%s\"", tag_name, m.name, get_ccode_name (m));
    1447              :                 }
    1448              : 
    1449           23 :                 if (m.tree_can_fail) {
    1450            1 :                         buffer.append_printf (" throws=\"1\"");
    1451              :                 }
    1452           23 :                 write_symbol_attributes (m);
    1453           23 :                 buffer.append_printf (">\n");
    1454           23 :                 indent++;
    1455              : 
    1456           23 :                 write_doc (get_method_comment (m), m.comment);
    1457              : 
    1458           23 :                 var datatype = SemanticAnalyzer.get_data_type_for_symbol (m.parent_symbol);
    1459           23 :                 List<TypeParameter>? type_params = null;
    1460           23 :                 if (m.parent_symbol is Class) {
    1461           19 :                         type_params = ((Class) m.parent_symbol).get_type_parameters ();
    1462              :                 }
    1463           23 :                 write_params_and_return (m, tag_name, m.get_parameters (), type_params, datatype, false, get_method_return_comment (m), true);
    1464              : 
    1465           23 :                 indent--;
    1466           23 :                 write_indent ();
    1467           23 :                 buffer.append_printf ("</%s>\n", tag_name);
    1468              :         }
    1469              : 
    1470           10 :         public override void visit_property (Property prop) {
    1471           10 :                 if (!check_accessibility (prop) || prop.overrides || (prop.base_interface_property != null && !prop.is_abstract && !prop.is_virtual)) {
    1472            4 :                         return;
    1473              :                 }
    1474              : 
    1475            6 :                 if (context.analyzer.is_gobject_property (prop)) {
    1476            5 :                         write_indent ();
    1477            5 :                         buffer.append_printf ("<property name=\"%s\"", get_ccode_name (prop));
    1478            5 :                         if (prop.get_accessor == null) {
    1479            2 :                                 buffer.append_printf (" readable=\"0\"");
    1480              :                         }
    1481            5 :                         if (prop.set_accessor != null) {
    1482            5 :                                 buffer.append_printf (" writable=\"1\"");
    1483            5 :                                 if (prop.set_accessor.construction) {
    1484            4 :                                         if (!prop.set_accessor.writable) {
    1485            1 :                                                 buffer.append_printf (" construct-only=\"1\"");
    1486              :                                         } else {
    1487            3 :                                                 buffer.append_printf (" construct=\"1\"");
    1488              :                                         }
    1489              :                                 }
    1490              :                         }
    1491            5 :                         write_symbol_attributes (prop);
    1492            5 :                         buffer.append_printf (">\n");
    1493            5 :                         indent++;
    1494              : 
    1495            5 :                         write_doc (get_property_comment (prop), prop.comment);
    1496              : 
    1497            5 :                         write_type (prop.property_type);
    1498              : 
    1499            5 :                         indent--;
    1500            5 :                         write_indent ();
    1501            5 :                         buffer.append_printf ("</property>\n");
    1502              :                 }
    1503              : 
    1504           10 :                 if (prop.get_accessor != null && prop.get_accessor.readable) {
    1505            4 :                         var m = prop.get_accessor.get_method ();
    1506            4 :                         if (m != null) {
    1507            4 :                                 visit_method (m);
    1508              :                         }
    1509              :                 }
    1510              : 
    1511           11 :                 if (prop.set_accessor != null && prop.set_accessor.writable) {
    1512            5 :                         var m = prop.set_accessor.get_method ();
    1513            5 :                         if (m != null) {
    1514            5 :                                 visit_method (m);
    1515              :                         }
    1516              :                 }
    1517              :         }
    1518              : 
    1519            4 :         public override void visit_signal (Signal sig) {
    1520            4 :                 if (!check_accessibility (sig)) {
    1521              :                         return;
    1522              :                 }
    1523              : 
    1524            4 :                 if (sig.emitter != null) {
    1525            1 :                         sig.emitter.accept (this);
    1526              :                 }
    1527              : 
    1528            4 :                 if (sig.default_handler != null) {
    1529            1 :                         sig.default_handler.accept (this);
    1530              :                 }
    1531              : 
    1532            4 :                 write_indent ();
    1533            4 :                 buffer.append_printf ("<glib:signal name=\"%s\"", get_ccode_name (sig));
    1534            4 :                 write_symbol_attributes (sig);
    1535            4 :                 buffer.append_printf (">\n");
    1536            4 :                 indent++;
    1537              : 
    1538            4 :                 write_doc (get_signal_comment (sig), sig.comment);
    1539              : 
    1540            4 :                 write_params_and_return (sig, "glib:signal", sig.get_parameters (), null, sig.return_type, false, get_signal_return_comment (sig));
    1541              : 
    1542            4 :                 indent--;
    1543            4 :                 write_indent ();
    1544            4 :                 buffer.append_printf ("</glib:signal>\n");
    1545              :         }
    1546              : 
    1547         3207 :         private void write_indent () {
    1548              :                 int i;
    1549              : 
    1550        14327 :                 for (i = 0; i < indent; i++) {
    1551        25447 :                         buffer.append_c ('\t');
    1552              :                 }
    1553              :         }
    1554              : 
    1555            7 :         private void write_indent_stream () {
    1556              :                 int i;
    1557              : 
    1558            7 :                 for (i = 0; i < indent; i++) {
    1559            0 :                         stream.putc ('\t');
    1560              :                 }
    1561              :         }
    1562              : 
    1563              : 
    1564          603 :         private void write_param_or_return (DataType? type, string tag, ref int index, bool has_array_length, string? name = null, Comment? parent_comment = null, string? comment = null, ParameterDirection direction = ParameterDirection.IN, bool constructor = false, bool caller_allocates = false, bool ellipsis = false) {
    1565          603 :                 write_indent ();
    1566          603 :                 buffer.append_printf ("<%s", tag);
    1567          603 :                 if (ellipsis) {
    1568              :                         name = "...";
    1569              :                 }
    1570          601 :                 if (name != null) {
    1571          406 :                         buffer.append_printf (" name=\"%s\"", name);
    1572              :                 }
    1573          603 :                 if (direction == ParameterDirection.REF) {
    1574            7 :                         buffer.append_printf (" direction=\"inout\"");
    1575          596 :                 } else if (direction == ParameterDirection.OUT) {
    1576           39 :                         buffer.append_printf (" direction=\"out\"");
    1577              :                 }
    1578              : 
    1579          603 :                 unowned DelegateType? delegate_type = type as DelegateType;
    1580          603 :                 unowned ArrayType? array_type = type as ArrayType;
    1581              : 
    1582          603 :                 if (type != null && ((type.value_owned && delegate_type == null) || (constructor
    1583           23 :                     && !(type.type_symbol is Struct || type.type_symbol.is_subtype_of (ginitiallyunowned_type))))) {
    1584          171 :                         var any_owned = false;
    1585          185 :                         foreach (var generic_arg in type.get_type_arguments ()) {
    1586            7 :                                 any_owned |= generic_arg.value_owned;
    1587              :                         }
    1588          171 :                         if (type.has_type_arguments () && !any_owned) {
    1589            1 :                                 buffer.append_printf (" transfer-ownership=\"container\"");
    1590          170 :                         } else if (array_type != null && !array_type.element_type.value_owned) {
    1591            1 :                                 buffer.append_printf (" transfer-ownership=\"container\"");
    1592              :                         } else {
    1593          169 :                                 buffer.append_printf (" transfer-ownership=\"full\"");
    1594              :                         }
    1595              :                 } else {
    1596          432 :                         buffer.append_printf (" transfer-ownership=\"none\"");
    1597              :                 }
    1598          603 :                 if (caller_allocates) {
    1599            6 :                         buffer.append_printf (" caller-allocates=\"1\"");
    1600              :                 }
    1601          603 :                 if (type != null && type.nullable) {
    1602           72 :                         if (tag == "parameter"
    1603           64 :                             && (direction == ParameterDirection.OUT || direction == ParameterDirection.REF)) {
    1604            4 :                                 buffer.append_printf (" optional=\"1\"");
    1605              :                         } else {
    1606           68 :                                 buffer.append_printf (" nullable=\"1\"");
    1607              :                         }
    1608              :                 }
    1609              : 
    1610          603 :                 if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
    1611           38 :                         int closure_index = tag == "parameter" ?
    1612           38 :                                 index + 1 : (type.value_owned ? index - 1 : index);
    1613           38 :                         buffer.append_printf (" closure=\"%i\"", closure_index);
    1614           38 :                         if (delegate_type.is_called_once) {
    1615           22 :                                 buffer.append (" scope=\"async\"");
    1616           16 :                         } else if (type.value_owned) {
    1617           14 :                                 buffer.append_printf (" scope=\"notified\" destroy=\"%i\"", closure_index + 1);
    1618              :                         } else {
    1619            2 :                                 buffer.append (" scope=\"call\"");
    1620              :                         }
    1621          565 :                 } else if (delegate_type != null) {
    1622           15 :                         buffer.append (" scope=\"call\"");
    1623              :                 }
    1624              : 
    1625          603 :                 buffer.append_printf (">\n");
    1626          603 :                 indent++;
    1627              : 
    1628          603 :                 write_doc (comment, parent_comment);
    1629              : 
    1630          603 :                 if (ellipsis) {
    1631            2 :                         write_indent ();
    1632            2 :                         buffer.append ("<varargs/>\n");
    1633          601 :                 } else if (type != null) {
    1634          601 :                         int length_param_index = -1;
    1635          601 :                         if (has_array_length) {
    1636          369 :                                 length_param_index = tag == "parameter" ? index + 1 : index;
    1637              :                         }
    1638              : 
    1639          601 :                         bool additional_indirection = direction != ParameterDirection.IN;
    1640          601 :                         if (!additional_indirection && tag == "parameter" && !type.nullable) {
    1641              :                                 // pass non-simple structs always by reference
    1642          192 :                                 unowned Struct? st = type.type_symbol as Struct;
    1643           81 :                                 if (st != null && !st.is_simple_type ()) {
    1644          601 :                                         additional_indirection = true;
    1645              :                                 }
    1646              :                         }
    1647              : 
    1648          601 :                         write_type (type, length_param_index, additional_indirection);
    1649              :                 }
    1650              : 
    1651          603 :                 indent--;
    1652          603 :                 write_indent ();
    1653          603 :                 buffer.append_printf ("</%s>\n", tag);
    1654          603 :                 index++;
    1655              :         }
    1656              : 
    1657           50 :         private void write_ctype_attributes (TypeSymbol symbol, string suffix = "", bool symbol_prefix = false) {
    1658           50 :                 buffer.append_printf (" c:type=\"%s%s\"", get_ccode_name (symbol), suffix);
    1659           50 :                 if (symbol_prefix) {
    1660           21 :                         buffer.append_printf (" c:symbol-prefix=\"%s\"", get_ccode_lower_case_suffix (symbol));
    1661              :                 }
    1662              :         }
    1663              : 
    1664           28 :         private void write_gtype_attributes (TypeSymbol symbol, bool symbol_prefix = false) {
    1665           28 :                 write_ctype_attributes(symbol, "", symbol_prefix);
    1666           28 :                 buffer.append_printf (" glib:type-name=\"%s\"", get_ccode_name (symbol));
    1667           28 :                 buffer.append_printf (" glib:get-type=\"%sget_type\"", get_ccode_lower_case_prefix (symbol));
    1668              :         }
    1669              : 
    1670          670 :         private void write_type (DataType type, int index = -1, bool additional_indirection = false) {
    1671          696 :                 if (type is ArrayType) {
    1672           26 :                         var array_type = (ArrayType) type;
    1673              : 
    1674           26 :                         write_indent ();
    1675           26 :                         buffer.append_printf ("<array");
    1676           27 :                         if (array_type.fixed_length && array_type.length is IntegerLiteral) {
    1677            1 :                                 var lit = (IntegerLiteral) array_type.length;
    1678            1 :                                 buffer.append_printf (" fixed-size=\"%i\"", int.parse (lit.value));
    1679           25 :                         } else if (index != -1) {
    1680           24 :                                 buffer.append_printf (" length=\"%i\"", index);
    1681              :                         }
    1682           26 :                         buffer.append_printf (" c:type=\"%s%s\"", get_ccode_name (array_type.element_type), !additional_indirection ? "*" : "**");
    1683           26 :                         buffer.append_printf (">\n");
    1684           26 :                         indent++;
    1685              : 
    1686           26 :                         write_type (array_type.element_type);
    1687              : 
    1688           26 :                         indent--;
    1689           26 :                         write_indent ();
    1690           26 :                         buffer.append_printf ("</array>\n");
    1691          644 :                 } else if (type is VoidType) {
    1692          145 :                         write_indent ();
    1693          145 :                         buffer.append_printf ("<type name=\"none\" c:type=\"void\"/>\n");
    1694          499 :                 } else if (type is PointerType) {
    1695           40 :                         write_indent ();
    1696           40 :                         buffer.append_printf ("<type name=\"gpointer\" c:type=\"%s%s\"/>\n", get_ccode_name (type), !additional_indirection ? "" : "*");
    1697          459 :                 } else if (type is GenericType) {
    1698              :                         // generic type parameters not supported in GIR
    1699           14 :                         write_indent ();
    1700           14 :                         buffer.append ("<type name=\"gpointer\" c:type=\"gpointer\"/>\n");
    1701          499 :                 } else if (type is DelegateType) {
    1702           54 :                         var deleg_type = (DelegateType) type;
    1703           54 :                         write_indent ();
    1704           54 :                         buffer.append_printf ("<type name=\"%s\" c:type=\"%s%s\"/>\n", gi_type_name (deleg_type.delegate_symbol), get_ccode_name (type), !additional_indirection ? "" : "*");
    1705          782 :                 } else if (type.type_symbol != null) {
    1706          391 :                         write_indent ();
    1707          391 :                         string type_name = gi_type_name (type.type_symbol);
    1708          391 :                         bool is_array = false;
    1709          391 :                         if ((type_name == "GLib.Array") || (type_name == "GLib.PtrArray")) {
    1710              :                                 is_array = true;
    1711              :                         }
    1712          391 :                         buffer.append_printf ("<%s name=\"%s\" c:type=\"%s%s\"", is_array ? "array" : "type", gi_type_name (type.type_symbol), get_ccode_name (type), !additional_indirection ? "" : "*");
    1713              : 
    1714          391 :                         List<DataType> type_arguments = type.get_type_arguments ();
    1715          391 :                         if (type_arguments.size == 0) {
    1716          385 :                                 buffer.append_printf ("/>\n");
    1717              :                         } else {
    1718            6 :                                 buffer.append_printf (">\n");
    1719            6 :                                 indent++;
    1720              : 
    1721           28 :                                 foreach (DataType type_argument in type_arguments) {
    1722           11 :                                         write_type (type_argument);
    1723              :                                 }
    1724              : 
    1725            6 :                                 indent--;
    1726            6 :                                 write_indent ();
    1727            6 :                                 buffer.append_printf ("</%s>\n", is_array ? "array" : "type");
    1728              :                         }
    1729              :                 } else {
    1730            0 :                         write_indent ();
    1731            0 :                         buffer.append_printf ("<type name=\"%s\"/>\n", type.to_string ());
    1732              :                 }
    1733              :         }
    1734              : 
    1735          676 :         private string? get_full_gir_name (Symbol sym) {
    1736          676 :                 string? gir_fullname = sym.get_attribute_string ("GIR", "fullname");
    1737          676 :                 if (gir_fullname != null) {
    1738          676 :                         return gir_fullname;
    1739              :                 }
    1740              : 
    1741          676 :                 string? gir_name = sym.get_attribute_string ("GIR", "name");
    1742              : 
    1743          676 :                 if (gir_name == null && sym is Namespace) {
    1744          338 :                         gir_name = sym.get_attribute_string ("CCode", "gir_namespace");
    1745              :                 }
    1746          676 :                 if (gir_name == null) {
    1747          708 :                         gir_name = sym.name;
    1748              :                 }
    1749              : 
    1750          676 :                 if (sym.parent_symbol == null) {
    1751          338 :                         return gir_name;
    1752              :                 }
    1753              : 
    1754          338 :                 if (sym.name == null) {
    1755            0 :                         return get_full_gir_name (sym.parent_symbol);
    1756              :                 }
    1757              : 
    1758          338 :                 string parent_gir_name = get_full_gir_name (sym.parent_symbol);
    1759          338 :                 if (parent_gir_name == null) {
    1760          338 :                         return gir_name;
    1761              :                 }
    1762              : 
    1763            0 :                 string self_gir_name = gir_name.has_prefix (".") ? gir_name.substring (1) : gir_name;
    1764            0 :                 if ("." in parent_gir_name) {
    1765            0 :                         return "%s%s".printf (parent_gir_name, self_gir_name);
    1766              :                 } else {
    1767            0 :                         return "%s.%s".printf (parent_gir_name, self_gir_name);
    1768              :                 }
    1769              :         }
    1770              : 
    1771          871 :         private string gi_type_name (TypeSymbol type_symbol) {
    1772          871 :                 Symbol parent = type_symbol.parent_symbol;
    1773         1209 :                 if (parent is Namespace) {
    1774          871 :                         Namespace ns = parent as Namespace;
    1775         1742 :                         var ns_gir_name = ns.get_attribute_string ("GIR", "name") ?? ns.name;
    1776          871 :                         if (ns_gir_name != null) {
    1777          533 :                                 unowned SourceFile source_file = type_symbol.source_reference.file;
    1778          533 :                                 if (source_file.gir_namespace != null) {
    1779              :                                         GIRNamespace external;
    1780          533 :                                         if (source_file.gir_ambiguous) {
    1781           12 :                                                 external = GIRNamespace.for_symbol (type_symbol);
    1782              :                                         } else {
    1783          521 :                                                 external = GIRNamespace (source_file.gir_namespace, source_file.gir_version);
    1784              :                                         }
    1785          533 :                                         if (!externals.contains (external)) {
    1786            9 :                                                 externals.add (external);
    1787              :                                         }
    1788          533 :                                         string? gir_fullname = type_symbol.get_attribute_string ("GIR", "fullname");
    1789          533 :                                         if (gir_fullname != null) {
    1790            0 :                                                 return gir_fullname;
    1791              :                                         }
    1792         1030 :                                         var type_name = type_symbol.get_attribute_string ("GIR", "name") ?? type_symbol.name;
    1793          533 :                                         return "%s.%s".printf (external.ns, type_name);
    1794              :                                 } else {
    1795            0 :                                         unannotated_namespaces.add(ns);
    1796              :                                 }
    1797              :                         }
    1798              :                 }
    1799              : 
    1800          338 :                 return get_full_gir_name (type_symbol);
    1801              :         }
    1802              : 
    1803           13 :         private string? literal_expression_to_value_string (Expression literal) {
    1804           13 :                 if (literal is StringLiteral) {
    1805            1 :                         var lit = literal as StringLiteral;
    1806            1 :                         if (lit != null) {
    1807            1 :                                 return Markup.escape_text (lit.eval ());
    1808              :                         }
    1809           12 :                 } else if (literal is CharacterLiteral) {
    1810            1 :                         return "%c".printf ((char) ((CharacterLiteral) literal).get_char ());
    1811           11 :                 } else if (literal is BooleanLiteral) {
    1812            4 :                         return ((BooleanLiteral) literal).value ? "true" : "false";
    1813            9 :                 } else if (literal is RealLiteral) {
    1814            2 :                         return ((RealLiteral) literal).value;
    1815            8 :                 } else if (literal is IntegerLiteral) {
    1816           14 :                         return ((IntegerLiteral) literal).value;
    1817            1 :                 } else if (literal is UnaryExpression) {
    1818            1 :                         var unary = (UnaryExpression) literal;
    1819            1 :                         if (unary.operator == UnaryOperator.MINUS) {
    1820            1 :                                 if (unary.inner is RealLiteral) {
    1821            1 :                                         return "-" + ((RealLiteral) unary.inner).value;
    1822            0 :                                 } else if (unary.inner is IntegerLiteral) {
    1823            0 :                                         return "-" + ((IntegerLiteral) unary.inner).value;
    1824              :                                 }
    1825              :                         }
    1826              :                 }
    1827           13 :                 return null;
    1828              :         }
    1829              : 
    1830          211 :         private bool check_accessibility (Symbol sym) {
    1831          211 :                 if (sym.access == SymbolAccessibility.PUBLIC ||
    1832           18 :                     sym.access == SymbolAccessibility.PROTECTED) {
    1833          194 :                         return true;
    1834              :                 }
    1835              : 
    1836              :                 // internal fields and function pointers in classes/interfaces are public API
    1837           17 :                 if (sym.access == SymbolAccessibility.INTERNAL) {
    1838            8 :                         unowned Symbol? parent = sym.parent_symbol;
    1839            8 :                         if (parent != null
    1840            8 :                             && (parent is Class || parent is Interface)
    1841            8 :                             && ((sym is Field && ((Field) sym).binding == MemberBinding.INSTANCE)
    1842            7 :                             || (sym is Method && ((Method) sym).binding == MemberBinding.INSTANCE && (((Method) sym).is_abstract || ((Method) sym).is_virtual)))) {
    1843            4 :                                 return true;
    1844              :                         }
    1845              :                 }
    1846              : 
    1847          211 :                 return false;
    1848              :         }
    1849              : 
    1850          282 :         private bool is_visibility (Symbol sym) {
    1851          282 :                 return sym.get_attribute_bool ("GIR", "visible", true);
    1852              :         }
    1853              : 
    1854          163 :         bool has_namespace (Symbol sym) {
    1855          163 :                 if (!(sym.parent_symbol is Namespace) || sym.parent_symbol.name != null) {
    1856          154 :                         return true;
    1857              :                 }
    1858              : 
    1859            9 :                 Report.warning (sym.source_reference, "`%s' must be part of namespace to be included in GIR", sym.name);
    1860            9 :                 return false;
    1861              :         }
    1862              : }
        

Generated by: LCOV version 2.0-1