change run to use meson/ninja and then exec. - remove libvala code from application...
[roobuilder] / src / codegen / valagtypemodule.vala
1 /* valagtypemodule.vala
2  *
3  * Copyright (C) 2006-2010  Jürg Billeter
4  * Copyright (C) 2006-2008  Raffaele Sandrini
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19  *
20  * Author:
21  *      Jürg Billeter <j@bitron.ch>
22  *      Raffaele Sandrini <raffaele@sandrini.ch>
23  */
24
25
26 public class Vala.GTypeModule : GErrorModule {
27         public override CCodeParameter generate_parameter (Parameter param, CCodeFile decl_space, Map<int,CCodeParameter> cparam_map, Map<int,CCodeExpression>? carg_map) {
28                 if (!(param.variable_type is ObjectType)) {
29                         return base.generate_parameter (param, decl_space, cparam_map, carg_map);
30                 }
31
32                 generate_type_declaration (param.variable_type, decl_space);
33
34                 string? ctypename = get_ccode_type (param);
35                 if (ctypename == null) {
36                         ctypename = get_ccode_name (param.variable_type);
37
38                         if (param.direction != ParameterDirection.IN) {
39                                 ctypename = "%s*".printf (ctypename);
40                         }
41                 }
42
43                 var cparam = new CCodeParameter (get_ccode_name (param), ctypename);
44                 if (param.format_arg) {
45                         cparam.modifiers = CCodeModifiers.FORMAT_ARG;
46                 }
47
48                 cparam_map.set (get_param_pos (get_ccode_pos (param)), cparam);
49                 if (carg_map != null) {
50                         carg_map.set (get_param_pos (get_ccode_pos (param)), get_parameter_cexpression (param));
51                 }
52
53                 return cparam;
54         }
55
56         public override void generate_class_declaration (Class cl, CCodeFile decl_space) {
57                 if (add_symbol_declaration (decl_space, cl, get_ccode_name (cl))) {
58                         return;
59                 }
60
61                 if (cl.base_class != null) {
62                         // base class declaration
63                         // necessary for ref and unref function declarations
64                         generate_class_declaration (cl.base_class, decl_space);
65                 }
66
67                 bool is_gtypeinstance = !cl.is_compact;
68                 bool is_fundamental = is_gtypeinstance && cl.base_class == null;
69                 bool is_gsource = cl.is_subtype_of (gsource_type);
70
71                 if (is_gtypeinstance) {
72                         decl_space.add_include ("glib-object.h");
73
74                         decl_space.add_type_declaration (new CCodeNewline ());
75                         var macro = "(%s_get_type ())".printf (get_ccode_lower_case_name (cl, null));
76                         decl_space.add_type_declaration (new CCodeMacroReplacement (get_ccode_type_id (cl), macro));
77
78                         macro = "(G_TYPE_CHECK_INSTANCE_CAST ((obj), %s, %s))".printf (get_ccode_type_id (cl), get_ccode_name (cl));
79                         decl_space.add_type_declaration (new CCodeMacroReplacement ("%s(obj)".printf (get_ccode_type_cast_function (cl)), macro));
80
81                         if (!(cl.is_sealed && decl_space.file_type == CCodeFileType.PUBLIC_HEADER)) {
82                                 macro = "(G_TYPE_CHECK_CLASS_CAST ((klass), %s, %s))".printf (get_ccode_type_id (cl), get_ccode_type_name (cl));
83                                 decl_space.add_type_declaration (new CCodeMacroReplacement ("%s(klass)".printf (get_ccode_class_type_function (cl)), macro));
84                         }
85
86                         macro = "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), %s))".printf (get_ccode_type_id (cl));
87                         decl_space.add_type_declaration (new CCodeMacroReplacement ("%s(obj)".printf (get_ccode_type_check_function (cl)), macro));
88
89                         if (!(cl.is_sealed && decl_space.file_type == CCodeFileType.PUBLIC_HEADER)) {
90                                 macro = "(G_TYPE_CHECK_CLASS_TYPE ((klass), %s))".printf (get_ccode_type_id (cl));
91                                 decl_space.add_type_declaration (new CCodeMacroReplacement ("%s(klass)".printf (get_ccode_class_type_check_function (cl)), macro));
92                         }
93
94                         if (!(cl.is_sealed && decl_space.file_type == CCodeFileType.PUBLIC_HEADER)) {
95                                 macro = "(G_TYPE_INSTANCE_GET_CLASS ((obj), %s, %s))".printf (get_ccode_type_id (cl), get_ccode_type_name (cl));
96                                 decl_space.add_type_declaration (new CCodeMacroReplacement ("%s(obj)".printf (get_ccode_type_get_function (cl)), macro));
97                         }
98                         decl_space.add_type_declaration (new CCodeNewline ());
99                 }
100
101                 if (!(!cl.is_compact || cl.base_class == null || compact_class_has_instance_struct_member (cl))) {
102                         decl_space.add_type_declaration (new CCodeTypeDefinition (get_ccode_name (cl.base_class), new CCodeVariableDeclarator (get_ccode_name (cl))));
103                 } else {
104                         decl_space.add_type_declaration (new CCodeTypeDefinition ("struct _%s".printf (get_ccode_name (cl)), new CCodeVariableDeclarator (get_ccode_name (cl))));
105                 }
106
107                 if (is_fundamental) {
108                         var ref_fun = new CCodeFunction (get_ccode_ref_function (cl), "gpointer");
109                         var unref_fun = new CCodeFunction (get_ccode_unref_function (cl), "void");
110                         if (cl.is_private_symbol ()) {
111                                 ref_fun.modifiers = CCodeModifiers.STATIC;
112                                 unref_fun.modifiers = CCodeModifiers.STATIC;
113                         } else if (context.hide_internal && cl.is_internal_symbol ()) {
114                                 ref_fun.modifiers = CCodeModifiers.INTERNAL;
115                                 unref_fun.modifiers = CCodeModifiers.INTERNAL;
116                         } else {
117                                 ref_fun.modifiers = CCodeModifiers.EXTERN;
118                                 unref_fun.modifiers = CCodeModifiers.EXTERN;
119                                 requires_vala_extern = true;
120                         }
121
122                         ref_fun.add_parameter (new CCodeParameter ("instance", "gpointer"));
123                         unref_fun.add_parameter (new CCodeParameter ("instance", "gpointer"));
124
125                         decl_space.add_function_declaration (ref_fun);
126                         decl_space.add_function_declaration (unref_fun);
127
128                         // GParamSpec and GValue functions
129                         var function = new CCodeFunction (get_ccode_param_spec_function (cl), "GParamSpec*");
130                         function.add_parameter (new CCodeParameter ("name", "const gchar*"));
131                         function.add_parameter (new CCodeParameter ("nick", "const gchar*"));
132                         function.add_parameter (new CCodeParameter ("blurb", "const gchar*"));
133                         function.add_parameter (new CCodeParameter ("object_type", "GType"));
134                         function.add_parameter (new CCodeParameter ("flags", "GParamFlags"));
135
136                         if (cl.is_private_symbol ()) {
137                                 // avoid C warning as this function is not always used
138                                 function.modifiers = CCodeModifiers.STATIC | CCodeModifiers.UNUSED;
139                         } else if (context.hide_internal && cl.is_internal_symbol ()) {
140                                 function.modifiers = CCodeModifiers.INTERNAL;
141                         } else {
142                                 function.modifiers = CCodeModifiers.EXTERN;
143                                 requires_vala_extern = true;
144                         }
145
146                         decl_space.add_function_declaration (function);
147
148                         function = new CCodeFunction (get_ccode_set_value_function (cl), "void");
149                         function.add_parameter (new CCodeParameter ("value", "GValue*"));
150                         function.add_parameter (new CCodeParameter ("v_object", "gpointer"));
151
152                         if (cl.is_private_symbol ()) {
153                                 // avoid C warning as this function is not always used
154                                 function.modifiers = CCodeModifiers.STATIC | CCodeModifiers.UNUSED;
155                         } else if (context.hide_internal && cl.is_internal_symbol ()) {
156                                 // avoid C warning as this function is not always used
157                                 function.modifiers = CCodeModifiers.INTERNAL | CCodeModifiers.UNUSED;
158                         } else {
159                                 function.modifiers = CCodeModifiers.EXTERN;
160                                 requires_vala_extern = true;
161                         }
162
163                         decl_space.add_function_declaration (function);
164
165                         function = new CCodeFunction (get_ccode_take_value_function (cl), "void");
166                         function.add_parameter (new CCodeParameter ("value", "GValue*"));
167                         function.add_parameter (new CCodeParameter ("v_object", "gpointer"));
168
169                         if (cl.is_private_symbol ()) {
170                                 // avoid C warning as this function is not always used
171                                 function.modifiers = CCodeModifiers.STATIC | CCodeModifiers.UNUSED;
172                         } else if (context.hide_internal && cl.is_internal_symbol ()) {
173                                 function.modifiers = CCodeModifiers.INTERNAL;
174                         } else {
175                                 function.modifiers = CCodeModifiers.EXTERN;
176                                 requires_vala_extern = true;
177                         }
178
179                         decl_space.add_function_declaration (function);
180
181                         function = new CCodeFunction (get_ccode_get_value_function (cl), "gpointer");
182                         function.add_parameter (new CCodeParameter ("value", "const GValue*"));
183
184                         if (cl.is_private_symbol ()) {
185                                 // avoid C warning as this function is not always used
186                                 function.modifiers = CCodeModifiers.STATIC | CCodeModifiers.UNUSED;
187                         } else if (context.hide_internal && cl.is_internal_symbol ()) {
188                                 // avoid C warning as this function is not always used
189                                 function.modifiers = CCodeModifiers.INTERNAL | CCodeModifiers.UNUSED;
190                         } else {
191                                 function.modifiers = CCodeModifiers.EXTERN;
192                                 requires_vala_extern = true;
193                         }
194
195                         decl_space.add_function_declaration (function);
196                 } else if (!is_gtypeinstance && !is_gsource) {
197                         if (cl.base_class == null) {
198                                 var function = new CCodeFunction (get_ccode_free_function (cl), "void");
199                                 if (cl.is_private_symbol ()) {
200                                         function.modifiers = CCodeModifiers.STATIC;
201                                 } else if (context.hide_internal && cl.is_internal_symbol ()) {
202                                         function.modifiers = CCodeModifiers.INTERNAL;
203                                 } else {
204                                         function.modifiers = CCodeModifiers.EXTERN;
205                                         requires_vala_extern = true;
206                                 }
207
208                                 function.add_parameter (new CCodeParameter ("self", "%s *".printf (get_ccode_name (cl))));
209
210                                 decl_space.add_function_declaration (function);
211                         }
212                 }
213
214                 if (is_gtypeinstance && !(cl.is_sealed && decl_space.file_type == CCodeFileType.PUBLIC_HEADER)) {
215                         decl_space.add_type_declaration (new CCodeTypeDefinition ("struct _%s".printf (get_ccode_type_name (cl)), new CCodeVariableDeclarator (get_ccode_type_name (cl))));
216
217                         var type_fun = new ClassRegisterFunction (cl);
218                         type_fun.init_from_type (context, in_plugin, true);
219                         decl_space.add_type_member_declaration (type_fun.get_declaration ());
220
221                         requires_vala_extern = true;
222                 }
223
224                 var base_class = cl;
225                 while (base_class.base_class != null) {
226                         base_class = base_class.base_class;
227                 }
228                 // Custom unref-methods need to be emitted before G_DEFINE_AUTOPTR_CLEANUP_FUNC,
229                 // so we guard against that special case and handle it in generate_method_declaration.
230                 if (!(base_class.is_compact && is_reference_counting (base_class))
231                     && (context.header_filename == null|| decl_space.file_type == CCodeFileType.PUBLIC_HEADER
232                         || (decl_space.file_type == CCodeFileType.INTERNAL_HEADER && base_class.is_internal_symbol()))) {
233                         string autoptr_cleanup_func;
234                         if (is_reference_counting (base_class)) {
235                                 autoptr_cleanup_func = get_ccode_unref_function (base_class);
236                         } else {
237                                 autoptr_cleanup_func = get_ccode_free_function (base_class);
238                         }
239                         if (autoptr_cleanup_func == null || autoptr_cleanup_func == "") {
240                                 Report.error (cl.source_reference, "internal error: autoptr_cleanup_func not available");
241                         }
242                         decl_space.add_type_member_declaration (new CCodeIdentifier ("G_DEFINE_AUTOPTR_CLEANUP_FUNC (%s, %s)".printf (get_ccode_name (cl), autoptr_cleanup_func)));
243                         decl_space.add_type_member_declaration (new CCodeNewline ());
244                 }
245         }
246
247         public override void generate_class_struct_declaration (Class cl, CCodeFile decl_space) {
248                 if (add_symbol_declaration (decl_space, cl, "struct _%s".printf (get_ccode_name (cl)))) {
249                         return;
250                 }
251
252                 if (cl.base_class != null) {
253                         // base class declaration
254                         generate_class_struct_declaration (cl.base_class, decl_space);
255                 }
256                 foreach (DataType base_type in cl.get_base_types ()) {
257                         unowned Interface? iface = base_type.type_symbol as Interface;
258                         if (iface != null) {
259                                 generate_interface_declaration (iface, decl_space);
260                         }
261                 }
262
263                 generate_class_declaration (cl, decl_space);
264
265                 if (cl.is_sealed && decl_space.file_type == CCodeFileType.PUBLIC_HEADER) {
266                         return;
267                 }
268
269                 bool is_gtypeinstance = !cl.is_compact;
270                 bool is_fundamental = is_gtypeinstance && cl.base_class == null;
271
272                 var instance_struct = new CCodeStruct ("_%s".printf (get_ccode_name (cl)));
273                 var type_struct = new CCodeStruct ("_%s".printf (get_ccode_type_name (cl)));
274
275                 if (cl.base_class != null) {
276                         instance_struct.add_field (get_ccode_name (cl.base_class), "parent_instance");
277                 } else if (is_fundamental) {
278                         instance_struct.add_field ("GTypeInstance", "parent_instance");
279                         instance_struct.add_field ("volatile int", "ref_count");
280                 }
281
282                 if (is_gtypeinstance) {
283                         decl_space.add_type_declaration (new CCodeTypeDefinition ("struct %sPrivate".printf (instance_struct.name), new CCodeVariableDeclarator ("%sPrivate".printf (get_ccode_name (cl)))));
284
285                         if (!context.abi_stability) {
286                                 instance_struct.add_field ("%sPrivate *".printf (get_ccode_name (cl)), "priv");
287                         }
288                         if (is_fundamental) {
289                                 type_struct.add_field ("GTypeClass", "parent_class");
290                         } else {
291                                 type_struct.add_field (get_ccode_type_name (cl.base_class), "parent_class");
292                         }
293
294                         if (is_fundamental) {
295                                 type_struct.add_field ("void", "(*finalize) (%s *self)".printf (get_ccode_name (cl)));
296                         }
297                 }
298
299                 if (context.abi_stability) {
300                         foreach (Symbol s in cl.get_members ()) {
301                                 if (s is Method) {
302                                         var m = (Method) s;
303                                         generate_struct_method_declaration (cl, m, instance_struct, type_struct, decl_space);
304                                 } else if (s is Signal) {
305                                         var sig = (Signal) s;
306                                         if (sig.default_handler != null) {
307                                                 if (sig.is_virtual) {
308                                                         generate_virtual_method_declaration (sig.default_handler, decl_space, type_struct);
309                                                 } else {
310                                                         generate_method_declaration (sig.default_handler, cfile);
311                                                 }
312                                         }
313                                 } else if (s is Property) {
314                                         var prop = (Property) s;
315                                         generate_struct_property_declaration (cl, prop, instance_struct, type_struct, decl_space);
316                                 } else if (s is Field) {
317                                         if (s.access != SymbolAccessibility.PRIVATE || cl.is_opaque) {
318                                                 generate_struct_field_declaration ((Field) s, instance_struct, type_struct, decl_space);
319                                         }
320                                 } else {
321                                         Report.error (s.source_reference, "internal: Unsupported symbol");
322                                 }
323                         }
324                 } else {
325                         foreach (Method m in cl.get_methods ()) {
326                                 generate_struct_method_declaration (cl, m, instance_struct, type_struct, decl_space);
327                         }
328
329                         foreach (Signal sig in cl.get_signals ()) {
330                                 if (sig.default_handler != null) {
331                                         if (sig.is_virtual) {
332                                                 generate_virtual_method_declaration (sig.default_handler, decl_space, type_struct);
333                                         } else {
334                                                 generate_method_declaration (sig.default_handler, cfile);
335                                         }
336                                 }
337                         }
338
339                         foreach (Property prop in cl.get_properties ()) {
340                                 generate_struct_property_declaration (cl, prop, instance_struct, type_struct, decl_space);
341                         }
342
343                         foreach (Field f in cl.get_fields ()) {
344                                 if (f.access != SymbolAccessibility.PRIVATE || cl.is_opaque) {
345                                         generate_struct_field_declaration (f, instance_struct, type_struct, decl_space);
346                                 }
347                         }
348                 }
349
350                 if (cl.is_compact && cl.base_class == null && !compact_class_has_instance_struct_member (cl)) {
351                         // add dummy member, C doesn't allow empty structs
352                         instance_struct.add_field ("int", "dummy");
353                 }
354
355                 if (!cl.is_compact || cl.base_class == null || compact_class_has_instance_struct_member (cl)) {
356                         decl_space.add_type_definition (instance_struct);
357                 }
358
359                 if (is_gtypeinstance) {
360                         if (context.abi_stability) {
361                                 instance_struct.add_field ("%sPrivate *".printf (get_ccode_name (cl)), "priv");
362                         }
363                         decl_space.add_type_definition (type_struct);
364                 }
365         }
366
367         bool compact_class_has_instance_struct_member (Class cl) {
368                 assert (cl.is_compact);
369                 foreach (Symbol s in cl.get_members ()) {
370                         if (s is Method) {
371                                 unowned Method m = (Method) s;
372                                 if (m.is_abstract || m.is_virtual) {
373                                         return true;
374                                 }
375                         } else if (s is Property) {
376                                 unowned Property prop = (Property) s;
377                                 if (prop.is_abstract || prop.is_virtual) {
378                                         return true;
379                                 }
380                         } else if (s is Field) {
381                                 if (s.access != SymbolAccessibility.PRIVATE || cl.is_opaque) {
382                                         unowned Field f = (Field) s;
383                                         if (f.binding == MemberBinding.INSTANCE) {
384                                                 return true;
385                                         }
386                                 }
387                         } else {
388                                 Report.error (s.source_reference, "internal: Unsupported symbol");
389                         }
390                 }
391                 return false;
392         }
393
394         void generate_struct_method_declaration (ObjectTypeSymbol type_sym, Method m, CCodeStruct instance_struct, CCodeStruct type_struct, CCodeFile decl_space) {
395                 unowned Class? cl = type_sym as Class;
396                 if (type_sym is Interface || (cl != null && !cl.is_compact)) {
397                         generate_virtual_method_declaration (m, decl_space, type_struct);
398                 } else if (cl != null && cl.is_compact && cl.base_class == null) {
399                         generate_virtual_method_declaration (m, decl_space, instance_struct);
400                 }
401         }
402
403         void generate_struct_property_declaration (ObjectTypeSymbol type_sym, Property prop, CCodeStruct instance_struct, CCodeStruct type_struct, CCodeFile decl_space) {
404                 if (!prop.is_abstract && !prop.is_virtual) {
405                         return;
406                 }
407                 generate_type_declaration (prop.property_type, decl_space);
408
409                 unowned ObjectTypeSymbol t = (ObjectTypeSymbol) prop.parent_symbol;
410                 unowned Class? cl = type_sym as Class;
411
412                 var this_type = new ObjectType (t);
413                 var cselfparam = new CCodeParameter ("self", get_ccode_name (this_type));
414
415                 if (prop.get_accessor != null) {
416                         var vdeclarator = new CCodeFunctionDeclarator ("get_%s".printf (prop.name));
417                         vdeclarator.add_parameter (cselfparam);
418                         var creturn_type = get_callable_creturn_type (prop.get_accessor.get_method ());
419                         if (prop.property_type.is_real_non_null_struct_type ()) {
420                                 var cvalueparam = new CCodeParameter ("result", "%s *".printf (get_ccode_name (prop.get_accessor.value_type)));
421                                 vdeclarator.add_parameter (cvalueparam);
422                         }
423
424                         var array_type = prop.property_type as ArrayType;
425                         if (array_type != null && get_ccode_array_length (prop)) {
426                                 var length_ctype = get_ccode_array_length_type (prop) + "*";
427                                 for (int dim = 1; dim <= array_type.rank; dim++) {
428                                         vdeclarator.add_parameter (new CCodeParameter (get_array_length_cname ("result", dim), length_ctype));
429                                 }
430                         } else if ((prop.property_type is DelegateType) && get_ccode_delegate_target (prop) && ((DelegateType) prop.property_type).delegate_symbol.has_target) {
431                                 vdeclarator.add_parameter (new CCodeParameter (get_delegate_target_cname ("result"), "gpointer*"));
432                         }
433
434                         var vdecl = new CCodeDeclaration (get_ccode_name (creturn_type));
435                         vdecl.add_declarator (vdeclarator);
436                         type_struct.add_declaration (vdecl);
437
438                         if (cl != null && cl.is_compact && cl.base_class == null) {
439                                 instance_struct.add_declaration (vdecl);
440                         }
441                 }
442                 if (prop.set_accessor != null) {
443                         CCodeParameter cvalueparam;
444                         if (prop.property_type.is_real_non_null_struct_type ()) {
445                                 cvalueparam = new CCodeParameter ("value", "%s *".printf (get_ccode_name (prop.set_accessor.value_type)));
446                         } else {
447                                 cvalueparam = new CCodeParameter ("value", get_ccode_name (prop.set_accessor.value_type));
448                         }
449
450                         var vdeclarator = new CCodeFunctionDeclarator ("set_%s".printf (prop.name));
451                         vdeclarator.add_parameter (cselfparam);
452                         vdeclarator.add_parameter (cvalueparam);
453
454                         var array_type = prop.property_type as ArrayType;
455                         if (array_type != null && get_ccode_array_length (prop)) {
456                                 var length_ctype = get_ccode_array_length_type (prop);
457                                 for (int dim = 1; dim <= array_type.rank; dim++) {
458                                         vdeclarator.add_parameter (new CCodeParameter (get_array_length_cname ("value", dim), length_ctype));
459                                 }
460                         } else if ((prop.property_type is DelegateType) && get_ccode_delegate_target (prop) && ((DelegateType) prop.property_type).delegate_symbol.has_target) {
461                                 vdeclarator.add_parameter (new CCodeParameter (get_delegate_target_cname ("value"), "gpointer"));
462                                 if (prop.set_accessor.value_type.value_owned) {
463                                         vdeclarator.add_parameter (new CCodeParameter (get_delegate_target_destroy_notify_cname ("value"), get_ccode_name (delegate_target_destroy_type)));
464                                 }
465                         }
466
467                         var vdecl = new CCodeDeclaration ("void");
468                         vdecl.add_declarator (vdeclarator);
469                         type_struct.add_declaration (vdecl);
470
471                         if (cl != null && cl.is_compact && cl.base_class == null) {
472                                 instance_struct.add_declaration (vdecl);
473                         }
474                 }
475         }
476
477         void generate_struct_field_declaration (Field f, CCodeStruct instance_struct, CCodeStruct type_struct, CCodeFile decl_space) {
478                 CCodeModifiers modifiers = (f.is_volatile ? CCodeModifiers.VOLATILE : 0) | (f.version.deprecated ? CCodeModifiers.DEPRECATED : 0);
479                 if (f.binding == MemberBinding.INSTANCE) {
480                         append_field (instance_struct, f, decl_space);
481                 } else if (f.binding == MemberBinding.CLASS) {
482                         type_struct.add_field (get_ccode_name (f.variable_type), get_ccode_name (f), modifiers);
483                 }
484         }
485
486         public override bool generate_method_declaration (Method m, CCodeFile decl_space) {
487                 if (base.generate_method_declaration (m, decl_space)) {
488                         // Custom unref-methods need to be emitted before G_DEFINE_AUTOPTR_CLEANUP_FUNC,
489                         // in addition to the non-ref-countable case in generate_class_declaration.
490                         unowned Class? cl = m.parent_symbol as Class;
491                         if (cl != null && cl.is_compact && get_ccode_unref_function (cl) == get_ccode_name (m)
492                             && (context.header_filename == null || decl_space.file_type == CCodeFileType.PUBLIC_HEADER
493                                 || (decl_space.file_type == CCodeFileType.INTERNAL_HEADER && cl.is_internal_symbol()))) {
494                                 decl_space.add_type_member_declaration (new CCodeIdentifier ("G_DEFINE_AUTOPTR_CLEANUP_FUNC (%s, %s)".printf (get_ccode_name (cl), get_ccode_name (m))));
495                                 decl_space.add_type_member_declaration (new CCodeNewline ());
496                         }
497
498                         return true;
499                 }
500
501                 return false;
502         }
503
504         public virtual void generate_virtual_method_declaration (Method m, CCodeFile decl_space, CCodeStruct type_struct) {
505                 if (!m.is_abstract && !m.is_virtual) {
506                         return;
507                 }
508
509                 var creturn_type = get_callable_creturn_type (m);
510
511                 // add vfunc field to the type struct
512                 var vdeclarator = new CCodeFunctionDeclarator (get_ccode_vfunc_name (m));
513                 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
514
515                 if (m.printf_format) {
516                         vdeclarator.modifiers |= CCodeModifiers.PRINTF;
517                 } else if (m.scanf_format) {
518                         vdeclarator.modifiers |= CCodeModifiers.SCANF;
519                 }
520
521                 if (m.version.deprecated) {
522                         vdeclarator.modifiers |= CCodeModifiers.DEPRECATED;
523                 }
524
525                 generate_cparameters (m, decl_space, cparam_map, new CCodeFunction ("fake"), vdeclarator);
526
527                 var vdecl = new CCodeDeclaration (get_ccode_name (creturn_type));
528                 vdecl.add_declarator (vdeclarator);
529                 type_struct.add_declaration (vdecl);
530         }
531
532         void generate_class_private_declaration (Class cl, CCodeFile decl_space) {
533                 if (cl.is_opaque || decl_space.add_declaration ("%sPrivate".printf (get_ccode_name (cl)))) {
534                         return;
535                 }
536
537                 bool is_gtypeinstance = !cl.is_compact;
538                 bool has_class_locks = false;
539
540                 var instance_priv_struct = new CCodeStruct ("_%sPrivate".printf (get_ccode_name (cl)));
541                 var type_priv_struct = new CCodeStruct ("_%sPrivate".printf (get_ccode_type_name (cl)));
542
543                 if (is_gtypeinstance) {
544                         /* create type, dup_func, and destroy_func fields for generic types */
545                         foreach (TypeParameter type_param in cl.get_type_parameters ()) {
546                                 instance_priv_struct.add_field ("GType", get_ccode_type_id (type_param));
547                                 instance_priv_struct.add_field ("GBoxedCopyFunc", get_ccode_copy_function (type_param));
548                                 instance_priv_struct.add_field ("GDestroyNotify", get_ccode_destroy_function (type_param));
549                         }
550                 }
551
552                 foreach (Field f in cl.get_fields ()) {
553                         if (f.access == SymbolAccessibility.PRIVATE) {
554                                 generate_struct_field_declaration (f, instance_priv_struct, type_priv_struct, decl_space);
555                         }
556                         if (f.lock_used) {
557                                 if (f.binding == MemberBinding.INSTANCE) {
558                                         cl.has_private_fields = true;
559                                         // add field for mutex
560                                         instance_priv_struct.add_field (get_ccode_name (mutex_type), get_symbol_lock_name (get_ccode_name (f)));
561                                 } else if (f.binding == MemberBinding.CLASS) {
562                                         has_class_locks = true;
563                                         // add field for mutex
564                                         type_priv_struct.add_field (get_ccode_name (mutex_type), get_symbol_lock_name (get_ccode_name (f)));
565                                 }
566                         }
567                 }
568
569                 foreach (Property prop in cl.get_properties ()) {
570                         if (prop.binding == MemberBinding.INSTANCE) {
571                                 if (prop.lock_used) {
572                                         cl.has_private_fields = true;
573                                         // add field for mutex
574                                         instance_priv_struct.add_field (get_ccode_name (mutex_type), get_symbol_lock_name (get_ccode_name (prop)));
575                                 }
576                         } else if (prop.binding == MemberBinding.CLASS) {
577                                 if (prop.lock_used) {
578                                         has_class_locks = true;
579                                         // add field for mutex
580                                         type_priv_struct.add_field (get_ccode_name (mutex_type), get_symbol_lock_name (get_ccode_name (prop)));
581                                 }
582                         }
583                 }
584
585                 if (is_gtypeinstance) {
586                         if (cl.has_class_private_fields || has_class_locks) {
587                                 decl_space.add_type_declaration (new CCodeTypeDefinition ("struct %s".printf (type_priv_struct.name), new CCodeVariableDeclarator ("%sPrivate".printf (get_ccode_type_name (cl)))));
588                         }
589
590                         /* only add the *Private struct if it is not empty, i.e. we actually have private data */
591                         if (cl.has_private_fields || cl.has_type_parameters ()) {
592                                 decl_space.add_type_definition (instance_priv_struct);
593
594                                 var parent_decl = new CCodeDeclaration ("gint");
595                                 var parent_var_decl = new CCodeVariableDeclarator ("%s_private_offset".printf (get_ccode_name (cl)));
596                                 parent_decl.add_declarator (parent_var_decl);
597                                 parent_decl.modifiers = CCodeModifiers.STATIC;
598                                 cfile.add_type_member_declaration (parent_decl);
599
600                                 var function = new CCodeFunction ("%s_get_instance_private".printf (get_ccode_lower_case_name (cl, null)), "gpointer");
601                                 function.modifiers = CCodeModifiers.STATIC | CCodeModifiers.INLINE;
602                                 function.add_parameter (new CCodeParameter ("self", "%s*".printf (get_ccode_name (cl))));
603
604                                 push_function (function);
605
606                                 function.block = new CCodeBlock ();
607                                 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_STRUCT_MEMBER_P"));
608                                 ccall.add_argument (new CCodeIdentifier ("self"));
609                                 ccall.add_argument (new CCodeIdentifier ("%s_private_offset".printf (get_ccode_name (cl))));
610                                 function.block.add_statement (new CCodeReturnStatement (ccall));
611
612                                 pop_function ();
613                                 cfile.add_function (function);
614                         }
615
616                         if (cl.has_class_private_fields || has_class_locks) {
617                                 decl_space.add_type_definition (type_priv_struct);
618
619                                 string macro = "(G_TYPE_CLASS_GET_PRIVATE (klass, %s, %sPrivate))".printf (get_ccode_type_id (cl), get_ccode_type_name (cl));
620                                 decl_space.add_type_member_declaration (new CCodeMacroReplacement ("%s(klass)".printf (get_ccode_class_get_private_function (cl)), macro));
621                         }
622                 }
623         }
624
625         public override void visit_class (Class cl) {
626                 push_context (new EmitContext (cl));
627                 push_line (cl.source_reference);
628
629                 var old_param_spec_struct = param_spec_struct;
630                 var old_prop_enum = prop_enum;
631                 var old_signal_enum = signal_enum;
632                 var old_class_init_context = class_init_context;
633                 var old_base_init_context = base_init_context;
634                 var old_class_finalize_context = class_finalize_context;
635                 var old_base_finalize_context = base_finalize_context;
636                 var old_instance_init_context = instance_init_context;
637                 var old_instance_finalize_context = instance_finalize_context;
638
639                 bool is_gtypeinstance = !cl.is_compact;
640                 bool is_gobject = is_gtypeinstance && cl.is_subtype_of (gobject_type);
641                 bool is_fundamental = is_gtypeinstance && cl.base_class == null;
642
643                 if (get_ccode_name (cl).length < 3) {
644                         cl.error = true;
645                         Report.error (cl.source_reference, "Class name `%s' is too short", get_ccode_name (cl));
646                         return;
647                 }
648
649                 prop_enum = new CCodeEnum ();
650                 prop_enum.add_value (new CCodeEnumValue ("%s_0_PROPERTY".printf (get_ccode_upper_case_name (cl, null))));
651                 signal_enum = new CCodeEnum ();
652                 class_init_context = new EmitContext (cl);
653                 base_init_context = new EmitContext (cl);
654                 class_finalize_context = new EmitContext (cl);
655                 base_finalize_context = new EmitContext (cl);
656                 instance_init_context = new EmitContext (cl);
657                 instance_finalize_context = new EmitContext (cl);
658
659                 generate_class_struct_declaration (cl, cfile);
660                 generate_class_private_declaration (cl, cfile);
661
662                 var last_prop = "%s_NUM_PROPERTIES".printf (get_ccode_upper_case_name (cl));
663                 if (is_gobject) {
664                         cfile.add_type_declaration (prop_enum);
665
666                         var prop_array_decl = new CCodeDeclaration ("GParamSpec*");
667                         prop_array_decl.modifiers |= CCodeModifiers.STATIC;
668                         prop_array_decl.add_declarator (new CCodeVariableDeclarator ("%s_properties".printf (get_ccode_lower_case_name (cl)), null, new CCodeDeclaratorSuffix.with_array (new CCodeIdentifier (last_prop))));
669                         cfile.add_type_declaration (prop_array_decl);
670                 }
671
672                 if (!cl.is_internal_symbol () || cl.is_sealed) {
673                         if (!cl.is_opaque) {
674                                 generate_class_struct_declaration (cl, header_file);
675                         } else {
676                                 generate_class_declaration (cl, header_file);
677                         }
678                 }
679                 if (!cl.is_private_symbol () || cl.is_sealed) {
680                         generate_class_struct_declaration (cl, internal_header_file);
681                 }
682
683                 if (is_gtypeinstance) {
684                         begin_base_init_function (cl);
685                         begin_class_init_function (cl);
686                         begin_instance_init_function (cl);
687
688                         begin_base_finalize_function (cl);
689                         begin_class_finalize_function (cl);
690                         begin_finalize_function (cl);
691                 } else {
692                         if (cl.is_compact || cl.base_class == null || cl.is_subtype_of (gsource_type)) {
693                                 begin_instance_init_function (cl);
694                                 begin_finalize_function (cl);
695                         }
696                 }
697
698                 cl.accept_children (this);
699
700                 if (is_gtypeinstance) {
701                         if (is_fundamental) {
702                                 param_spec_struct = new CCodeStruct ( "_%sParamSpec%s".printf(get_ccode_prefix (cl.parent_symbol), cl.name));
703                                 param_spec_struct.add_field ("GParamSpec", "parent_instance");
704                                 cfile.add_type_definition (param_spec_struct);
705
706                                 cfile.add_type_declaration (new CCodeTypeDefinition ("struct %s".printf (param_spec_struct.name), new CCodeVariableDeclarator ( "%sParamSpec%s".printf(get_ccode_prefix (cl.parent_symbol), cl.name))));
707
708                                 add_type_value_table_init_function (cl);
709                                 add_type_value_table_free_function (cl);
710                                 add_type_value_table_copy_function (cl);
711                                 add_type_value_table_peek_pointer_function (cl);
712                                 add_type_value_table_collect_value_function (cl);
713                                 add_type_value_table_lcopy_value_function (cl);
714                                 add_g_param_spec_type_function (cl);
715                                 add_g_value_get_function (cl);
716                                 add_g_value_set_function (cl);
717                                 add_g_value_take_function (cl);
718
719                                 var ref_count = new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "ref_count"), new CCodeConstant ("1"));
720                                 push_context (instance_init_context);
721                                 ccode.add_expression (ref_count);
722                                 pop_context ();
723                         }
724
725                         if (is_gobject) {
726                                 prop_enum.add_value (new CCodeEnumValue (last_prop));
727                         }
728
729                         if (cl.get_signals ().size > 0) {
730                                 var last_signal = "%s_NUM_SIGNALS".printf (get_ccode_upper_case_name (cl));
731                                 signal_enum.add_value (new CCodeEnumValue (last_signal));
732                                 cfile.add_type_declaration (signal_enum);
733
734                                 var signal_array_decl = new CCodeDeclaration ("guint");
735                                 signal_array_decl.modifiers |= CCodeModifiers.STATIC;
736                                 signal_array_decl.add_declarator (new CCodeVariableDeclarator ("%s_signals".printf (get_ccode_lower_case_name (cl)), new CCodeConstant ("{0}"), new CCodeDeclaratorSuffix.with_array (new CCodeIdentifier (last_signal))));
737                                 cfile.add_type_declaration (signal_array_decl);
738                         }
739
740
741                         if (cl.class_constructor != null) {
742                                 add_base_init_function (cl);
743                         }
744                         add_class_init_function (cl);
745
746                         if (cl.class_destructor != null) {
747                                 add_base_finalize_function (cl);
748                         }
749
750                         if (cl.static_destructor != null) {
751                                 add_class_finalize_function (cl);
752                         }
753
754                         foreach (DataType base_type in cl.get_base_types ()) {
755                                 if (base_type.type_symbol is Interface) {
756                                         add_interface_init_function (cl, (Interface) base_type.type_symbol);
757                                 }
758                         }
759
760                         add_instance_init_function (cl);
761
762                         if (!cl.is_compact && (cl.get_fields ().size > 0 || cl.destructor != null || cl.is_fundamental ())) {
763                                 add_finalize_function (cl);
764                         }
765
766                         if (cl.comment != null) {
767                                 cfile.add_type_member_definition (new CCodeComment (cl.comment.content));
768                         }
769
770                         var type_fun = new ClassRegisterFunction (cl);
771                         type_fun.init_from_type (context, in_plugin, false);
772                         cfile.add_type_member_declaration (type_fun.get_source_declaration ());
773                         cfile.add_type_member_definition (type_fun.get_definition ());
774
775                         if (is_fundamental) {
776                                 var ref_count = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "ref_count");
777
778                                 // ref function
779                                 var ref_fun = new CCodeFunction (get_ccode_ref_function (cl), "gpointer");
780                                 ref_fun.add_parameter (new CCodeParameter ("instance", "gpointer"));
781                                 if (cl.is_private_symbol ()) {
782                                         ref_fun.modifiers = CCodeModifiers.STATIC;
783                                 } else if (context.hide_internal && cl.is_internal_symbol ()) {
784                                         ref_fun.modifiers = CCodeModifiers.INTERNAL;
785                                 }
786                                 push_function (ref_fun);
787
788                                 ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self", new CCodeIdentifier ("instance")));
789                                 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_atomic_int_inc"));
790                                 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ref_count));
791                                 ccode.add_expression (ccall);
792                                 ccode.add_return (new CCodeIdentifier ("instance"));
793
794                                 pop_function ();
795                                 cfile.add_function (ref_fun);
796
797                                 // unref function
798                                 var unref_fun = new CCodeFunction (get_ccode_unref_function (cl), "void");
799                                 unref_fun.add_parameter (new CCodeParameter ("instance", "gpointer"));
800                                 if (cl.is_private_symbol ()) {
801                                         unref_fun.modifiers = CCodeModifiers.STATIC;
802                                 } else if (context.hide_internal && cl.is_internal_symbol ()) {
803                                         unref_fun.modifiers = CCodeModifiers.INTERNAL;
804                                 }
805                                 push_function (unref_fun);
806
807                                 ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self", new CCodeIdentifier ("instance")));
808                                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_atomic_int_dec_and_test"));
809                                 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ref_count));
810                                 ccode.open_if (ccall);
811
812                                 var get_class = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (cl)));
813                                 get_class.add_argument (new CCodeIdentifier ("self"));
814
815                                 // finalize class
816                                 var ccast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_get_function (cl)));
817                                 ccast.add_argument (new CCodeIdentifier ("self"));
818                                 ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (ccast, "finalize"));
819                                 ccall.add_argument (new CCodeIdentifier ("self"));
820                                 ccode.add_expression (ccall);
821
822                                 // free type instance
823                                 var free = new CCodeFunctionCall (new CCodeIdentifier ("g_type_free_instance"));
824                                 free.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GTypeInstance *"));
825                                 ccode.add_expression (free);
826
827                                 ccode.close ();
828                                 pop_function ();
829                                 cfile.add_function (unref_fun);
830                         }
831                 } else {
832                         if (cl.is_compact || cl.base_class == null || cl.is_subtype_of (gsource_type)) {
833                                 add_instance_init_function (cl);
834                                 add_finalize_function (cl);
835                         }
836                 }
837
838                 param_spec_struct = old_param_spec_struct;
839                 prop_enum = old_prop_enum;
840                 signal_enum = old_signal_enum;
841                 class_init_context = old_class_init_context;
842                 base_init_context = old_base_init_context;
843                 class_finalize_context = old_class_finalize_context;
844                 base_finalize_context = old_base_finalize_context;
845                 instance_init_context = old_instance_init_context;
846                 instance_finalize_context = old_instance_finalize_context;
847
848                 pop_line ();
849                 pop_context ();
850         }
851
852         private void add_type_value_table_init_function (Class cl) {
853                 var function = new CCodeFunction ("%s_init".printf (get_ccode_lower_case_name (cl, "value_")), "void");
854                 function.add_parameter (new CCodeParameter ("value", "GValue*"));
855                 function.modifiers = CCodeModifiers.STATIC;
856
857                 push_function (function);
858                 ccode.add_assignment (new CCodeMemberAccess (new CCodeMemberAccess.pointer (new CCodeIdentifier ("value"), "data[0]"), "v_pointer"), new CCodeConstant ("NULL"));
859                 pop_function ();
860                 cfile.add_function (function);
861         }
862
863         private void add_type_value_table_free_function (Class cl) {
864                 var function = new CCodeFunction ("%s_free_value".printf (get_ccode_lower_case_name (cl, "value_")), "void");
865                 function.add_parameter (new CCodeParameter ("value", "GValue*"));
866                 function.modifiers = CCodeModifiers.STATIC;
867
868                 push_function (function);
869
870                 var vpointer = new CCodeMemberAccess(new CCodeMemberAccess.pointer (new CCodeIdentifier ("value"), "data[0]"),"v_pointer");
871                 var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_unref_function (cl)));
872                 ccall.add_argument (vpointer);
873
874                 ccode.open_if (vpointer);
875                 ccode.add_expression (ccall);
876                 ccode.close ();
877
878                 pop_function ();
879                 cfile.add_function (function);
880         }
881
882         private void add_type_value_table_copy_function (Class cl) {
883                 var function = new CCodeFunction ("%s_copy_value".printf (get_ccode_lower_case_name (cl, "value_")), "void");
884                 function.add_parameter (new CCodeParameter ("src_value", "const GValue*"));
885                 function.add_parameter (new CCodeParameter ("dest_value", "GValue*"));
886                 function.modifiers = CCodeModifiers.STATIC;
887
888                 push_function (function);
889
890                 var dest_vpointer = new CCodeMemberAccess (new CCodeMemberAccess.pointer (new CCodeIdentifier ("dest_value"), "data[0]"), "v_pointer");
891                 var src_vpointer = new CCodeMemberAccess (new CCodeMemberAccess.pointer (new CCodeIdentifier ("src_value"), "data[0]"), "v_pointer");
892
893                 var ref_ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_ref_function (cl)));
894                 ref_ccall.add_argument ( src_vpointer );
895
896                 ccode.open_if (src_vpointer);
897                 ccode.add_assignment (dest_vpointer, ref_ccall);
898                 ccode.add_else ();
899                 ccode.add_assignment (dest_vpointer, new CCodeConstant ("NULL"));
900                 ccode.close ();
901
902                 pop_function ();
903                 cfile.add_function (function);
904         }
905
906         private void add_type_value_table_peek_pointer_function (Class cl) {
907                 var function = new CCodeFunction ("%s_peek_pointer".printf (get_ccode_lower_case_name (cl, "value_")), "gpointer");
908                 function.add_parameter (new CCodeParameter ("value", "const GValue*"));
909                 function.modifiers = CCodeModifiers.STATIC;
910
911                 push_function (function);
912
913                 var vpointer = new CCodeMemberAccess (new CCodeMemberAccess.pointer (new CCodeIdentifier ("value"), "data[0]"), "v_pointer");
914                 ccode.add_return (vpointer);
915
916                 pop_function ();
917                 cfile.add_function (function);
918         }
919
920         private void add_type_value_table_lcopy_value_function ( Class cl ) {
921                 // Required for GTypeCValue
922                 cfile.add_include ("gobject/gvaluecollector.h");
923
924                 var function = new CCodeFunction ("%s_lcopy_value".printf (get_ccode_lower_case_name (cl, "value_")), "gchar*");
925                 function.add_parameter (new CCodeParameter ("value", "const GValue*"));
926                 function.add_parameter (new CCodeParameter ("n_collect_values", "guint"));
927                 function.add_parameter (new CCodeParameter ("collect_values", "GTypeCValue*"));
928                 function.add_parameter (new CCodeParameter ("collect_flags", "guint"));
929                 function.modifiers = CCodeModifiers.STATIC;
930
931                 var vpointer = new CCodeMemberAccess (new CCodeMemberAccess.pointer (new CCodeIdentifier ("value"), "data[0]"), "v_pointer");
932                 var object_p_ptr = new CCodeIdentifier ("*object_p");
933                 var null_ = new CCodeConstant ("NULL");
934
935                 push_function (function);
936
937                 ccode.add_declaration ("%s **".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("object_p", new CCodeMemberAccess (new CCodeIdentifier ("collect_values[0]"), "v_pointer")));
938
939                 var value_type_name_fct = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE_NAME"));
940                 value_type_name_fct.add_argument (new CCodeConstant ("value"));
941
942                 var assert_condition = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("object_p"));
943                 ccode.open_if (assert_condition);
944                 var assert_printf = new CCodeFunctionCall (new CCodeIdentifier ("g_strdup_printf"));
945                 assert_printf.add_argument (new CCodeConstant ("\"value location for `%s' passed as NULL\""));
946                 assert_printf.add_argument (value_type_name_fct);
947                 ccode.add_return (assert_printf);
948                 ccode.close ();
949
950                 var main_condition = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, vpointer);
951                 var main_else_if_condition = new CCodeBinaryExpression (CCodeBinaryOperator.BITWISE_AND, new CCodeIdentifier ("collect_flags"), new CCodeIdentifier ("G_VALUE_NOCOPY_CONTENTS"));
952                 var ref_fct = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_ref_function (cl)));
953                 ref_fct.add_argument (vpointer);
954                 ccode.open_if (main_condition);
955                 ccode.add_assignment (object_p_ptr, null_);
956                 ccode.else_if (main_else_if_condition);
957                 ccode.add_assignment (object_p_ptr, vpointer);
958                 ccode.add_else ();
959                 ccode.add_assignment (object_p_ptr, ref_fct);
960                 ccode.close ();
961
962                 ccode.add_return (null_);
963                 pop_function ();
964                 cfile.add_function (function);
965         }
966
967         private void add_type_value_table_collect_value_function (Class cl) {
968                 // Required for GTypeCValue
969                 cfile.add_include ("gobject/gvaluecollector.h");
970
971                 var function = new CCodeFunction ("%s_collect_value".printf (get_ccode_lower_case_name (cl, "value_")), "gchar*");
972                 function.add_parameter (new CCodeParameter ("value", "GValue*"));
973                 function.add_parameter (new CCodeParameter ("n_collect_values", "guint"));
974                 function.add_parameter (new CCodeParameter ("collect_values", "GTypeCValue*"));
975                 function.add_parameter (new CCodeParameter ("collect_flags", "guint"));
976                 function.modifiers = CCodeModifiers.STATIC;
977
978                 var vpointer = new CCodeMemberAccess (new CCodeMemberAccess.pointer (new CCodeIdentifier ("value"), "data[0]"), "v_pointer");
979
980                 push_function (function);
981
982                 var collect_vpointer = new CCodeMemberAccess (new CCodeIdentifier ("collect_values[0]"), "v_pointer");
983
984                 ccode.open_if (collect_vpointer);
985                 ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("object", collect_vpointer));
986                 var obj_identifier = new CCodeIdentifier ("object");
987                 var l_expression = new CCodeMemberAccess (new CCodeMemberAccess.pointer (obj_identifier, "parent_instance"), "g_class");
988                 var sub_condition = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, l_expression, new CCodeConstant ("NULL"));
989                 var value_type_name_fct = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE_NAME"));
990                 value_type_name_fct.add_argument (new CCodeConstant ("value"));
991
992                 ccode.open_if (sub_condition);
993                 var true_return = new CCodeFunctionCall (new CCodeIdentifier ("g_strconcat"));
994                 true_return.add_argument (new CCodeConstant ("\"invalid unclassed object pointer for value type `\""));
995                 true_return.add_argument (value_type_name_fct);
996                 true_return.add_argument (new CCodeConstant ("\"'\""));
997                 true_return.add_argument (new CCodeConstant ("NULL"));
998                 ccode.add_return (true_return);
999
1000                 var reg_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_type_compatible"));
1001                 var type_check = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_FROM_INSTANCE"));
1002                 type_check.add_argument (new CCodeIdentifier ("object"));
1003                 reg_call.add_argument (type_check);
1004                 var stored_type = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE"));
1005                 stored_type.add_argument (new CCodeIdentifier ("value"));
1006                 reg_call.add_argument (stored_type);
1007
1008                 ccode.else_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, reg_call));
1009                 var false_return = new CCodeFunctionCall (new CCodeIdentifier ("g_strconcat"));
1010                 var type_name_fct = new CCodeFunctionCall (new CCodeIdentifier ("g_type_name"));
1011                 type_name_fct.add_argument (type_check);
1012                 false_return.add_argument (new CCodeConstant ("\"invalid object type `\""));
1013                 false_return.add_argument (type_name_fct);
1014                 false_return.add_argument (new CCodeConstant ("\"' for value type `\""));
1015                 false_return.add_argument (value_type_name_fct);
1016                 false_return.add_argument (new CCodeConstant ("\"'\""));
1017                 false_return.add_argument (new CCodeConstant ("NULL"));
1018                 ccode.add_return (false_return);
1019
1020                 ccode.close ();
1021
1022                 var ref_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_ref_function (cl)));
1023                 ref_call.add_argument (new CCodeIdentifier ("object"));
1024                 ccode.add_assignment (vpointer, ref_call);
1025
1026                 ccode.add_else ();
1027                 ccode.add_assignment (vpointer, new CCodeConstant ("NULL"));
1028
1029                 ccode.close ();
1030
1031                 ccode.add_return (new CCodeConstant ("NULL"));
1032
1033                 pop_function ();
1034                 cfile.add_function (function);
1035         }
1036
1037         private void add_g_param_spec_type_function (Class cl) {
1038                 var function = new CCodeFunction (get_ccode_param_spec_function (cl), "GParamSpec*");
1039                 function.add_parameter (new CCodeParameter ("name", "const gchar*"));
1040                 function.add_parameter (new CCodeParameter ("nick", "const gchar*"));
1041                 function.add_parameter (new CCodeParameter ("blurb", "const gchar*"));
1042                 function.add_parameter (new CCodeParameter ("object_type", "GType"));
1043                 function.add_parameter (new CCodeParameter ("flags", "GParamFlags"));
1044
1045                 if (cl.is_private_symbol ()) {
1046                         function.modifiers = CCodeModifiers.STATIC;
1047                 } else if (context.hide_internal && cl.is_internal_symbol ()) {
1048                         function.modifiers = CCodeModifiers.INTERNAL;
1049                 }
1050
1051                 push_function (function);
1052
1053                 ccode.add_declaration ("%sParamSpec%s*".printf (get_ccode_prefix (cl.parent_symbol), cl.name), new CCodeVariableDeclarator ("spec"));
1054
1055                 var subccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_is_a"));
1056                 subccall.add_argument (new CCodeIdentifier ("object_type"));
1057                 subccall.add_argument (new CCodeIdentifier ( get_ccode_type_id (cl) ));
1058
1059                 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_return_val_if_fail"));
1060                 ccall.add_argument (subccall);
1061                 ccall.add_argument (new CCodeConstant ("NULL"));
1062                 ccode.add_expression (ccall);
1063
1064                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_internal"));
1065                 ccall.add_argument (new CCodeIdentifier ( "G_TYPE_PARAM_OBJECT" ));
1066                 ccall.add_argument (new CCodeIdentifier ("name"));
1067                 ccall.add_argument (new CCodeIdentifier ("nick"));
1068                 ccall.add_argument (new CCodeIdentifier ("blurb"));
1069                 ccall.add_argument (new CCodeIdentifier ("flags"));
1070
1071                 ccode.add_assignment (new CCodeIdentifier ("spec"), ccall);
1072
1073                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_PARAM_SPEC"));
1074                 ccall.add_argument (new CCodeIdentifier ("spec"));
1075
1076                 ccode.add_assignment (new CCodeMemberAccess.pointer (ccall, "value_type"), new CCodeIdentifier ("object_type"));
1077                 ccode.add_return (ccall);
1078
1079                 pop_function ();
1080                 cfile.add_function (function);
1081         }
1082
1083         private void add_g_value_set_function (Class cl) {
1084                 var function = new CCodeFunction (get_ccode_set_value_function (cl), "void");
1085                 function.add_parameter (new CCodeParameter ("value", "GValue*"));
1086                 function.add_parameter (new CCodeParameter ("v_object", "gpointer"));
1087
1088                 if (cl.is_private_symbol ()) {
1089                         function.modifiers = CCodeModifiers.STATIC;
1090                 } else if (context.hide_internal && cl.is_internal_symbol ()) {
1091                         function.modifiers = CCodeModifiers.INTERNAL;
1092                 }
1093
1094                 var vpointer = new CCodeMemberAccess (new CCodeMemberAccess.pointer (new CCodeIdentifier ("value"), "data[0]"), "v_pointer");
1095
1096                 push_function (function);
1097
1098                 ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("old"));
1099
1100                 var ccall_typecheck = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_VALUE_TYPE"));
1101                 ccall_typecheck.add_argument (new CCodeIdentifier ( "value" ));
1102                 ccall_typecheck.add_argument (new CCodeIdentifier ( get_ccode_type_id (cl) ));
1103
1104                 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
1105                 ccall.add_argument (ccall_typecheck);
1106                 ccode.add_expression (ccall);
1107
1108                 ccode.add_assignment (new CCodeConstant ("old"), vpointer);
1109
1110                 ccode.open_if (new CCodeIdentifier ("v_object"));
1111                 ccall_typecheck = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_INSTANCE_TYPE"));
1112                 ccall_typecheck.add_argument (new CCodeIdentifier ( "v_object" ));
1113                 ccall_typecheck.add_argument (new CCodeIdentifier ( get_ccode_type_id (cl) ));
1114
1115                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
1116                 ccall.add_argument (ccall_typecheck);
1117                 ccode.add_expression (ccall);
1118
1119                 var ccall_typefrominstance = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_FROM_INSTANCE"));
1120                 ccall_typefrominstance.add_argument (new CCodeIdentifier ( "v_object" ));
1121
1122                 var ccall_gvaluetype = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE"));
1123                 ccall_gvaluetype.add_argument (new CCodeIdentifier ( "value" ));
1124
1125                 var ccall_typecompatible = new CCodeFunctionCall (new CCodeIdentifier ("g_value_type_compatible"));
1126                 ccall_typecompatible.add_argument (ccall_typefrominstance);
1127                 ccall_typecompatible.add_argument (ccall_gvaluetype);
1128
1129                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
1130                 ccall.add_argument (ccall_typecompatible);
1131                 ccode.add_expression (ccall);
1132
1133                 ccode.add_assignment (vpointer, new CCodeConstant ("v_object"));
1134
1135                 ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_ref_function (cl)));
1136                 ccall.add_argument (vpointer);
1137                 ccode.add_expression (ccall);
1138
1139                 ccode.add_else ();
1140                 ccode.add_assignment (vpointer, new CCodeConstant ("NULL"));
1141                 ccode.close ();
1142
1143                 ccode.open_if (new CCodeIdentifier ("old"));
1144                 ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_unref_function (cl)));
1145                 ccall.add_argument (new CCodeIdentifier ("old"));
1146                 ccode.add_expression (ccall);
1147                 ccode.close ();
1148
1149                 pop_function ();
1150                 cfile.add_function (function);
1151         }
1152
1153         private void add_g_value_take_function (Class cl) {
1154                 var function = new CCodeFunction (get_ccode_take_value_function (cl), "void");
1155                 function.add_parameter (new CCodeParameter ("value", "GValue*"));
1156                 function.add_parameter (new CCodeParameter ("v_object", "gpointer"));
1157
1158                 if (cl.is_private_symbol ()) {
1159                         function.modifiers = CCodeModifiers.STATIC;
1160                 } else if (context.hide_internal && cl.is_internal_symbol ()) {
1161                         function.modifiers = CCodeModifiers.INTERNAL;
1162                 }
1163
1164                 var vpointer = new CCodeMemberAccess(new CCodeMemberAccess.pointer (new CCodeIdentifier ("value"), "data[0]"),"v_pointer");
1165
1166                 push_function (function);
1167
1168                 ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("old"));
1169
1170                 var ccall_typecheck = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_VALUE_TYPE"));
1171                 ccall_typecheck.add_argument (new CCodeIdentifier ( "value" ));
1172                 ccall_typecheck.add_argument (new CCodeIdentifier ( get_ccode_type_id (cl) ));
1173
1174                 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
1175                 ccall.add_argument (ccall_typecheck);
1176                 ccode.add_expression (ccall);
1177
1178                 ccode.add_assignment (new CCodeConstant ("old"), vpointer);
1179
1180                 ccode.open_if (new CCodeIdentifier ("v_object"));
1181
1182                 ccall_typecheck = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_INSTANCE_TYPE"));
1183                 ccall_typecheck.add_argument (new CCodeIdentifier ( "v_object" ));
1184                 ccall_typecheck.add_argument (new CCodeIdentifier ( get_ccode_type_id (cl) ));
1185
1186                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
1187                 ccall.add_argument (ccall_typecheck);
1188                 ccode.add_expression (ccall);
1189
1190                 var ccall_typefrominstance = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_FROM_INSTANCE"));
1191                 ccall_typefrominstance.add_argument (new CCodeIdentifier ( "v_object" ));
1192
1193                 var ccall_gvaluetype = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE"));
1194                 ccall_gvaluetype.add_argument (new CCodeIdentifier ( "value" ));
1195
1196                 var ccall_typecompatible = new CCodeFunctionCall (new CCodeIdentifier ("g_value_type_compatible"));
1197                 ccall_typecompatible.add_argument (ccall_typefrominstance);
1198                 ccall_typecompatible.add_argument (ccall_gvaluetype);
1199
1200                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
1201                 ccall.add_argument (ccall_typecompatible);
1202                 ccode.add_expression (ccall);
1203
1204                 ccode.add_assignment (vpointer, new CCodeConstant ("v_object"));
1205
1206                 ccode.add_else ();
1207                 ccode.add_assignment (vpointer, new CCodeConstant ("NULL"));
1208                 ccode.close ();
1209
1210                 ccode.open_if (new CCodeIdentifier ("old"));
1211                 ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_unref_function (cl)));
1212                 ccall.add_argument (new CCodeIdentifier ("old"));
1213                 ccode.add_expression (ccall);
1214                 ccode.close ();
1215
1216                 pop_function ();
1217                 cfile.add_function (function);
1218         }
1219
1220         private void add_g_value_get_function (Class cl) {
1221                 var function = new CCodeFunction (get_ccode_get_value_function (cl), "gpointer");
1222                 function.add_parameter (new CCodeParameter ("value", "const GValue*"));
1223
1224                 if (cl.is_private_symbol ()) {
1225                         function.modifiers = CCodeModifiers.STATIC;
1226                 } else if (context.hide_internal && cl.is_internal_symbol ()) {
1227                         function.modifiers = CCodeModifiers.INTERNAL;
1228                 }
1229
1230                 var vpointer = new CCodeMemberAccess(new CCodeMemberAccess.pointer (new CCodeIdentifier ("value"), "data[0]"),"v_pointer");
1231
1232                 push_function (function);
1233
1234                 var ccall_typecheck = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_VALUE_TYPE"));
1235                 ccall_typecheck.add_argument (new CCodeIdentifier ("value"));
1236                 ccall_typecheck.add_argument (new CCodeIdentifier (get_ccode_type_id (cl)));
1237
1238                 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_return_val_if_fail"));
1239                 ccall.add_argument (ccall_typecheck);
1240                 ccall.add_argument (new CCodeConstant ("NULL"));
1241                 ccode.add_expression (ccall);
1242
1243                 ccode.add_return (vpointer);
1244
1245                 pop_function ();
1246                 cfile.add_function (function);
1247         }
1248
1249         private void begin_base_init_function (Class cl) {
1250                 push_context (base_init_context);
1251
1252                 var base_init = new CCodeFunction ("%s_base_init".printf (get_ccode_lower_case_name (cl, null)), "void");
1253                 base_init.add_parameter (new CCodeParameter ("klass", "%s *".printf (get_ccode_type_name (cl))));
1254                 base_init.modifiers = CCodeModifiers.STATIC;
1255
1256                 push_function (base_init);
1257
1258                 pop_context ();
1259         }
1260
1261         private void add_base_init_function (Class cl) {
1262                 cfile.add_function (base_init_context.ccode);
1263         }
1264
1265         public virtual void generate_class_init (Class cl) {
1266         }
1267
1268         public virtual void end_instance_init (Class cl) {
1269         }
1270
1271         private void begin_class_init_function (Class cl) {
1272                 push_context (class_init_context);
1273
1274                 var func = new CCodeFunction ("%s_class_init".printf (get_ccode_lower_case_name (cl, null)));
1275                 func.add_parameter (new CCodeParameter ("klass", "%s *".printf (get_ccode_type_name (cl))));
1276                 func.add_parameter (new CCodeParameter ("klass_data", "gpointer"));
1277                 func.modifiers = CCodeModifiers.STATIC;
1278
1279                 CCodeFunctionCall ccall;
1280
1281                 /* save pointer to parent class */
1282                 var parent_decl = new CCodeDeclaration ("gpointer");
1283                 var parent_var_decl = new CCodeVariableDeclarator ("%s_parent_class".printf (get_ccode_lower_case_name (cl, null)));
1284                 parent_var_decl.initializer = new CCodeConstant ("NULL");
1285                 parent_decl.add_declarator (parent_var_decl);
1286                 parent_decl.modifiers = CCodeModifiers.STATIC;
1287                 cfile.add_type_member_declaration (parent_decl);
1288
1289                 push_function (func);
1290
1291                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek_parent"));
1292                 ccall.add_argument (new CCodeIdentifier ("klass"));
1293                 var parent_assignment = new CCodeAssignment (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (cl, null))), ccall);
1294                 ccode.add_expression (parent_assignment);
1295
1296
1297                 if (!cl.is_compact && !cl.is_subtype_of (gobject_type) && (cl.get_fields ().size > 0 || cl.destructor != null || cl.is_fundamental ())) {
1298                         // set finalize function
1299                         var fundamental_class = cl;
1300                         while (fundamental_class.base_class != null) {
1301                                 fundamental_class = fundamental_class.base_class;
1302                         }
1303
1304                         var ccast = new CCodeCastExpression (new CCodeIdentifier ("klass"), "%s *".printf (get_ccode_type_name (fundamental_class)));
1305                         var finalize_assignment = new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, "finalize"), new CCodeIdentifier ("%sfinalize".printf (get_ccode_lower_case_prefix (cl))));
1306                         ccode.add_expression (finalize_assignment);
1307                 }
1308
1309                 /* add struct for private fields */
1310                 if (cl.has_private_fields || cl.has_type_parameters ()) {
1311                         ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_adjust_private_offset"));
1312                         ccall.add_argument (new CCodeIdentifier ("klass"));
1313                         ccall.add_argument (new CCodeIdentifier ("&%s_private_offset".printf (get_ccode_name (cl))));
1314                         ccode.add_expression (ccall);
1315                 }
1316
1317                 /* connect overridden methods */
1318                 foreach (Method m in cl.get_methods ()) {
1319                         if (m.base_method == null) {
1320                                 continue;
1321                         }
1322                         var base_type = (ObjectTypeSymbol) m.base_method.parent_symbol;
1323
1324                         // there is currently no default handler for abstract async methods
1325                         if (!m.is_abstract || !m.coroutine) {
1326                                 generate_method_declaration (m.base_method, cfile);
1327
1328                                 CCodeExpression cfunc = new CCodeIdentifier (get_ccode_real_name (m));
1329                                 cfunc = cast_method_pointer (m.base_method, cfunc, base_type, (m.coroutine ? 1 : 3));
1330                                 var ccast = new CCodeCastExpression (new CCodeIdentifier ("klass"), "%s *".printf (get_ccode_type_name (base_type)));
1331                                 ccode.add_assignment (new CCodeMemberAccess.pointer (ccast, get_ccode_vfunc_name (m.base_method)), cfunc);
1332
1333                                 if (m.coroutine) {
1334                                         cfunc = new CCodeIdentifier (get_ccode_finish_real_name (m));
1335                                         cfunc = cast_method_pointer (m.base_method, cfunc, base_type, 2);
1336                                         ccode.add_assignment (new CCodeMemberAccess.pointer (ccast, get_ccode_finish_vfunc_name (m.base_method)), cfunc);
1337                                 }
1338                         }
1339                 }
1340
1341                 /* connect default signal handlers */
1342                 foreach (Signal sig in cl.get_signals ()) {
1343                         if (sig.default_handler == null || !sig.is_virtual) {
1344                                 continue;
1345                         }
1346
1347                         var ccast = new CCodeCastExpression (new CCodeIdentifier ("klass"), "%s *".printf (get_ccode_type_name (cl)));
1348                         ccode.add_assignment (new CCodeMemberAccess.pointer (ccast, get_ccode_vfunc_name (sig.default_handler)), new CCodeIdentifier (get_ccode_real_name (sig.default_handler)));
1349                 }
1350
1351                 /* connect overridden properties */
1352                 foreach (Property prop in cl.get_properties ()) {
1353                         if (prop.base_property == null) {
1354                                 continue;
1355                         }
1356                         var base_type = (Class) prop.base_property.parent_symbol;
1357
1358                         var ccast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function (base_type)));
1359                         ccast.add_argument (new CCodeIdentifier ("klass"));
1360
1361                         if (!get_ccode_no_accessor_method (prop.base_property) && !get_ccode_concrete_accessor (prop.base_property)) {
1362                                 if (prop.get_accessor != null) {
1363                                         generate_property_accessor_declaration (prop.base_property.get_accessor, cfile);
1364
1365                                         string cname = get_ccode_real_name (prop.get_accessor);
1366                                         ccode.add_assignment (new CCodeMemberAccess.pointer (ccast, "get_%s".printf (prop.name)), new CCodeIdentifier (cname));
1367                                 }
1368                                 if (prop.set_accessor != null) {
1369                                         generate_property_accessor_declaration (prop.base_property.set_accessor, cfile);
1370
1371                                         string cname = get_ccode_real_name (prop.set_accessor);
1372                                         ccode.add_assignment (new CCodeMemberAccess.pointer (ccast, "set_%s".printf (prop.name)), new CCodeIdentifier (cname));
1373                                 }
1374                         }
1375                 }
1376
1377                 generate_class_init (cl);
1378
1379                 if (!cl.is_compact) {
1380                         /* create signals */
1381                         foreach (Signal sig in cl.get_signals ()) {
1382                                 if (sig.comment != null) {
1383                                         ccode.add_statement (new CCodeComment (sig.comment.content));
1384                                 }
1385                                 ccode.add_expression (get_signal_creation (sig, cl));
1386                         }
1387                 }
1388
1389                 pop_context ();
1390         }
1391
1392         private void add_class_init_function (Class cl) {
1393                 cfile.add_function (class_init_context.ccode);
1394         }
1395
1396         private void add_generic_accessor_function (string base_name, string return_type, CCodeExpression? expression, TypeParameter p, Class cl, Interface iface) {
1397                 string name = "%s_%s_%s".printf (get_ccode_lower_case_name (cl), get_ccode_lower_case_name (iface), base_name);
1398
1399                 var function = new CCodeFunction (name, return_type);
1400                 function.modifiers = CCodeModifiers.STATIC;
1401                 var this_type = SemanticAnalyzer.get_data_type_for_symbol (cl);
1402                 function.add_parameter (new CCodeParameter ("self", get_ccode_name (this_type)));
1403                 push_function (function);
1404                 ccode.add_return (expression);
1405                 pop_function ();
1406                 cfile.add_function (function);
1407
1408                 CCodeExpression cfunc = new CCodeIdentifier (function.name);
1409                 string cast = "%s (*)".printf (return_type);
1410                 string cast_args = "%s *".printf (get_ccode_name (iface));
1411                 cast = "%s (%s)".printf (cast, cast_args);
1412                 cfunc = new CCodeCastExpression (cfunc, cast);
1413                 var ciface = new CCodeIdentifier ("iface");
1414                 ccode.add_assignment (new CCodeMemberAccess.pointer (ciface, base_name), cfunc);
1415         }
1416
1417         private void add_interface_init_function (Class cl, Interface iface) {
1418                 var iface_init = new CCodeFunction ("%s_%s_interface_init".printf (get_ccode_lower_case_name (cl), get_ccode_lower_case_name (iface)), "void");
1419                 iface_init.add_parameter (new CCodeParameter ("iface", "%s *".printf (get_ccode_type_name (iface))));
1420                 iface_init.add_parameter (new CCodeParameter ("iface_data", "gpointer"));
1421                 iface_init.modifiers = CCodeModifiers.STATIC;
1422
1423                 push_function (iface_init);
1424
1425                 CCodeFunctionCall ccall;
1426
1427                 /* save pointer to parent vtable */
1428                 string parent_iface_var = "%s_%s_parent_iface".printf (get_ccode_lower_case_name (cl), get_ccode_lower_case_name (iface));
1429                 var parent_decl = new CCodeDeclaration ("%s *".printf (get_ccode_type_name (iface)));
1430                 var parent_var_decl = new CCodeVariableDeclarator (parent_iface_var);
1431                 parent_var_decl.initializer = new CCodeConstant ("NULL");
1432                 parent_decl.add_declarator (parent_var_decl);
1433                 parent_decl.modifiers = CCodeModifiers.STATIC;
1434                 cfile.add_type_member_declaration (parent_decl);
1435                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_interface_peek_parent"));
1436                 ccall.add_argument (new CCodeIdentifier ("iface"));
1437                 ccode.add_assignment (new CCodeIdentifier (parent_iface_var), ccall);
1438
1439                 foreach (Method m in cl.get_methods ()) {
1440                         if (m.base_interface_method == null) {
1441                                 continue;
1442                         }
1443
1444                         var base_type = m.base_interface_method.parent_symbol;
1445                         if (base_type != iface) {
1446                                 continue;
1447                         }
1448
1449                         generate_method_declaration (m.base_interface_method, cfile);
1450
1451                         var ciface = new CCodeIdentifier ("iface");
1452                         CCodeExpression cfunc;
1453                         if (m.is_abstract || m.is_virtual) {
1454                                 cfunc = new CCodeIdentifier (get_ccode_name (m));
1455                         } else {
1456                                 cfunc = new CCodeIdentifier (get_ccode_real_name (m));
1457                         }
1458                         cfunc = cast_method_pointer (m.base_interface_method, cfunc, iface, (m.coroutine ? 1 : 3));
1459                         ccode.add_assignment (new CCodeMemberAccess.pointer (ciface, get_ccode_vfunc_name (m.base_interface_method)), cfunc);
1460
1461                         if (m.coroutine) {
1462                                 if (m.is_abstract || m.is_virtual) {
1463                                         cfunc = new CCodeIdentifier (get_ccode_finish_name (m));
1464                                 } else {
1465                                         cfunc = new CCodeIdentifier (get_ccode_finish_real_name (m));
1466                                 }
1467                                 cfunc = cast_method_pointer (m.base_interface_method, cfunc, iface, 2);
1468                                 ccode.add_assignment (new CCodeMemberAccess.pointer (ciface, get_ccode_finish_vfunc_name (m.base_interface_method)), cfunc);
1469                         }
1470                 }
1471
1472                 if (iface.get_attribute ("GenericAccessors") != null) {
1473                         foreach (TypeParameter p in iface.get_type_parameters ()) {
1474                                 GenericType p_type = new GenericType (p);
1475                                 DataType p_data_type = p_type.get_actual_type (SemanticAnalyzer.get_data_type_for_symbol (cl), null, cl);
1476
1477                                 add_generic_accessor_function ("get_%s".printf (get_ccode_type_id (p)),
1478                                                                "GType",
1479                                                                get_type_id_expression (p_data_type),
1480                                                                p, cl, iface);
1481
1482                                 add_generic_accessor_function ("get_%s".printf (get_ccode_copy_function (p)),
1483                                                                "GBoxedCopyFunc",
1484                                                                get_dup_func_expression (p_data_type, p_data_type.source_reference),
1485                                                                p, cl, iface);
1486
1487                                 add_generic_accessor_function ("get_%s".printf (get_ccode_destroy_function (p)),
1488                                                                "GDestroyNotify",
1489                                                                get_destroy_func_expression (p_data_type),
1490                                                                p, cl, iface);
1491                         }
1492                 }
1493
1494                 // connect inherited implementations
1495                 var it = cl.get_implicit_implementations ().map_iterator ();
1496                 while (it.next ()) {
1497                         Method m = it.get_key ();
1498                         if (m.parent_symbol == iface) {
1499                                 Method base_method = it.get_value ();
1500
1501                                 generate_method_declaration (base_method, cfile);
1502
1503                                 CCodeExpression cfunc = new CCodeIdentifier (get_ccode_name (base_method));
1504                                 cfunc = cast_method_pointer (m, cfunc, iface);
1505                                 var ciface = new CCodeIdentifier ("iface");
1506                                 ccode.add_assignment (new CCodeMemberAccess.pointer (ciface, get_ccode_vfunc_name (m)), cfunc);
1507                         }
1508                 }
1509
1510                 foreach (Property prop in cl.get_properties ()) {
1511                         if (prop.base_interface_property == null) {
1512                                 continue;
1513                         }
1514
1515                         var base_type = (ObjectTypeSymbol) prop.base_interface_property.parent_symbol;
1516                         if (base_type != iface) {
1517                                 continue;
1518                         }
1519
1520                         var ciface = new CCodeIdentifier ("iface");
1521
1522                         if (!get_ccode_no_accessor_method (prop.base_interface_property) && !get_ccode_concrete_accessor (prop.base_interface_property)) {
1523                                 if (prop.get_accessor != null) {
1524                                         generate_property_accessor_declaration (prop.base_interface_property.get_accessor, cfile);
1525
1526                                         string cname = get_ccode_real_name (prop.get_accessor);
1527                                         if (prop.is_abstract || prop.is_virtual) {
1528                                                 cname = get_ccode_name (prop.get_accessor);
1529                                         }
1530
1531                                         CCodeExpression cfunc = new CCodeIdentifier (cname);
1532                                         if (prop.is_abstract || prop.is_virtual) {
1533                                                 cfunc = cast_property_accessor_pointer (prop.get_accessor, cfunc, base_type);
1534                                         }
1535                                         ccode.add_assignment (new CCodeMemberAccess.pointer (ciface, "get_%s".printf (prop.name)), cfunc);
1536                                 }
1537                                 if (prop.set_accessor != null) {
1538                                         generate_property_accessor_declaration (prop.base_interface_property.set_accessor, cfile);
1539
1540                                         string cname = get_ccode_real_name (prop.set_accessor);
1541                                         if (prop.is_abstract || prop.is_virtual) {
1542                                                 cname = get_ccode_name (prop.set_accessor);
1543                                         }
1544
1545                                         CCodeExpression cfunc = new CCodeIdentifier (cname);
1546                                         if (prop.is_abstract || prop.is_virtual) {
1547                                                 cfunc = cast_property_accessor_pointer (prop.set_accessor, cfunc, base_type);
1548                                         }
1549                                         ccode.add_assignment (new CCodeMemberAccess.pointer (ciface, "set_%s".printf (prop.name)), cfunc);
1550                                 }
1551                         }
1552                 }
1553
1554                 foreach (Property prop in iface.get_properties ()) {
1555                         if (!prop.is_abstract) {
1556                                 continue;
1557                         }
1558
1559                         Property cl_prop = null;
1560                         var base_class = cl;
1561                         while (base_class != null && cl_prop == null) {
1562                                 cl_prop = base_class.scope.lookup (prop.name) as Property;
1563                                 base_class = base_class.base_class;
1564                         }
1565                         if (base_class != null && cl_prop.parent_symbol != cl) {
1566                                 // property inherited from base class
1567
1568                                 var base_property = cl_prop;
1569                                 if (cl_prop.base_property != null) {
1570                                         base_property = cl_prop.base_property;
1571                                 } else if (cl_prop.base_interface_property != null) {
1572                                         base_property = cl_prop.base_interface_property;
1573                                 }
1574
1575                                 // Our base class provides this interface implementation
1576                                 if (prop == base_property) {
1577                                         continue;
1578                                 }
1579
1580                                 var ciface = new CCodeIdentifier ("iface");
1581
1582                                 if (base_property.get_accessor != null && prop.get_accessor != null) {
1583                                         generate_property_accessor_declaration (base_property.get_accessor, cfile);
1584
1585                                         string cname = get_ccode_name (base_property.get_accessor);
1586                                         CCodeExpression cfunc = new CCodeIdentifier (cname);
1587                                         cfunc = cast_property_accessor_pointer (prop.get_accessor, cfunc, iface);
1588                                         ccode.add_assignment (new CCodeMemberAccess.pointer (ciface, "get_%s".printf (prop.name)), cfunc);
1589                                 }
1590                                 if (base_property.set_accessor != null && prop.set_accessor != null) {
1591                                         generate_property_accessor_declaration (base_property.set_accessor, cfile);
1592
1593                                         string cname = get_ccode_name (base_property.set_accessor);
1594                                         CCodeExpression cfunc = new CCodeIdentifier (cname);
1595                                         cfunc = cast_property_accessor_pointer (prop.set_accessor, cfunc, iface);
1596                                         ccode.add_assignment (new CCodeMemberAccess.pointer (ciface, "set_%s".printf (prop.name)), cfunc);
1597                                 }
1598                         }
1599                 }
1600
1601                 pop_function ();
1602                 cfile.add_function (iface_init);
1603         }
1604
1605         CCodeExpression cast_property_accessor_pointer (PropertyAccessor acc, CCodeExpression cfunc, ObjectTypeSymbol base_type) {
1606                 string cast;
1607                 if (acc.readable && acc.value_type.is_real_non_null_struct_type ()) {
1608                         cast = "void (*) (%s *, %s *)".printf (get_ccode_name (base_type), get_ccode_name (acc.value_type));
1609                 } else if (acc.readable) {
1610                         cast = "%s (*) (%s *)".printf (get_ccode_name (acc.value_type), get_ccode_name (base_type));
1611                 } else if (acc.value_type.is_real_non_null_struct_type ()) {
1612                         cast = "void (*) (%s *, %s *)".printf (get_ccode_name (base_type), get_ccode_name (acc.value_type));
1613                 } else {
1614                         cast = "void (*) (%s *, %s)".printf (get_ccode_name (base_type), get_ccode_name (acc.value_type));
1615                 }
1616                 return new CCodeCastExpression (cfunc, cast);
1617         }
1618
1619         CCodeExpression cast_method_pointer (Method m, CCodeExpression cfunc, ObjectTypeSymbol base_type, int direction = 3) {
1620                 // Cast the function pointer to match the interface
1621                 string cast;
1622                 if (direction == 1 || m.return_type.is_real_non_null_struct_type ()) {
1623                         cast = "void (*)";
1624                 } else {
1625                         cast = "%s (*)".printf (get_ccode_name (m.return_type));
1626                 }
1627
1628                 var vdeclarator = new CCodeFunctionDeclarator (get_ccode_vfunc_name (m));
1629                 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
1630
1631                 generate_cparameters (m, cfile, cparam_map, new CCodeFunction ("fake"), vdeclarator, null, null, direction);
1632
1633                 // append C arguments in the right order
1634                 int last_pos = -1;
1635                 int min_pos;
1636                 string cast_args = "";
1637                 while (true) {
1638                         min_pos = -1;
1639                         foreach (int pos in cparam_map.get_keys ()) {
1640                                 if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
1641                                         min_pos = pos;
1642                                 }
1643                         }
1644                         if (min_pos == -1) {
1645                                 break;
1646                         }
1647                         if (last_pos != -1) {
1648                                 cast_args = "%s, ".printf (cast_args);
1649                         }
1650                         var cparam = cparam_map.get (min_pos);
1651                         if (cparam.ellipsis) {
1652                                 cast_args = "%s...".printf (cast_args);
1653                         } else {
1654                                 cast_args = "%s%s".printf (cast_args, cparam.type_name);
1655                         }
1656                         last_pos = min_pos;
1657                 }
1658                 cast = "%s (%s)".printf (cast, cast_args);
1659                 return new CCodeCastExpression (cfunc, cast);
1660         }
1661
1662         private void begin_instance_init_function (Class cl) {
1663                 push_context (instance_init_context);
1664
1665                 var func = new CCodeFunction ("%s_instance_init".printf (get_ccode_lower_case_name (cl, null)));
1666                 func.add_parameter (new CCodeParameter ("self", "%s *".printf (get_ccode_name (cl))));
1667                 if (!cl.is_compact) {
1668                         func.add_parameter (new CCodeParameter ("klass", "gpointer"));
1669                 }
1670                 func.modifiers = CCodeModifiers.STATIC;
1671
1672                 push_function (func);
1673
1674                 bool is_gsource = cl.is_subtype_of (gsource_type);
1675
1676                 if (cl.is_compact) {
1677                         // Add declaration, since the instance_init function is explicitly called
1678                         // by the creation methods
1679                         cfile.add_function_declaration (func);
1680
1681                         // connect overridden methods
1682                         foreach (Method m in cl.get_methods ()) {
1683                                 if (m.base_method == null || is_gsource) {
1684                                         continue;
1685                                 }
1686                                 var base_type = (ObjectTypeSymbol) m.base_method.parent_symbol;
1687
1688                                 // there is currently no default handler for abstract async methods
1689                                 if (!m.is_abstract || !m.coroutine) {
1690                                         generate_method_declaration (m.base_method, cfile);
1691
1692                                         CCodeExpression cfunc = new CCodeIdentifier (get_ccode_real_name (m));
1693                                         cfunc = cast_method_pointer (m.base_method, cfunc, base_type, (m.coroutine ? 1 : 3));
1694                                         var ccast = new CCodeCastExpression (new CCodeIdentifier ("self"), "%s *".printf (get_ccode_name (base_type)));
1695                                         func.add_assignment (new CCodeMemberAccess.pointer (ccast, get_ccode_vfunc_name (m.base_method)), cfunc);
1696
1697                                         if (m.coroutine) {
1698                                                 cfunc = new CCodeIdentifier (get_ccode_finish_real_name (m));
1699                                                 cfunc = cast_method_pointer (m.base_method, cfunc, base_type, 2);
1700                                                 ccode.add_assignment (new CCodeMemberAccess.pointer (ccast, get_ccode_finish_vfunc_name (m.base_method)), cfunc);
1701                                         }
1702                                 }
1703                         }
1704
1705                         // connect overridden properties
1706                         foreach (Property prop in cl.get_properties ()) {
1707                                 if (prop.base_property == null || is_gsource) {
1708                                         continue;
1709                                 }
1710                                 var base_type = prop.base_property.parent_symbol;
1711
1712                                 var ccast = new CCodeCastExpression (new CCodeIdentifier ("self"), "%s *".printf (get_ccode_name (base_type)));
1713
1714                                 if (!get_ccode_no_accessor_method (prop.base_property) && !get_ccode_concrete_accessor (prop.base_property)) {
1715                                         if (prop.get_accessor != null) {
1716                                                 generate_property_accessor_declaration (prop.base_property.get_accessor, cfile);
1717
1718                                                 string cname = get_ccode_real_name (prop.get_accessor);
1719                                                 ccode.add_assignment (new CCodeMemberAccess.pointer (ccast, "get_%s".printf (prop.name)), new CCodeIdentifier (cname));
1720                                         }
1721                                         if (prop.set_accessor != null) {
1722                                                 generate_property_accessor_declaration (prop.base_property.set_accessor, cfile);
1723
1724                                                 string cname = get_ccode_real_name (prop.set_accessor);
1725                                                 ccode.add_assignment (new CCodeMemberAccess.pointer (ccast, "set_%s".printf (prop.name)), new CCodeIdentifier (cname));
1726                                         }
1727                                 }
1728                         }
1729                 }
1730
1731                 if (!cl.is_compact && (cl.has_private_fields || cl.has_type_parameters ())) {
1732                         var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_get_instance_private".printf (get_ccode_lower_case_name (cl, null))));
1733                         ccall.add_argument (new CCodeIdentifier ("self"));
1734                         func.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), ccall);
1735                 }
1736
1737                 pop_context ();
1738         }
1739
1740         private void add_instance_init_function (Class cl) {
1741                 push_context (instance_init_context);
1742                 end_instance_init (cl);
1743                 pop_context ();
1744
1745                 cfile.add_function (instance_init_context.ccode);
1746         }
1747
1748         private void begin_class_finalize_function (Class cl) {
1749                 push_context (class_finalize_context);
1750
1751                 var function = new CCodeFunction ("%s_class_finalize".printf (get_ccode_lower_case_name (cl, null)), "void");
1752                 function.modifiers = CCodeModifiers.STATIC;
1753
1754                 function.add_parameter (new CCodeParameter ("klass", "%s *".printf (get_ccode_type_name (cl))));
1755
1756                 push_function (function);
1757
1758                 if (cl.static_destructor != null) {
1759                         cl.static_destructor.body.emit (this);
1760
1761                         if (current_method_inner_error) {
1762                                 ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("_inner_error%d_".printf (current_inner_error_id), new CCodeConstant ("NULL")));
1763                         }
1764
1765                         if (current_method_return) {
1766                                 // support return statements in destructors
1767                                 ccode.add_label ("_return");
1768                                 ccode.add_statement (new CCodeEmptyStatement ());
1769                         }
1770                 }
1771
1772                 pop_context ();
1773         }
1774
1775         private void add_class_finalize_function (Class cl) {
1776                 cfile.add_function_declaration (class_finalize_context.ccode);
1777                 cfile.add_function (class_finalize_context.ccode);
1778         }
1779
1780         private void begin_base_finalize_function (Class cl) {
1781                 push_context (base_finalize_context);
1782
1783                 var function = new CCodeFunction ("%s_base_finalize".printf (get_ccode_lower_case_name (cl, null)), "void");
1784                 function.modifiers = CCodeModifiers.STATIC;
1785
1786                 function.add_parameter (new CCodeParameter ("klass", "%s *".printf (get_ccode_type_name (cl))));
1787                 function.add_parameter (new CCodeParameter ("klass_data", "gpointer"));
1788
1789                 push_function (function);
1790
1791                 if (cl.class_destructor != null) {
1792                         cl.class_destructor.body.emit (this);
1793
1794                         if (current_method_inner_error) {
1795                                 ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("_inner_error%d_".printf (current_inner_error_id), new CCodeConstant ("NULL")));
1796                         }
1797
1798                         if (current_method_return) {
1799                                 // support return statements in destructors
1800                                 ccode.add_label ("_return");
1801                                 ccode.add_statement (new CCodeEmptyStatement ());
1802                         }
1803                 }
1804
1805                 pop_context ();
1806         }
1807
1808         private void add_base_finalize_function (Class cl) {
1809                 push_context (base_finalize_context);
1810
1811                 cfile.add_function_declaration (ccode);
1812                 cfile.add_function (ccode);
1813
1814                 pop_context ();
1815         }
1816
1817         private void begin_finalize_function (Class cl) {
1818                 push_context (instance_finalize_context);
1819
1820                 bool is_gsource = cl.is_subtype_of (gsource_type);
1821
1822                 if (!cl.is_compact || is_gsource) {
1823                         var fundamental_class = cl;
1824                         while (fundamental_class.base_class != null) {
1825                                 fundamental_class = fundamental_class.base_class;
1826                         }
1827
1828                         var func = new CCodeFunction ("%sfinalize".printf (get_ccode_lower_case_prefix (cl)));
1829                         func.add_parameter (new CCodeParameter ("obj", "%s *".printf (get_ccode_name (fundamental_class))));
1830                         func.modifiers = CCodeModifiers.STATIC;
1831
1832                         push_function (func);
1833
1834                         if (is_gsource) {
1835                                 cfile.add_function_declaration (func);
1836                         }
1837
1838                         CCodeExpression ccast;
1839                         if (!cl.is_compact) {
1840                                 ccast = generate_instance_cast (new CCodeIdentifier ("obj"), cl);
1841                         } else {
1842                                 ccast = new CCodeCastExpression (new CCodeIdentifier ("obj"), "%s *".printf (get_ccode_name (cl)));
1843                         }
1844
1845                         ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self"));
1846                         ccode.add_assignment (new CCodeIdentifier ("self"), ccast);
1847
1848                         if (!cl.is_compact && cl.base_class == null) {
1849                                 // non-gobject class
1850                                 var call = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_handlers_destroy"));
1851                                 call.add_argument (new CCodeIdentifier ("self"));
1852                                 ccode.add_expression (call);
1853                         }
1854                 } else if (cl.base_class == null) {
1855                         var function = new CCodeFunction (get_ccode_free_function (cl), "void");
1856                         if (cl.is_private_symbol ()) {
1857                                 function.modifiers = CCodeModifiers.STATIC;
1858                         } else if (context.hide_internal && cl.is_internal_symbol ()) {
1859                                 function.modifiers = CCodeModifiers.INTERNAL;
1860                         }
1861
1862                         function.add_parameter (new CCodeParameter ("self", "%s *".printf (get_ccode_name (cl))));
1863
1864                         push_function (function);
1865                 }
1866
1867                 if (cl.destructor != null) {
1868                         cl.destructor.body.emit (this);
1869
1870                         if (current_method_inner_error) {
1871                                 ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("_inner_error%d_".printf (current_inner_error_id), new CCodeConstant ("NULL")));
1872                         }
1873
1874                         if (current_method_return) {
1875                                 // support return statements in destructors
1876                                 ccode.add_label ("_return");
1877                         }
1878                 }
1879
1880                 pop_context ();
1881         }
1882
1883         private void add_finalize_function (Class cl) {
1884                 if (!cl.is_compact) {
1885                         var fundamental_class = cl;
1886                         while (fundamental_class.base_class != null) {
1887                                 fundamental_class = fundamental_class.base_class;
1888                         }
1889
1890                         // chain up to finalize function of the base class
1891                         if (cl.base_class != null) {
1892                                 var ccast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function (fundamental_class)));
1893                                 ccast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (cl, null))));
1894                                 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (ccast, "finalize"));
1895                                 ccall.add_argument (new CCodeIdentifier ("obj"));
1896                                 push_context (instance_finalize_context);
1897                                 ccode.add_expression (ccall);
1898                                 pop_context ();
1899                         }
1900
1901                         cfile.add_function_declaration (instance_finalize_context.ccode);
1902                         cfile.add_function (instance_finalize_context.ccode);
1903                 } else if (cl.base_class == null) {
1904                         // g_slice_free needs glib.h
1905                         cfile.add_include ("glib.h");
1906                         var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_free"));
1907                         ccall.add_argument (new CCodeIdentifier (get_ccode_name (cl)));
1908                         ccall.add_argument (new CCodeIdentifier ("self"));
1909                         push_context (instance_finalize_context);
1910                         ccode.add_expression (ccall);
1911                         pop_context ();
1912
1913                         cfile.add_function (instance_finalize_context.ccode);
1914                 } else if (cl.is_subtype_of (gsource_type)) {
1915                         cfile.add_function (instance_finalize_context.ccode);
1916                 }
1917         }
1918
1919         public override CCodeExpression get_param_spec_cexpression (Property prop) {
1920                 var cl = (TypeSymbol) prop.parent_symbol;
1921                 var prop_array = new CCodeIdentifier ("%s_properties".printf (get_ccode_lower_case_name (cl)));
1922                 var prop_enum_value = new CCodeIdentifier ("%s_PROPERTY".printf (get_ccode_upper_case_name (prop)));
1923
1924                 return new CCodeElementAccess (prop_array, prop_enum_value);
1925         }
1926
1927         public override CCodeExpression get_param_spec (Property prop) {
1928                 var cspec = new CCodeFunctionCall ();
1929                 cspec.add_argument (get_property_canonical_cconstant (prop));
1930                 cspec.add_argument (new CCodeConstant ("\"%s\"".printf (prop.nick)));
1931                 cspec.add_argument (new CCodeConstant ("\"%s\"".printf (prop.blurb)));
1932
1933                 unowned TypeSymbol? type_symbol = prop.property_type.type_symbol;
1934                 if (type_symbol is Class || type_symbol is Interface) {
1935                         string param_spec_name = get_ccode_param_spec_function (type_symbol);
1936                         cspec.call = new CCodeIdentifier (param_spec_name);
1937                         if (param_spec_name == "g_param_spec_string") {
1938                                 cspec.add_argument (new CCodeConstant ("NULL"));
1939                         } else if (param_spec_name == "g_param_spec_variant") {
1940                                 cspec.add_argument (new CCodeConstant ("G_VARIANT_TYPE_ANY"));
1941                                 cspec.add_argument (new CCodeConstant ("NULL"));
1942                         } else if (param_spec_name == "gtk_param_spec_expression") {
1943                                 // No additional parameter required
1944                         } else if (get_ccode_type_id (type_symbol) != "G_TYPE_POINTER") {
1945                                 cspec.add_argument (new CCodeIdentifier (get_ccode_type_id (type_symbol)));
1946                         }
1947                 } else if (type_symbol is Enum) {
1948                         unowned Enum e = (Enum) type_symbol;
1949                         if (get_ccode_has_type_id (e)) {
1950                                 if (e.is_flags) {
1951                                         cspec.call = new CCodeIdentifier ("g_param_spec_flags");
1952                                 } else {
1953                                         cspec.call = new CCodeIdentifier ("g_param_spec_enum");
1954                                 }
1955                                 cspec.add_argument (new CCodeIdentifier (get_ccode_type_id (e)));
1956                         } else {
1957                                 if (e.is_flags) {
1958                                         cspec.call = new CCodeIdentifier ("g_param_spec_uint");
1959                                         cspec.add_argument (new CCodeConstant ("0"));
1960                                         cspec.add_argument (new CCodeConstant ("G_MAXUINT"));
1961                                 } else {
1962                                         cspec.call = new CCodeIdentifier ("g_param_spec_int");
1963                                         cspec.add_argument (new CCodeConstant ("G_MININT"));
1964                                         cspec.add_argument (new CCodeConstant ("G_MAXINT"));
1965                                 }
1966                         }
1967
1968                         if (prop.initializer != null) {
1969                                 cspec.add_argument ((CCodeExpression) get_ccodenode (prop.initializer));
1970                         } else {
1971                                 cspec.add_argument (new CCodeConstant (get_ccode_default_value (type_symbol)));
1972                         }
1973                 } else if (type_symbol is Struct) {
1974                         unowned Struct st = (Struct) type_symbol;
1975                         var type_id = get_ccode_type_id (st);
1976                         if (type_id == "G_TYPE_INT") {
1977                                 cspec.call = new CCodeIdentifier ("g_param_spec_int");
1978                                 cspec.add_argument (new CCodeConstant ("G_MININT"));
1979                                 cspec.add_argument (new CCodeConstant ("G_MAXINT"));
1980                                 if (prop.initializer != null) {
1981                                         cspec.add_argument ((CCodeExpression) get_ccodenode (prop.initializer));
1982                                 } else {
1983                                         cspec.add_argument (new CCodeConstant ("0"));
1984                                 }
1985                         } else if (type_id == "G_TYPE_UINT") {
1986                                 cspec.call = new CCodeIdentifier ("g_param_spec_uint");
1987                                 cspec.add_argument (new CCodeConstant ("0"));
1988                                 cspec.add_argument (new CCodeConstant ("G_MAXUINT"));
1989                                 if (prop.initializer != null) {
1990                                         cspec.add_argument ((CCodeExpression) get_ccodenode (prop.initializer));
1991                                 } else {
1992                                         cspec.add_argument (new CCodeConstant ("0U"));
1993                                 }
1994                         } else if (type_id == "G_TYPE_INT64") {
1995                                 cspec.call = new CCodeIdentifier ("g_param_spec_int64");
1996                                 cspec.add_argument (new CCodeConstant ("G_MININT64"));
1997                                 cspec.add_argument (new CCodeConstant ("G_MAXINT64"));
1998                                 if (prop.initializer != null) {
1999                                         cspec.add_argument ((CCodeExpression) get_ccodenode (prop.initializer));
2000                                 } else {
2001                                         cspec.add_argument (new CCodeConstant ("0"));
2002                                 }
2003                         } else if (type_id == "G_TYPE_UINT64") {
2004                                 cspec.call = new CCodeIdentifier ("g_param_spec_uint64");
2005                                 cspec.add_argument (new CCodeConstant ("0"));
2006                                 cspec.add_argument (new CCodeConstant ("G_MAXUINT64"));
2007                                 if (prop.initializer != null) {
2008                                         cspec.add_argument ((CCodeExpression) get_ccodenode (prop.initializer));
2009                                 } else {
2010                                         cspec.add_argument (new CCodeConstant ("0U"));
2011                                 }
2012                         } else if (type_id == "G_TYPE_LONG") {
2013                                 cspec.call = new CCodeIdentifier ("g_param_spec_long");
2014                                 cspec.add_argument (new CCodeConstant ("G_MINLONG"));
2015                                 cspec.add_argument (new CCodeConstant ("G_MAXLONG"));
2016                                 if (prop.initializer != null) {
2017                                         cspec.add_argument ((CCodeExpression) get_ccodenode (prop.initializer));
2018                                 } else {
2019                                         cspec.add_argument (new CCodeConstant ("0L"));
2020                                 }
2021                         } else if (type_id == "G_TYPE_ULONG") {
2022                                 cspec.call = new CCodeIdentifier ("g_param_spec_ulong");
2023                                 cspec.add_argument (new CCodeConstant ("0"));
2024                                 cspec.add_argument (new CCodeConstant ("G_MAXULONG"));
2025                                 if (prop.initializer != null) {
2026                                         cspec.add_argument ((CCodeExpression) get_ccodenode (prop.initializer));
2027                                 } else {
2028                                         cspec.add_argument (new CCodeConstant ("0UL"));
2029                                 }
2030                         } else if (type_id == "G_TYPE_BOOLEAN") {
2031                                 cspec.call = new CCodeIdentifier ("g_param_spec_boolean");
2032                                 if (prop.initializer != null) {
2033                                         cspec.add_argument ((CCodeExpression) get_ccodenode (prop.initializer));
2034                                 } else {
2035                                         cspec.add_argument (new CCodeConstant ("FALSE"));
2036                                 }
2037                         } else if (type_id == "G_TYPE_CHAR") {
2038                                 cspec.call = new CCodeIdentifier ("g_param_spec_char");
2039                                 cspec.add_argument (new CCodeConstant ("G_MININT8"));
2040                                 cspec.add_argument (new CCodeConstant ("G_MAXINT8"));
2041                                 if (prop.initializer != null) {
2042                                         cspec.add_argument ((CCodeExpression) get_ccodenode (prop.initializer));
2043                                 } else {
2044                                         cspec.add_argument (new CCodeConstant ("0"));
2045                                 }
2046                         } else if (type_id == "G_TYPE_UCHAR") {
2047                                 cspec.call = new CCodeIdentifier ("g_param_spec_uchar");
2048                                 cspec.add_argument (new CCodeConstant ("0"));
2049                                 cspec.add_argument (new CCodeConstant ("G_MAXUINT8"));
2050                                 if (prop.initializer != null) {
2051                                         cspec.add_argument ((CCodeExpression) get_ccodenode (prop.initializer));
2052                                 } else {
2053                                         cspec.add_argument (new CCodeConstant ("0"));
2054                                 }
2055                         } else if (type_id == "G_TYPE_FLOAT") {
2056                                 cspec.call = new CCodeIdentifier ("g_param_spec_float");
2057                                 cspec.add_argument (new CCodeConstant ("-G_MAXFLOAT"));
2058                                 cspec.add_argument (new CCodeConstant ("G_MAXFLOAT"));
2059                                 if (prop.initializer != null) {
2060                                         cspec.add_argument ((CCodeExpression) get_ccodenode (prop.initializer));
2061                                 } else {
2062                                         cspec.add_argument (new CCodeConstant ("0.0F"));
2063                                 }
2064                         } else if (type_id == "G_TYPE_DOUBLE") {
2065                                 cspec.call = new CCodeIdentifier ("g_param_spec_double");
2066                                 cspec.add_argument (new CCodeConstant ("-G_MAXDOUBLE"));
2067                                 cspec.add_argument (new CCodeConstant ("G_MAXDOUBLE"));
2068                                 if (prop.initializer != null) {
2069                                         cspec.add_argument ((CCodeExpression) get_ccodenode (prop.initializer));
2070                                 } else {
2071                                         cspec.add_argument (new CCodeConstant ("0.0"));
2072                                 }
2073                         } else if (type_id == "G_TYPE_GTYPE") {
2074                                 cspec.call = new CCodeIdentifier ("g_param_spec_gtype");
2075                                 if (prop.initializer != null) {
2076                                         cspec.add_argument ((CCodeExpression) get_ccodenode (prop.initializer));
2077                                 } else {
2078                                         cspec.add_argument (new CCodeConstant ("G_TYPE_NONE"));
2079                                 }
2080                         } else {
2081                                 cspec.call = new CCodeIdentifier ("g_param_spec_boxed");
2082                                 cspec.add_argument (new CCodeIdentifier (type_id));
2083                         }
2084                 } else if (prop.property_type is ArrayType && ((ArrayType)prop.property_type).element_type.type_symbol == string_type.type_symbol) {
2085                         cspec.call = new CCodeIdentifier ("g_param_spec_boxed");
2086                         cspec.add_argument (new CCodeIdentifier ("G_TYPE_STRV"));
2087                 } else {
2088                         cspec.call = new CCodeIdentifier ("g_param_spec_pointer");
2089                 }
2090
2091                 var pflags = "G_PARAM_STATIC_STRINGS";
2092                 if (prop.get_accessor != null && prop.get_accessor.access != SymbolAccessibility.PRIVATE) {
2093                         pflags = "%s%s".printf (pflags, " | G_PARAM_READABLE");
2094                 }
2095                 if (prop.set_accessor != null && prop.set_accessor.access != SymbolAccessibility.PRIVATE) {
2096                         pflags = "%s%s".printf (pflags, " | G_PARAM_WRITABLE");
2097                         if (prop.set_accessor.construction) {
2098                                 if (prop.set_accessor.writable) {
2099                                         pflags = "%s%s".printf (pflags, " | G_PARAM_CONSTRUCT");
2100                                 } else {
2101                                         pflags = "%s%s".printf (pflags, " | G_PARAM_CONSTRUCT_ONLY");
2102                                 }
2103                         }
2104                 }
2105                 if (!prop.notify) {
2106                         pflags = "%s%s".printf (pflags, " | G_PARAM_EXPLICIT_NOTIFY");
2107                 }
2108                 if (prop.version.deprecated) {
2109                         pflags = "%s%s".printf (pflags, " | G_PARAM_DEPRECATED");
2110                 }
2111                 cspec.add_argument (new CCodeConstant (pflags));
2112
2113                 if (prop.parent_symbol is Interface) {
2114                         return cspec;
2115                 } else {
2116                         return new CCodeAssignment (get_param_spec_cexpression (prop), cspec);
2117                 }
2118         }
2119
2120         public override void generate_interface_declaration (Interface iface, CCodeFile decl_space) {
2121                 if (add_symbol_declaration (decl_space, iface, get_ccode_name (iface))) {
2122                         return;
2123                 }
2124
2125                 decl_space.add_include ("glib-object.h");
2126
2127                 var instance_struct = new CCodeStruct ("_%s".printf (get_ccode_name (iface)));
2128                 var type_struct = new CCodeStruct ("_%s".printf (get_ccode_type_name (iface)));
2129
2130                 decl_space.add_type_declaration (new CCodeNewline ());
2131                 var macro = "(%s_get_type ())".printf (get_ccode_lower_case_name (iface, null));
2132                 decl_space.add_type_declaration (new CCodeMacroReplacement (get_ccode_type_id (iface), macro));
2133
2134                 macro = "(G_TYPE_CHECK_INSTANCE_CAST ((obj), %s, %s))".printf (get_ccode_type_id (iface), get_ccode_name (iface));
2135                 decl_space.add_type_declaration (new CCodeMacroReplacement ("%s(obj)".printf (get_ccode_type_cast_function (iface)), macro));
2136
2137                 macro = "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), %s))".printf (get_ccode_type_id (iface));
2138                 decl_space.add_type_declaration (new CCodeMacroReplacement ("%s(obj)".printf (get_ccode_type_check_function (iface)), macro));
2139
2140                 macro = "(G_TYPE_INSTANCE_GET_INTERFACE ((obj), %s, %s))".printf (get_ccode_type_id (iface), get_ccode_type_name (iface));
2141                 decl_space.add_type_declaration (new CCodeMacroReplacement ("%s(obj)".printf (get_ccode_type_get_function (iface)), macro));
2142                 decl_space.add_type_declaration (new CCodeNewline ());
2143
2144                 decl_space.add_type_declaration (new CCodeTypeDefinition ("struct _%s".printf (get_ccode_name (iface)), new CCodeVariableDeclarator (get_ccode_name (iface))));
2145                 decl_space.add_type_declaration (new CCodeTypeDefinition ("struct %s".printf (type_struct.name), new CCodeVariableDeclarator (get_ccode_type_name (iface))));
2146
2147                 foreach (DataType prerequisite in iface.get_prerequisites ()) {
2148                         unowned Class? prereq_cl = prerequisite.type_symbol as Class;
2149                         unowned Interface? prereq_iface = prerequisite.type_symbol as Interface;
2150                         if (prereq_cl != null) {
2151                                 generate_class_declaration (prereq_cl, decl_space);
2152                         } else if (prereq_iface != null) {
2153                                 generate_interface_declaration (prereq_iface, decl_space);
2154                         }
2155                 }
2156
2157                 type_struct.add_field ("GTypeInterface", "parent_iface");
2158
2159                 if (iface.get_attribute ("GenericAccessors") != null) {
2160                         foreach (TypeParameter p in iface.get_type_parameters ()) {
2161                                 var vdeclarator = new CCodeFunctionDeclarator ("get_%s".printf (get_ccode_type_id (p)));
2162                                 var this_type = SemanticAnalyzer.get_data_type_for_symbol (iface);
2163                                 vdeclarator.add_parameter (new CCodeParameter ("self", get_ccode_name (this_type)));
2164
2165                                 var vdecl = new CCodeDeclaration ("GType");
2166                                 vdecl.add_declarator (vdeclarator);
2167                                 type_struct.add_declaration (vdecl);
2168
2169                                 vdeclarator = new CCodeFunctionDeclarator ("get_%s".printf (get_ccode_copy_function (p)));
2170                                 this_type = SemanticAnalyzer.get_data_type_for_symbol (iface);
2171                                 vdeclarator.add_parameter (new CCodeParameter ("self", get_ccode_name (this_type)));
2172
2173                                 vdecl = new CCodeDeclaration ("GBoxedCopyFunc");
2174                                 vdecl.add_declarator (vdeclarator);
2175                                 type_struct.add_declaration (vdecl);
2176
2177                                 vdeclarator = new CCodeFunctionDeclarator ("get_%s".printf (get_ccode_destroy_function (p)));
2178                                 this_type = SemanticAnalyzer.get_data_type_for_symbol (iface);
2179                                 vdeclarator.add_parameter (new CCodeParameter ("self", get_ccode_name (this_type)));
2180
2181                                 vdecl = new CCodeDeclaration ("GDestroyNotify");
2182                                 vdecl.add_declarator (vdeclarator);
2183                                 type_struct.add_declaration (vdecl);
2184                         }
2185                 }
2186
2187                 foreach (Symbol sym in iface.get_virtuals ()) {
2188                         Method m;
2189                         Signal sig;
2190                         Property prop;
2191                         if ((m = sym as Method) != null) {
2192                                 generate_struct_method_declaration (iface, m, instance_struct, type_struct, decl_space);
2193                         } else if ((sig = sym as Signal) != null) {
2194                                 if (sig.default_handler != null) {
2195                                         if (sig.is_virtual) {
2196                                                 generate_virtual_method_declaration (sig.default_handler, decl_space, type_struct);
2197                                         } else {
2198                                                 generate_method_declaration (sig.default_handler, cfile);
2199                                         }
2200                                 }
2201                         } else if ((prop = sym as Property) != null) {
2202                                 generate_struct_property_declaration (iface, prop, instance_struct, type_struct, decl_space);
2203                         } else {
2204                                 Report.error (sym.source_reference, "internal: Unsupported symbol");
2205                         }
2206                 }
2207
2208                 decl_space.add_type_definition (type_struct);
2209
2210                 var type_fun = new InterfaceRegisterFunction (iface);
2211                 type_fun.init_from_type (context, in_plugin, true);
2212                 decl_space.add_type_member_declaration (type_fun.get_declaration ());
2213
2214                 requires_vala_extern = true;
2215         }
2216
2217         public override void visit_interface (Interface iface) {
2218                 push_context (new EmitContext (iface));
2219                 push_line (iface.source_reference);
2220
2221                 var old_signal_enum = signal_enum;
2222
2223                 if (get_ccode_name (iface).length < 3) {
2224                         iface.error = true;
2225                         Report.error (iface.source_reference, "Interface name `%s' is too short", get_ccode_name (iface));
2226                         return;
2227                 }
2228
2229                 signal_enum = new CCodeEnum ();
2230
2231                 generate_interface_declaration (iface, cfile);
2232                 if (!iface.is_internal_symbol ()) {
2233                         generate_interface_declaration (iface, header_file);
2234                 }
2235                 if (!iface.is_private_symbol ()) {
2236                         generate_interface_declaration (iface, internal_header_file);
2237                 }
2238
2239                 iface.accept_children (this);
2240
2241                 if (iface.get_signals ().size > 0) {
2242                         var last_signal = "%s_NUM_SIGNALS".printf (get_ccode_upper_case_name (iface));
2243                         signal_enum.add_value (new CCodeEnumValue (last_signal));
2244                         cfile.add_type_declaration (signal_enum);
2245
2246                         var signal_array_decl = new CCodeDeclaration ("guint");
2247                         signal_array_decl.modifiers |= CCodeModifiers.STATIC;
2248                         signal_array_decl.add_declarator (new CCodeVariableDeclarator ("%s_signals".printf (get_ccode_lower_case_name (iface)), new CCodeConstant ("{0}"), new CCodeDeclaratorSuffix.with_array (new CCodeIdentifier (last_signal))));
2249                         cfile.add_type_declaration (signal_array_decl);
2250                 }
2251
2252                 add_interface_default_init_function (iface);
2253
2254                 if (iface.comment != null) {
2255                         cfile.add_type_member_definition (new CCodeComment (iface.comment.content));
2256                 }
2257
2258                 var type_fun = new InterfaceRegisterFunction (iface);
2259                 type_fun.init_from_type (context, in_plugin, false);
2260                 cfile.add_type_member_declaration (type_fun.get_source_declaration ());
2261                 cfile.add_type_member_definition (type_fun.get_definition ());
2262
2263                 signal_enum = old_signal_enum;
2264
2265                 pop_line ();
2266                 pop_context ();
2267         }
2268
2269         private void add_interface_default_init_function (Interface iface) {
2270                 push_context (new EmitContext (iface));
2271
2272                 var default_init = new CCodeFunction ("%s_default_init".printf (get_ccode_lower_case_name (iface, null)), "void");
2273                 default_init.add_parameter (new CCodeParameter ("iface", "%s *".printf (get_ccode_type_name (iface))));
2274                 default_init.add_parameter (new CCodeParameter ("iface_data", "gpointer"));
2275                 default_init.modifiers = CCodeModifiers.STATIC;
2276
2277                 push_function (default_init);
2278
2279                 if (iface.is_subtype_of (gobject_type)) {
2280                         /* create properties */
2281                         var props = iface.get_properties ();
2282                         foreach (Property prop in props) {
2283                                 if (prop.is_abstract) {
2284                                         if (!context.analyzer.is_gobject_property (prop)) {
2285                                                 continue;
2286                                         }
2287
2288                                         if (prop.comment != null) {
2289                                                 ccode.add_statement (new CCodeComment (prop.comment.content));
2290                                         }
2291
2292                                         var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_interface_install_property"));
2293                                         cinst.add_argument (new CCodeIdentifier ("iface"));
2294                                         cinst.add_argument (get_param_spec (prop));
2295
2296                                         ccode.add_expression (cinst);
2297                                 }
2298                         }
2299                 }
2300
2301                 var ciface = new CCodeIdentifier ("iface");
2302
2303                 /* connect default signal handlers */
2304                 foreach (Signal sig in iface.get_signals ()) {
2305                         if (sig.default_handler == null || !sig.is_virtual) {
2306                                 continue;
2307                         }
2308                         var cname = get_ccode_real_name (sig.default_handler);
2309                         ccode.add_assignment (new CCodeMemberAccess.pointer (ciface, get_ccode_vfunc_name (sig.default_handler)), new CCodeIdentifier (cname));
2310                 }
2311
2312                 /* create signals */
2313                 foreach (Signal sig in iface.get_signals ()) {
2314                         if (sig.comment != null) {
2315                                 ccode.add_statement (new CCodeComment (sig.comment.content));
2316                         }
2317                         ccode.add_expression (get_signal_creation (sig, iface));
2318                 }
2319
2320                 // connect default implementations
2321                 foreach (Method m in iface.get_methods ()) {
2322                         if (m.is_virtual) {
2323                                 var cname = get_ccode_real_name (m);
2324                                 ccode.add_assignment (new CCodeMemberAccess.pointer (ciface, get_ccode_vfunc_name (m)), new CCodeIdentifier (cname));
2325                                 if (m.coroutine) {
2326                                         ccode.add_assignment (new CCodeMemberAccess.pointer (ciface, get_ccode_finish_vfunc_name (m)), new CCodeIdentifier (get_ccode_finish_real_name (m)));
2327                                 }
2328                         }
2329                 }
2330
2331                 foreach (Property prop in iface.get_properties ()) {
2332                         if (prop.is_virtual) {
2333                                 if (prop.get_accessor != null) {
2334                                         string cname = get_ccode_real_name (prop.get_accessor);
2335                                         ccode.add_assignment (new CCodeMemberAccess.pointer (ciface, "get_%s".printf (prop.name)), new CCodeIdentifier (cname));
2336                                 }
2337                                 if (prop.set_accessor != null) {
2338                                         string cname = get_ccode_real_name (prop.set_accessor);
2339                                         ccode.add_assignment (new CCodeMemberAccess.pointer (ciface, "set_%s".printf (prop.name)), new CCodeIdentifier (cname));
2340                                 }
2341                         }
2342                 }
2343
2344                 pop_context ();
2345
2346                 cfile.add_function (default_init);
2347         }
2348
2349         public override void visit_struct (Struct st) {
2350                 // custom simple type structs cannot have a type id which depends on head-allocation
2351                 if (st.get_attribute ("SimpleType") != null && !st.has_attribute_argument ("CCode", "type_id")) {
2352                         st.set_attribute_bool ("CCode", "has_type_id", false);
2353                 }
2354
2355                 base.visit_struct (st);
2356
2357                 if (st.is_boolean_type () || st.is_integer_type () || st.is_floating_type ()) {
2358                         // Skip GType handling for these struct types,
2359                         // like in CCodeStructModule.generate_struct_declaration()
2360                         return;
2361                 }
2362
2363                 if (get_ccode_has_type_id (st)) {
2364                         if (get_ccode_name (st).length < 3) {
2365                                 st.error = true;
2366                                 Report.error (st.source_reference, "Struct name `%s' is too short", get_ccode_name (st));
2367                                 return;
2368                         }
2369
2370                         push_line (st.source_reference);
2371                         var type_fun = new StructRegisterFunction (st);
2372                         type_fun.init_from_type (context, false, false);
2373                         cfile.add_type_member_definition (type_fun.get_definition ());
2374                         pop_line ();
2375                 }
2376         }
2377
2378         public override void visit_enum (Enum en) {
2379                 base.visit_enum (en);
2380
2381                 if (get_ccode_has_type_id (en)) {
2382                         if (get_ccode_name (en).length < 3) {
2383                                 en.error = true;
2384                                 Report.error (en.source_reference, "Enum name `%s' is too short", get_ccode_name (en));
2385                                 return;
2386                         }
2387
2388                         push_line (en.source_reference);
2389                         var type_fun = new EnumRegisterFunction (en);
2390                         type_fun.init_from_type (context, false, false);
2391                         cfile.add_type_member_definition (type_fun.get_definition ());
2392                         pop_line ();
2393                 }
2394         }
2395
2396         public override void visit_method_call (MethodCall expr) {
2397                 var ma = expr.call as MemberAccess;
2398                 var mtype = expr.call.value_type as MethodType;
2399                 if (mtype == null || ma == null || ma.inner == null ||
2400                         !(ma.inner.value_type is EnumValueType) || !get_ccode_has_type_id (ma.inner.value_type.type_symbol) ||
2401                         mtype.method_symbol != ((EnumValueType) ma.inner.value_type).get_to_string_method ()) {
2402                         base.visit_method_call (expr);
2403                         return;
2404                 }
2405                 // to_string() on a gtype enum
2406
2407                 bool is_flags = ((Enum) ((EnumValueType) ma.inner.value_type).type_symbol).is_flags;
2408
2409                 push_line (expr.source_reference);
2410                 if (context.require_glib_version (2, 54)) {
2411                         var to_string = new CCodeFunctionCall (new CCodeIdentifier ((is_flags ? "g_flags_to_string" : "g_enum_to_string")));
2412                         to_string.add_argument (new CCodeIdentifier (get_ccode_type_id (ma.inner.value_type)));
2413                         to_string.add_argument ((CCodeExpression) get_ccodenode (((MemberAccess) expr.call).inner));
2414                         expr.value_type.value_owned = true;
2415                         set_cvalue (expr, to_string);
2416                 } else {
2417                         var temp_var = get_temp_variable (new CType (is_flags ? "GFlagsValue*" : "GEnumValue*", "NULL"), false, expr, false);
2418                         emit_temp_var (temp_var);
2419
2420                         var class_ref = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_ref"));
2421                         class_ref.add_argument (new CCodeIdentifier (get_ccode_type_id (ma.inner.value_type)));
2422                         var get_value = new CCodeFunctionCall (new CCodeIdentifier (is_flags ? "g_flags_get_first_value" : "g_enum_get_value"));
2423                         get_value.add_argument (class_ref);
2424                         get_value.add_argument ((CCodeExpression) get_ccodenode (((MemberAccess) expr.call).inner));
2425
2426                         ccode.add_assignment (get_variable_cexpression (temp_var.name), get_value);
2427                         var is_null_value = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, get_variable_cexpression (temp_var.name), new CCodeConstant ("NULL"));
2428                         set_cvalue (expr, new CCodeConditionalExpression (is_null_value, new CCodeMemberAccess.pointer (get_variable_cexpression (temp_var.name), "value_name"), new CCodeConstant ("NULL")));
2429                 }
2430                 pop_line ();
2431         }
2432
2433         public override void visit_property (Property prop) {
2434                 var cl = current_type_symbol as Class;
2435                 var st = current_type_symbol as Struct;
2436
2437                 var base_prop = prop;
2438                 if (prop.base_property != null) {
2439                         base_prop = prop.base_property;
2440                 } else if (prop.base_interface_property != null) {
2441                         base_prop = prop.base_interface_property;
2442                 }
2443
2444                 if (base_prop.get_attribute ("NoAccessorMethod") == null &&
2445                         prop.name == "type" && ((cl != null && !cl.is_compact) || (st != null && get_ccode_has_type_id (st)))) {
2446                         Report.error (prop.source_reference, "Property 'type' not allowed");
2447                         return;
2448                 }
2449                 base.visit_property (prop);
2450         }
2451
2452         public override void create_type_check_statement (CodeNode method_node, DataType ret_type, TypeSymbol t, bool non_null, string var_name) {
2453                 var ccheck = new CCodeFunctionCall ();
2454
2455                 if (!context.assert) {
2456                         return;
2457                 } else if (context.checking && ((t is Class && !((Class) t).is_compact) || t is Interface)) {
2458                         if (!get_ccode_has_type_id (t)) {
2459                                 return;
2460                         }
2461
2462                         CCodeFunctionCall ctype_check;
2463                         if (t.external_package) {
2464                                 ctype_check = new CCodeFunctionCall (new CCodeIdentifier ("G_TYPE_CHECK_INSTANCE_TYPE"));
2465                                 ctype_check.add_argument (new CCodeIdentifier (var_name));
2466                                 ctype_check.add_argument (new CCodeIdentifier (get_ccode_type_id (t)));
2467                         } else {
2468                                 ctype_check = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_type_check_function (t)));
2469                                 ctype_check.add_argument (new CCodeIdentifier (var_name));
2470                         }
2471
2472                         CCodeExpression cexpr = ctype_check;
2473                         if (!non_null) {
2474                                 var cnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (var_name), new CCodeConstant ("NULL"));
2475
2476                                 cexpr = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cnull, ctype_check);
2477                         }
2478                         ccheck.add_argument (cexpr);
2479                 } else if (!non_null || (t is Struct && ((Struct) t).is_simple_type ())) {
2480                         return;
2481                 } else if (t == glist_type || t == gslist_type) {
2482                         // NULL is empty list
2483                         return;
2484                 } else {
2485                         var cnonnull = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier (var_name), new CCodeConstant ("NULL"));
2486                         ccheck.add_argument (cnonnull);
2487                 }
2488
2489                 // g_return_* needs glib.h
2490                 cfile.add_include ("glib.h");
2491
2492                 var cm = method_node as CreationMethod;
2493                 if (cm != null && !cm.coroutine && cm.parent_symbol is ObjectTypeSymbol) {
2494                         ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
2495                         ccheck.add_argument (new CCodeConstant ("NULL"));
2496                 } else if (ret_type is VoidType) {
2497                         /* void function */
2498                         ccheck.call = new CCodeIdentifier ("g_return_if_fail");
2499                 } else {
2500                         ccheck.call = new CCodeIdentifier ("g_return_val_if_fail");
2501
2502                         var cdefault = default_value_for_type (ret_type, false);
2503                         if (cdefault != null) {
2504                                 ccheck.add_argument (cdefault);
2505                         } else if (ret_type.type_symbol is Struct && !((Struct) ret_type.type_symbol).is_simple_type ()) {
2506                                 ccheck.add_argument (new CCodeIdentifier ("result"));
2507                         } else {
2508                                 return;
2509                         }
2510                 }
2511
2512                 ccode.add_expression (ccheck);
2513         }
2514
2515         public override void visit_cast_expression (CastExpression expr) {
2516                 unowned ObjectTypeSymbol? type_symbol = expr.type_reference.type_symbol as ObjectTypeSymbol;
2517
2518                 if (type_symbol == null || (type_symbol is Class && ((Class) type_symbol).is_compact)) {
2519                         base.visit_cast_expression (expr);
2520                         return;
2521                 }
2522
2523                 generate_type_declaration (expr.type_reference, cfile);
2524
2525                 // checked cast for strict subtypes of GTypeInstance
2526                 if (expr.is_silent_cast) {
2527                         TargetValue to_cast = expr.inner.target_value;
2528                         CCodeExpression cexpr;
2529                         if (!get_lvalue (to_cast)) {
2530                                 to_cast = store_temp_value (to_cast, expr);
2531                         }
2532                         cexpr = get_cvalue_ (to_cast);
2533                         var ccheck = create_type_check (cexpr, expr.type_reference);
2534                         var ccast = new CCodeCastExpression (cexpr, get_ccode_name (expr.type_reference));
2535                         var cnull = new CCodeConstant ("NULL");
2536                         var cast_value = new GLibValue (expr.value_type, new CCodeConditionalExpression (ccheck, ccast, cnull));
2537                         if (requires_destroy (expr.inner.value_type)) {
2538                                 var casted = store_temp_value (cast_value, expr);
2539                                 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_cvalue_ (casted), new CCodeConstant ("NULL")));
2540                                 ccode.add_expression (destroy_value (to_cast));
2541                                 ccode.close ();
2542                                 expr.target_value = ((GLibValue) casted).copy ();
2543                         } else {
2544                                 expr.target_value = cast_value;
2545                         }
2546                 } else {
2547                         set_cvalue (expr, generate_instance_cast (get_cvalue (expr.inner), expr.type_reference.type_symbol));
2548                 }
2549         }
2550 }