change run to use meson/ninja and then exec. - remove libvala code from application...
[roobuilder] / src / codegen / valaccodemethodcallmodule.vala
1 /* valaccodemethodcallmodule.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 using GLib;
26
27 public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
28         public override void visit_method_call (MethodCall expr) {
29                 // the bare function call
30                 var ccall = new CCodeFunctionCall (get_cvalue (expr.call));
31
32                 CCodeFunctionCall async_call = null;
33                 CCodeFunctionCall finish_call = null;
34
35                 Method m = null;
36                 Delegate deleg = null;
37                 List<Parameter> params;
38
39                 var ma = expr.call as MemberAccess;
40
41                 var itype = expr.call.value_type;
42                 params = itype.get_parameters ();
43
44                 if (itype is MethodType) {
45                         assert (ma != null);
46                         m = ((MethodType) itype).method_symbol;
47
48                         if (!get_ccode_simple_generics (m)) {
49                                 context.analyzer.check_type_arguments (ma);
50                         }
51
52                         if (ma.inner != null && ma.inner.value_type is EnumValueType && ((EnumValueType) ma.inner.value_type).get_to_string_method() == m) {
53                                 // Enum.VALUE.to_string()
54                                 unowned Enum en = (Enum) ma.inner.value_type.type_symbol;
55                                 ccall.call = new CCodeIdentifier (generate_enum_to_string_function (en));
56                         } else if (context.profile == Profile.POSIX && ma.inner != null && ma.inner.value_type != null && ma.inner.value_type.type_symbol == string_type.type_symbol && ma.member_name == "printf") {
57                                 ccall.call = new CCodeIdentifier (generate_string_printf_function ());
58                         } else if (expr.is_constructv_chainup) {
59                                 ccall.call = new CCodeIdentifier (get_ccode_constructv_name ((CreationMethod) m));
60                         }
61                 } else if (itype is SignalType) {
62                         var sig_type = (SignalType) itype;
63                         if (ma != null && ma.inner is BaseAccess && sig_type.signal_symbol.is_virtual) {
64                                 m = sig_type.signal_symbol.default_handler;
65                         } else {
66                                 ccall = (CCodeFunctionCall) get_cvalue (expr.call);
67                         }
68                 } else if (itype is ObjectType) {
69                         // constructor
70                         var cl = (Class) ((ObjectType) itype).type_symbol;
71                         m = cl.default_construction_method;
72                         generate_method_declaration (m, cfile);
73                         var real_name = get_ccode_real_name (m);
74                         if (expr.is_constructv_chainup) {
75                                 real_name = get_ccode_constructv_name ((CreationMethod) m);
76                         }
77                         ccall = new CCodeFunctionCall (new CCodeIdentifier (real_name));
78                 } else if (itype is StructValueType) {
79                         // constructor
80                         var st = (Struct) ((StructValueType) itype).type_symbol;
81                         m = st.default_construction_method;
82                         generate_method_declaration (m, cfile);
83                         ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_real_name (m)));
84                 } else if (itype is DelegateType) {
85                         deleg = ((DelegateType) itype).delegate_symbol;
86                 }
87
88                 var in_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
89                 var out_arg_map = in_arg_map;
90
91                 if (m != null && m.coroutine) {
92                         // async call
93
94                         async_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (m)));
95                         finish_call = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_finish_name (m)));
96
97                         if (ma.inner is BaseAccess) {
98                                 CCodeExpression? vcast = null;
99                                 if (m.base_method != null) {
100                                         unowned Class base_class = (Class) m.base_method.parent_symbol;
101                                         vcast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function (base_class)));
102                                         ((CCodeFunctionCall) vcast).add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class))));
103                                 } else if (m.base_interface_method != null) {
104                                         unowned Interface base_iface = (Interface) m.base_interface_method.parent_symbol;
105                                         vcast = get_this_interface_cexpression (base_iface);
106                                 }
107                                 if (vcast != null) {
108                                         async_call.call = new CCodeMemberAccess.pointer (vcast, get_ccode_vfunc_name (m));
109                                         finish_call.call = new CCodeMemberAccess.pointer (vcast, get_ccode_finish_vfunc_name (m));
110                                 }
111                         } else if (m != null && get_ccode_no_wrapper (m) && m.binding == MemberBinding.INSTANCE && !(m is CreationMethod)) {
112                                 var instance_value = ma.inner.target_value;
113                                 if ((ma.member_name == "begin" || ma.member_name == "end") && ma.inner.symbol_reference == ma.symbol_reference) {
114                                         var inner_ma = (MemberAccess) ma.inner;
115                                         instance_value = inner_ma.inner.target_value;
116                                 }
117
118                                 CCodeExpression? vcast = null;
119                                 if (m.parent_symbol is Class) {
120                                         unowned Class base_class = (Class) m.parent_symbol;
121                                         vcast = get_this_class_cexpression (base_class, instance_value);
122                                 } else if (m.parent_symbol is Interface) {
123                                         unowned Interface base_iface = (Interface) m.parent_symbol;
124                                         vcast = get_this_interface_cexpression (base_iface, instance_value);
125                                 }
126                                 if (vcast != null) {
127                                         async_call.call = new CCodeMemberAccess.pointer (vcast, get_ccode_vfunc_name (m));
128                                         finish_call.call = new CCodeMemberAccess.pointer (vcast, get_ccode_finish_vfunc_name (m));
129                                 }
130                         }
131
132                         if (ma.member_name == "begin" && ma.inner.symbol_reference == ma.symbol_reference) {
133                                 // no finish call
134                                 ccall = async_call;
135                                 params = m.get_async_begin_parameters ();
136                         } else if (ma.member_name == "end" && ma.inner.symbol_reference == ma.symbol_reference) {
137                                 // no async call
138                                 ccall = finish_call;
139                                 params = m.get_async_end_parameters ();
140                         } else if (!expr.is_yield_expression) {
141                                 // same as .begin, backwards compatible to bindings without async methods
142                                 ccall = async_call;
143                                 params = m.get_async_begin_parameters ();
144                         } else {
145                                 ccall = finish_call;
146                                 // output arguments used separately
147                                 out_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
148                                 // pass GAsyncResult stored in closure to finish function
149                                 out_arg_map.set (get_param_pos (get_ccode_async_result_pos (m)), get_variable_cexpression ("_res_"));
150                         }
151                 }
152
153                 if (m is CreationMethod && m.parent_symbol is Class) {
154                         if (context.profile == Profile.GOBJECT) {
155                                 if (!((Class) m.parent_symbol).is_compact) {
156                                         ccall.add_argument (get_variable_cexpression ("object_type"));
157                                 }
158                         } else {
159                                 ccall.add_argument (get_this_cexpression ());
160                         }
161
162                         if (!current_class.is_compact) {
163                                 int type_param_index = 0;
164                                 if (current_class != m.parent_symbol) {
165                                         // chain up to base class
166                                         foreach (DataType base_type in current_class.get_base_types ()) {
167                                                 if (base_type.type_symbol is Class) {
168                                                         List<TypeParameter> type_parameters = null;
169                                                         if (get_ccode_real_name (m) == "g_object_new") {
170                                                                 // gobject-style chainup
171                                                                 type_parameters = ((Class) base_type.type_symbol).get_type_parameters ();
172                                                                 type_param_index += type_parameters.size;
173                                                         }
174                                                         add_generic_type_arguments (m, in_arg_map, base_type.get_type_arguments (), expr, true, type_parameters);
175                                                         break;
176                                                 }
177                                         }
178                                 } else {
179                                         // chain up to other constructor in same class
180                                         var cl = (Class) m.parent_symbol;
181                                         foreach (TypeParameter type_param in cl.get_type_parameters ()) {
182                                                 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeIdentifier (get_ccode_type_id (type_param)));
183                                                 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier (get_ccode_copy_function (type_param)));
184                                                 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeIdentifier (get_ccode_destroy_function (type_param)));
185                                                 type_param_index++;
186                                         }
187                                 }
188                                 if (current_class.has_type_parameters () && get_ccode_real_name (m) == "g_object_new") {
189                                         // gobject-style construction
190                                         foreach (var type_param in current_class.get_type_parameters ()) {
191                                                 var type_param_name = type_param.name.ascii_down ().replace ("_", "-");
192                                                 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.01), new CCodeConstant ("\"%s-type\"".printf (type_param_name)));
193                                                 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.02), new CCodeIdentifier (get_ccode_type_id (type_param)));
194                                                 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.03), new CCodeConstant ("\"%s-dup-func\"".printf (type_param_name)));
195                                                 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.04), new CCodeIdentifier (get_ccode_copy_function (type_param)));
196                                                 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.05), new CCodeConstant ("\"%s-destroy-func\"".printf (type_param_name)));
197                                                 in_arg_map.set (get_param_pos (0.1 * type_param_index + 0.06), new CCodeIdentifier (get_ccode_destroy_function (type_param)));
198                                                 type_param_index++;
199                                         }
200                                 }
201                         } else if (current_class.is_subtype_of (gsource_type)) {
202                                 // g_source_new
203
204                                 string class_prefix = get_ccode_lower_case_name (current_class);
205                                 string prepare_func = "NULL";
206                                 string check_func = "NULL";
207                                 foreach (Method impl in current_class.get_methods ()) {
208                                         if (!impl.overrides) {
209                                                 continue;
210                                         }
211                                         switch (impl.name) {
212                                         case "prepare":
213                                                 prepare_func = "%s_real_prepare".printf (class_prefix);
214                                                 break;
215                                         case "check":
216                                                 check_func = "%s_real_check".printf (class_prefix);
217                                                 break;
218                                         default:
219                                                 break;
220                                         }
221                                 }
222
223                                 var funcs = new CCodeDeclaration ("const GSourceFuncs");
224                                 funcs.modifiers = CCodeModifiers.STATIC;
225                                 funcs.add_declarator (new CCodeVariableDeclarator ("_source_funcs", new CCodeConstant ("{ %s, %s, %s_real_dispatch, %s_finalize}".printf (prepare_func, check_func, class_prefix, class_prefix))));
226                                 ccode.add_statement (funcs);
227
228                                 ccall.add_argument (new CCodeCastExpression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_source_funcs")), "GSourceFuncs *"));
229
230                                 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
231                                 csizeof.add_argument (new CCodeIdentifier (get_ccode_name (current_class)));
232                                 ccall.add_argument (csizeof);
233                         } else if (current_class.base_class != null && get_ccode_simple_generics (m)) {
234                                 if (current_class != m.parent_symbol) {
235                                         foreach (DataType base_type in current_class.get_base_types ()) {
236                                                 if (base_type.type_symbol is Class) {
237                                                         add_generic_type_arguments (m, in_arg_map, base_type.get_type_arguments (), expr);
238                                                         break;
239                                                 }
240                                         }
241                                 } else {
242                                         // TODO: simple generics are only supported in bindings.
243                                 }
244                         }
245                 } else if (m is CreationMethod && m.parent_symbol is Struct) {
246                         ccall.add_argument (get_this_cexpression ());
247                 } else if (m != null && m.has_type_parameters () && !get_ccode_has_generic_type_parameter (m) && !get_ccode_simple_generics (m) && (ccall != finish_call || expr.is_yield_expression)) {
248                         // generic method
249                         // don't add generic arguments for .end() calls
250                         add_generic_type_arguments (m, in_arg_map, ma.get_type_arguments (), expr);
251                 }
252
253                 // the complete call expression, might include casts, comma expressions, and/or assignments
254                 CCodeExpression ccall_expr = ccall;
255
256                 if (m is ArrayResizeMethod && context.profile != Profile.POSIX) {
257                         var array_type = (ArrayType) ma.inner.value_type;
258                         in_arg_map.set (get_param_pos (0), new CCodeIdentifier (get_ccode_name (array_type.element_type)));
259                 } else if (m is ArrayMoveMethod) {
260                         requires_array_move = true;
261                 } else if (m is ArrayCopyMethod) {
262                         expr.target_value = copy_value (ma.inner.target_value, expr);
263                         return;
264                 }
265
266                 CCodeExpression instance = null;
267                 if (m != null && m.is_async_callback) {
268                         if (current_method.closure) {
269                                 var block = ((Method) m.parent_symbol).body;
270                                 instance = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), "_async_data_");
271                         } else {
272                                 instance = new CCodeIdentifier ("_data_");
273                         }
274
275                         in_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
276                         out_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
277                 } else if (m != null && m.binding == MemberBinding.INSTANCE && !(m is CreationMethod)) {
278                         var instance_value = ma.inner.target_value;
279                         if ((ma.member_name == "begin" || ma.member_name == "end") && ma.inner.symbol_reference == ma.symbol_reference) {
280                                 var inner_ma = (MemberAccess) ma.inner;
281                                 instance_value = inner_ma.inner.target_value;
282                         }
283                         instance = get_cvalue_ (instance_value);
284
285                         var st = m.parent_symbol as Struct;
286                         if (st != null && !st.is_simple_type ()) {
287                                 // we need to pass struct instance by reference
288                                 if (!get_lvalue (instance_value)) {
289                                         instance_value = store_temp_value (instance_value, expr);
290                                 }
291                                 instance = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (instance_value));
292                         }
293
294                         if (!m.coroutine) {
295                                 in_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
296                         } else if (expr.is_yield_expression) {
297                                 in_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
298                                 if (get_ccode_finish_instance (m)) {
299                                         out_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
300                                 }
301                         } else if (ma.member_name != "end" || get_ccode_finish_instance (m)) {
302                                 out_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
303                                 in_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), instance);
304                         }
305                 } else if (m != null && m.binding == MemberBinding.CLASS) {
306                         unowned Class cl = (Class) m.parent_symbol;
307                         var cast = get_this_class_cexpression (cl, ma.inner != null ? ma.inner.target_value : null);
308                         in_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), cast);
309                         out_arg_map.set (get_param_pos (get_ccode_instance_pos (m)), cast);
310                 }
311
312                 if (m != null && get_ccode_has_generic_type_parameter (m)) {
313                         // insert type argument for macros
314                         if (m.has_type_parameters ()) {
315                                 // generic method
316                                 int type_param_index = 0;
317                                 foreach (var type_arg in ma.get_type_arguments ()) {
318                                         // real structs are passed by reference for simple generics
319                                         if (get_ccode_simple_generics (m) && type_arg.is_real_struct_type () && !type_arg.nullable && !(type_arg is PointerType)) {
320                                             type_arg = new PointerType (type_arg);
321                                         }
322                                         in_arg_map.set (get_param_pos (get_ccode_generic_type_pos (m) + 0.01 * type_param_index), new CCodeIdentifier (get_ccode_name (type_arg)));
323                                         type_param_index++;
324                                 }
325                         } else {
326                                 // method in generic type
327                                 int type_param_index = 0;
328                                 foreach (var type_arg in ma.inner.value_type.get_type_arguments ()) {
329                                         in_arg_map.set (get_param_pos (get_ccode_generic_type_pos (m) + 0.01 * type_param_index), new CCodeIdentifier (get_ccode_name (type_arg)));
330                                         type_param_index++;
331                                 }
332                         }
333                 }
334
335                 if (m is ArrayMoveMethod) {
336                         var array_type = (ArrayType) ma.inner.value_type;
337                         var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
338                         csizeof.add_argument (new CCodeIdentifier (get_ccode_name (array_type.element_type)));
339                         in_arg_map.set (get_param_pos (0.1), csizeof);
340                 } else if (m is DynamicMethod) {
341                         emit_context.push_symbol (m);
342                         m.clear_parameters ();
343                         int param_nr = 1;
344                         foreach (Expression arg in expr.get_argument_list ()) {
345                                 var unary = arg as UnaryExpression;
346                                 if (unary != null && unary.operator == UnaryOperator.OUT) {
347                                         // out argument
348                                         var param = new Parameter ("param%d".printf (param_nr), unary.inner.value_type);
349                                         param.direction = ParameterDirection.OUT;
350                                         m.add_parameter (param);
351                                 } else if (unary != null && unary.operator == UnaryOperator.REF) {
352                                         // ref argument
353                                         var param = new Parameter ("param%d".printf (param_nr), unary.inner.value_type);
354                                         param.direction = ParameterDirection.REF;
355                                         m.add_parameter (param);
356                                 } else {
357                                         // in argument
358                                         m.add_parameter (new Parameter ("param%d".printf (param_nr), arg.value_type));
359                                 }
360                                 param_nr++;
361                         }
362                         foreach (Parameter param in m.get_parameters ()) {
363                                 param.accept (this);
364                         }
365                         generate_dynamic_method_wrapper ((DynamicMethod) m);
366                         emit_context.pop_symbol ();
367                 } else if (m is CreationMethod && context.profile == Profile.GOBJECT && m.parent_symbol is Class) {
368                         ccode.add_assignment (get_this_cexpression (), new CCodeCastExpression (ccall, get_ccode_name (current_class) + "*"));
369
370                         if (current_method.body.captured) {
371                                 // capture self after setting it
372                                 var ref_call = new CCodeFunctionCall (get_dup_func_expression (new ObjectType (current_class), expr.source_reference));
373                                 ref_call.add_argument (get_this_cexpression ());
374
375                                 ccode.add_assignment (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (current_method.body))), "self"), ref_call);
376                         }
377
378                         //FIXME Only needed for non-"g_object_new" calls, if there is no property clash
379                         if (!current_class.is_compact && current_class.has_type_parameters ()) {
380                                 /* type, dup func, and destroy func fields for generic types */
381                                 var priv_access = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv");
382                                 foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
383                                         var type = get_ccode_type_id (type_param);
384                                         var dup_func = get_ccode_copy_function (type_param);
385                                         var destroy_func = get_ccode_destroy_function (type_param);
386                                         ccode.add_assignment (new CCodeMemberAccess.pointer (priv_access, type), new CCodeIdentifier (type));
387                                         ccode.add_assignment (new CCodeMemberAccess.pointer (priv_access, dup_func), new CCodeIdentifier (dup_func));
388                                         ccode.add_assignment (new CCodeMemberAccess.pointer (priv_access, destroy_func), new CCodeIdentifier (destroy_func));
389                                 }
390                         }
391                         // object chainup can't be used as expression
392                         ccall_expr = null;
393                 }
394
395                 bool ellipsis = false;
396
397                 int i = 1;
398                 int arg_pos;
399                 Iterator<Parameter> params_it = params.iterator ();
400                 foreach (Expression arg in expr.get_argument_list ()) {
401                         CCodeExpression cexpr = get_cvalue (arg);
402
403                         var carg_map = in_arg_map;
404
405                         Parameter? param = null;
406                         if (params_it.next ()) {
407                                 param = params_it.get ();
408                                 ellipsis = param.params_array || param.ellipsis;
409                         }
410
411                         if (param != null && !ellipsis) {
412                                         if (param.direction == ParameterDirection.OUT) {
413                                                 carg_map = out_arg_map;
414                                         }
415
416                                         var unary = arg as UnaryExpression;
417                                         if (unary == null || unary.operator != UnaryOperator.OUT) {
418                                                 if (get_ccode_array_length (param) && param.variable_type is ArrayType && !((ArrayType) param.variable_type).fixed_length) {
419                                                         var array_type = (ArrayType) param.variable_type;
420                                                         var length_ctype = get_ccode_array_length_type (param);
421                                                         if (unary != null && unary.operator == UnaryOperator.REF) {
422                                                                 length_ctype = "%s*".printf (length_ctype);
423                                                         }
424                                                         for (int dim = 1; dim <= array_type.rank; dim++) {
425                                                                 var array_length_expr = new CCodeCastExpression (get_array_length_cexpression (arg, dim), length_ctype);
426                                                                 carg_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), array_length_expr);
427                                                         }
428                                                 } else if (get_ccode_delegate_target (param) && param.variable_type is DelegateType) {
429                                                         var deleg_type = (DelegateType) param.variable_type;
430                                                         if (deleg_type.delegate_symbol.has_target) {
431                                                                 CCodeExpression delegate_target_destroy_notify;
432                                                                 var delegate_target = get_delegate_target_cexpression (arg, out delegate_target_destroy_notify);
433                                                                 assert (delegate_target != null);
434                                                                 if (get_ccode_type (param) == "GClosure*") {
435                                                                         // one single GClosure parameter
436                                                                         var closure_new = new CCodeFunctionCall (new CCodeIdentifier ("g_cclosure_new"));
437                                                                         closure_new.add_argument (new CCodeCastExpression (cexpr, "GCallback"));
438                                                                         closure_new.add_argument (delegate_target);
439                                                                         closure_new.add_argument (new CCodeCastExpression (delegate_target_destroy_notify, "GClosureNotify"));
440                                                                         //TODO Use get_non_null (arg.target_value)
441                                                                         if (arg.is_non_null ()) {
442                                                                                 cexpr = closure_new;
443                                                                         } else {
444                                                                                 cexpr = new CCodeConditionalExpression (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, cexpr, new CCodeConstant ("NULL")), new CCodeConstant ("NULL"), closure_new);
445                                                                         }
446                                                                 } else {
447                                                                         // Override previously given target/destroy only if it was NULL
448                                                                         // TODO https://gitlab.gnome.org/GNOME/vala/issues/59
449                                                                         var node = carg_map.get (get_param_pos (get_ccode_delegate_target_pos (param)));
450                                                                         if (node == null || (node is CCodeConstant && ((CCodeConstant) node).name == "NULL")) {
451                                                                                 carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param)), delegate_target);
452                                                                                 if (deleg_type.is_disposable ()) {
453                                                                                         assert (delegate_target_destroy_notify != null);
454                                                                                         carg_map.set (get_param_pos (get_ccode_destroy_notify_pos (param)), delegate_target_destroy_notify);
455                                                                                 }
456                                                                         }
457                                                                 }
458                                                         }
459                                                 } else if (param.variable_type is MethodType) {
460                                                         // callbacks in dynamic method calls
461                                                         CCodeExpression delegate_target_destroy_notify;
462                                                         carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param)), get_delegate_target_cexpression (arg, out delegate_target_destroy_notify));
463                                                 } else if (param.variable_type is GenericType) {
464                                                         if (m != null && get_ccode_simple_generics (m)) {
465                                                                 var generic_type = (GenericType) param.variable_type;
466                                                                 int type_param_index = m.get_type_parameter_index (generic_type.type_parameter.name);
467                                                                 var type_arg = ma.get_type_arguments ().get (type_param_index);
468                                                                 if (param.variable_type.value_owned) {
469                                                                         if (requires_copy (type_arg)) {
470                                                                                 carg_map.set (get_param_pos (get_ccode_destroy_notify_pos (param)), get_destroy_func_expression (type_arg));
471                                                                         } else {
472                                                                                 carg_map.set (get_param_pos (get_ccode_destroy_notify_pos (param)), new CCodeConstant ("NULL"));
473                                                                         }
474                                                                 }
475                                                         }
476                                                 }
477
478                                                 cexpr = handle_struct_argument (param, arg, cexpr);
479                                         } else {
480                                                 arg.target_value = null;
481
482                                                 var temp_var = get_temp_variable (param.variable_type, param.variable_type.value_owned, null, true);
483                                                 emit_temp_var (temp_var);
484                                                 set_cvalue (arg, get_variable_cexpression (temp_var.name));
485                                                 arg.target_value.value_type = arg.target_type;
486
487                                                 cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (arg));
488
489                                                 if (get_ccode_array_length (param) && param.variable_type is ArrayType && !((ArrayType) param.variable_type).fixed_length) {
490                                                         var array_type = (ArrayType) param.variable_type;
491                                                         var length_ctype = get_ccode_array_length_type (param);
492                                                         for (int dim = 1; dim <= array_type.rank; dim++) {
493                                                                 var temp_array_length = get_temp_variable (new CType (length_ctype, "0"), true, null, true);
494                                                                 emit_temp_var (temp_array_length);
495                                                                 append_array_length (arg, get_variable_cexpression (temp_array_length.name));
496                                                                 carg_map.set (get_param_pos (get_ccode_array_length_pos (param) + 0.01 * dim), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_lengths (arg).get (dim - 1)));
497                                                         }
498                                                 } else if (get_ccode_delegate_target (param) && param.variable_type is DelegateType) {
499                                                         var deleg_type = (DelegateType) param.variable_type;
500                                                         if (deleg_type.delegate_symbol.has_target) {
501                                                                 temp_var = get_temp_variable (delegate_target_type, true, null, true);
502                                                                 emit_temp_var (temp_var);
503                                                                 set_delegate_target (arg, get_variable_cexpression (temp_var.name));
504                                                                 carg_map.set (get_param_pos (get_ccode_delegate_target_pos (param)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_delegate_target (arg)));
505                                                                 if (deleg_type.is_disposable ()) {
506                                                                         temp_var = get_temp_variable (delegate_target_destroy_type, true, null, true);
507                                                                         emit_temp_var (temp_var);
508                                                                         set_delegate_target_destroy_notify (arg, get_variable_cexpression (temp_var.name));
509                                                                         carg_map.set (get_param_pos (get_ccode_destroy_notify_pos (param)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_delegate_target_destroy_notify (arg)));
510                                                                 }
511                                                         }
512                                                 }
513                                         }
514
515                                         if (get_ccode_type (param) != null) {
516                                                 cexpr = new CCodeCastExpression (cexpr, get_ccode_type (param));
517                                         }
518                         } else {
519                                 // ellipsis arguments
520                                 var unary = arg as UnaryExpression;
521                                 if (ellipsis && unary != null && unary.operator == UnaryOperator.OUT) {
522                                         carg_map = out_arg_map;
523
524                                         arg.target_value = null;
525
526                                         // infer type and ownership from argument expression
527                                         var temp_var = get_temp_variable (arg.value_type, arg.value_type.value_owned, null, true);
528                                         emit_temp_var (temp_var);
529                                         set_cvalue (arg, get_variable_cexpression (temp_var.name));
530                                         arg.target_value.value_type = arg.value_type;
531
532                                         if (arg.value_type is DelegateType && ((DelegateType) arg.value_type).delegate_symbol.has_target) {
533                                                 // Initialize target/destroy cvalues to allow assignment of delegates from varargs
534                                                 unowned GLibValue arg_value = (GLibValue) arg.target_value;
535                                                 if (arg_value.delegate_target_cvalue == null) {
536                                                         arg_value.delegate_target_cvalue = new CCodeConstant ("NULL");
537                                                 }
538                                                 if (arg_value.delegate_target_destroy_notify_cvalue == null) {
539                                                         arg_value.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
540                                                 }
541                                         }
542
543                                         cexpr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue (arg));
544                                 } else {
545                                         cexpr = handle_struct_argument (null, arg, cexpr);
546                                 }
547                         }
548
549                         if (itype is SignalType && ((SignalType) itype).signal_symbol is DynamicSignal) {
550                                 arg_pos = get_param_pos (i, false);
551                         } else {
552                                 arg_pos = get_param_pos (param != null && !ellipsis ? get_ccode_pos (param) : i, ellipsis);
553                         }
554                         carg_map.set (arg_pos, cexpr);
555
556                         if (m is ArrayResizeMethod && context.profile == Profile.POSIX) {
557                                 var csizeof = new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (((ArrayType) ma.inner.value_type).element_type)));
558                                 carg_map.set (arg_pos, new CCodeBinaryExpression (CCodeBinaryOperator.MUL, csizeof, cexpr));
559                         } else {
560                                 carg_map.set (arg_pos, cexpr);
561                         }
562
563                         if (arg is NamedArgument && ellipsis) {
564                                 var named_arg = (NamedArgument) arg;
565                                 string name = string.joinv ("-", named_arg.name.split ("_"));
566                                 carg_map.set (get_param_pos (i - 0.1, ellipsis), new CCodeConstant ("\"%s\"".printf (name)));
567                         }
568
569                         i++;
570                 }
571                 if (params_it.next ()) {
572                         var param = params_it.get ();
573
574                         /* if there are more parameters than arguments,
575                          * the additional parameter is an ellipsis parameter
576                          * otherwise there is a bug in the semantic analyzer
577                          */
578                         assert (param.params_array || param.ellipsis);
579                         ellipsis = true;
580                 }
581
582                 /* add length argument for methods returning arrays */
583                 if (m != null && m.return_type is ArrayType && async_call != ccall) {
584                         var array_type = (ArrayType) m.return_type;
585                         for (int dim = 1; dim <= array_type.rank; dim++) {
586                                 if (get_ccode_array_null_terminated (m)) {
587                                         // handle calls to methods returning null-terminated arrays
588                                         var temp_var = get_temp_variable (itype.get_return_type (), true, null, false);
589                                         var temp_ref = get_variable_cexpression (temp_var.name);
590
591                                         emit_temp_var (temp_var);
592
593                                         ccall_expr = new CCodeAssignment (temp_ref, ccall_expr);
594
595                                         requires_array_length = true;
596                                         var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
597                                         len_call.add_argument (temp_ref);
598
599                                         append_array_length (expr, len_call);
600                                 } else if (get_ccode_array_length (m)) {
601                                         var length_ctype = get_ccode_array_length_type (m);
602                                         var temp_var = get_temp_variable (new CType (length_ctype, "0"), true, null, true);
603                                         var temp_ref = get_variable_cexpression (temp_var.name);
604
605                                         emit_temp_var (temp_var);
606
607                                         out_arg_map.set (get_param_pos (get_ccode_array_length_pos (m) + 0.01 * dim), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
608
609                                         append_array_length (expr, temp_ref);
610                                 } else if (get_ccode_array_length_expr (m) != null) {
611                                         append_array_length (expr, new CCodeConstant (get_ccode_array_length_expr (m)));
612                                 } else {
613                                         append_array_length (expr, new CCodeConstant ("-1"));
614                                 }
615                         }
616                 } else if (m != null && m.return_type is DelegateType && async_call != ccall) {
617                         var deleg_type = (DelegateType) m.return_type;
618                         if (get_ccode_delegate_target (m) && deleg_type.delegate_symbol.has_target) {
619                                 var temp_var = get_temp_variable (delegate_target_type, true, null, true);
620                                 var temp_ref = get_variable_cexpression (temp_var.name);
621
622                                 emit_temp_var (temp_var);
623
624                                 out_arg_map.set (get_param_pos (get_ccode_delegate_target_pos (m)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
625
626                                 set_delegate_target (expr, temp_ref);
627
628                                 if (deleg_type.is_disposable ()) {
629                                         temp_var = get_temp_variable (delegate_target_destroy_type, true, null, true);
630                                         temp_ref = get_variable_cexpression (temp_var.name);
631
632                                         emit_temp_var (temp_var);
633
634                                         out_arg_map.set (get_param_pos (get_ccode_destroy_notify_pos (m)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
635
636                                         set_delegate_target_destroy_notify (expr, temp_ref);
637                                 } else {
638                                         set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
639                                 }
640                         } else {
641                                 set_delegate_target (expr, new CCodeConstant ("NULL"));
642                                 if (deleg_type.delegate_symbol.has_target) {
643                                         set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
644                                 }
645                         }
646                 }
647
648                 // add length argument for delegates returning arrays
649                 // TODO: avoid code duplication with methods returning arrays, see above
650                 if (deleg != null && deleg.return_type is ArrayType) {
651                         var array_type = (ArrayType) deleg.return_type;
652                         for (int dim = 1; dim <= array_type.rank; dim++) {
653                                 if (get_ccode_array_null_terminated (deleg)) {
654                                         // handle calls to methods returning null-terminated arrays
655                                         var temp_var = get_temp_variable (itype.get_return_type (), true, null, false);
656                                         var temp_ref = get_variable_cexpression (temp_var.name);
657
658                                         emit_temp_var (temp_var);
659
660                                         ccall_expr = new CCodeAssignment (temp_ref, ccall_expr);
661
662                                         requires_array_length = true;
663                                         var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
664                                         len_call.add_argument (temp_ref);
665
666                                         append_array_length (expr, len_call);
667                                 } else if (get_ccode_array_length (deleg)) {
668                                         var length_ctype = get_ccode_array_length_type (deleg);
669                                         var temp_var = get_temp_variable (new CType (length_ctype, "0"), true, null, true);
670                                         var temp_ref = get_variable_cexpression (temp_var.name);
671
672                                         emit_temp_var (temp_var);
673
674                                         out_arg_map.set (get_param_pos (get_ccode_array_length_pos (deleg) + 0.01 * dim), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
675
676                                         append_array_length (expr, temp_ref);
677                                 } else {
678                                         append_array_length (expr, new CCodeConstant ("-1"));
679                                 }
680                         }
681                 } else if (deleg != null && deleg.return_type is DelegateType && get_ccode_delegate_target (deleg)) {
682                         var deleg_type = (DelegateType) deleg.return_type;
683                         if (deleg_type.delegate_symbol.has_target) {
684                                 var temp_var = get_temp_variable (delegate_target_type, true, null, true);
685                                 var temp_ref = get_variable_cexpression (temp_var.name);
686
687                                 emit_temp_var (temp_var);
688
689                                 out_arg_map.set (get_param_pos (get_ccode_delegate_target_pos (deleg)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
690
691                                 set_delegate_target (expr, temp_ref);
692
693                                 if (deleg_type.is_disposable ()) {
694                                         temp_var = get_temp_variable (delegate_target_destroy_type, true, null, true);
695                                         temp_ref = get_variable_cexpression (temp_var.name);
696
697                                         emit_temp_var (temp_var);
698
699                                         out_arg_map.set (get_param_pos (get_ccode_destroy_notify_pos (deleg)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, temp_ref));
700
701                                         set_delegate_target_destroy_notify (expr, temp_ref);
702                                 }
703                         }
704                 }
705
706                 if (m != null && m.coroutine) {
707                         if (expr.is_yield_expression) {
708                                 // asynchronous call
709                                 in_arg_map.set (get_param_pos (-1), new CCodeIdentifier (generate_ready_function (current_method)));
710                                 in_arg_map.set (get_param_pos (-0.9), new CCodeIdentifier ("_data_"));
711                         }
712                 }
713
714                 if (expr.tree_can_fail) {
715                         // method can fail
716                         current_method_inner_error = true;
717                         // add &inner_error before the ellipsis arguments
718                         out_arg_map.set (get_param_pos (get_ccode_error_pos ((Callable) m ?? deleg)), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_inner_error_cexpression ()));
719                 } else if (m != null && m.has_error_type_parameter () && async_call != ccall) {
720                         // inferred error argument from base method
721                         out_arg_map.set (get_param_pos (get_ccode_error_pos (m)), new CCodeConstant ("NULL"));
722                 }
723
724                 if (ellipsis) {
725                         /* ensure variable argument list ends with NULL
726                          * except when using printf-style arguments */
727                         if (itype is SignalType) {
728                                 // g_signal_emit*() does not require more
729                         } else if (m == null) {
730                                 in_arg_map.set (get_param_pos (-1, true), new CCodeConstant ("NULL"));
731                         } else if (!m.printf_format && !m.scanf_format && get_ccode_sentinel (m) != "" && !expr.is_constructv_chainup) {
732                                 in_arg_map.set (get_param_pos (-1, true), new CCodeConstant (get_ccode_sentinel (m)));
733                         }
734                 }
735
736                 if (deleg != null && deleg.has_target) {
737                         CCodeExpression delegate_target_destroy_notify;
738                         in_arg_map.set (get_param_pos (get_ccode_instance_pos (deleg)), get_delegate_target_cexpression (expr.call, out delegate_target_destroy_notify));
739                         out_arg_map.set (get_param_pos (get_ccode_instance_pos (deleg)), get_delegate_target_cexpression (expr.call, out delegate_target_destroy_notify));
740                 }
741
742                 // structs are returned via out parameter
743                 bool return_result_via_out_param = itype.get_return_type ().is_real_non_null_struct_type ();
744
745                 // pass address for the return value of non-void signals without emitter functions
746                 if (itype is SignalType && !(itype.get_return_type () is VoidType)) {
747                         var sig = ((SignalType) itype).signal_symbol;
748
749                         if (ma != null && ma.inner is BaseAccess && sig.is_virtual) {
750                                 // normal return value for base access
751                         } else if (!get_ccode_has_emitter (sig) || ma.source_reference.file == sig.source_reference.file) {
752                                 return_result_via_out_param = true;
753                         }
754                 }
755
756                 if (async_call == ccall) {
757                         // skip out parameter for .begin() calls
758                         return_result_via_out_param = false;
759                 }
760
761                 CCodeExpression out_param_ref = null;
762
763                 if (return_result_via_out_param) {
764                         var out_param_var = get_temp_variable (itype.get_return_type (), true, null, true);
765                         out_param_ref = get_variable_cexpression (out_param_var.name);
766                         emit_temp_var (out_param_var);
767                         out_arg_map.set (get_param_pos (-3), new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, out_param_ref));
768                 }
769
770                 // append C arguments in the right order
771
772                 int last_pos;
773                 int min_pos;
774
775                 if (async_call != ccall) {
776                         // don't append out arguments for .begin() calls
777                         last_pos = -1;
778                         while (true) {
779                                 min_pos = -1;
780                                 foreach (int pos in out_arg_map.get_keys ()) {
781                                         if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
782                                                 min_pos = pos;
783                                         }
784                                 }
785                                 if (min_pos == -1) {
786                                         break;
787                                 }
788                                 ccall.add_argument (out_arg_map.get (min_pos));
789                                 last_pos = min_pos;
790                         }
791                 }
792
793                 if (async_call != null) {
794                         last_pos = -1;
795                         while (true) {
796                                 min_pos = -1;
797                                 foreach (int pos in in_arg_map.get_keys ()) {
798                                         if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
799                                                 min_pos = pos;
800                                         }
801                                 }
802                                 if (min_pos == -1) {
803                                         break;
804                                 }
805                                 async_call.add_argument (in_arg_map.get (min_pos));
806                                 last_pos = min_pos;
807                         }
808                 }
809
810                 if (expr.is_yield_expression) {
811                         // set state before calling async function to support immediate callbacks
812                         int state = emit_context.next_coroutine_state++;
813
814                         ccode.add_assignment (get_variable_cexpression ("_state_"), new CCodeConstant (state.to_string ()));
815                         ccode.add_expression (async_call);
816                         ccode.add_return (new CCodeConstant ("FALSE"));
817                         ccode.add_label ("_state_%d".printf (state));
818                 }
819
820                 if (expr.is_assert) {
821                         string message = ((string) expr.source_reference.begin.pos).substring (0, (int) (expr.source_reference.end.pos - expr.source_reference.begin.pos));
822                         ccall.call = new CCodeIdentifier ("_vala_assert");
823                         ccall.add_argument (new CCodeConstant ("\"%s\"".printf (message.replace ("\n", " ").escape (""))));
824                         requires_assert = true;
825
826                 }
827
828                 // Transform and add free function argument to GLib.[List,Queue,SList].remove[_all] calls
829                 unowned DataType? collection_type = null;
830                 if (ma != null && ma.inner != null) {
831                         collection_type = ma.inner.value_type;
832                 }
833                 if (collection_type != null
834                     && (collection_type.type_symbol == glist_type || collection_type.type_symbol == gslist_type || collection_type.type_symbol == gqueue_type)
835                     && (ma.member_name == "remove" || ma.member_name == "remove_all")
836                     //FIXME Perform stricter type argument check earlier
837                     && collection_type.check_type_arguments (context)) {
838                         var remove_method = (Method) collection_type.type_symbol.scope.lookup (ma.member_name + "_full");
839                         var type_arg = collection_type.get_type_arguments ()[0];
840                         if (remove_method != null && requires_destroy (type_arg)) {
841                                 // only add them once per source file
842                                 if (add_generated_external_symbol (remove_method)) {
843                                         visit_method (remove_method);
844                                 }
845                                 ccall.call = new CCodeIdentifier (get_ccode_name (remove_method));
846                                 ccall.add_argument (get_destroy0_func_expression (type_arg));
847                         }
848                 }
849
850                 if (return_result_via_out_param) {
851                         ccode.add_expression (ccall_expr);
852                         ccall_expr = out_param_ref;
853                 }
854
855                 if (m != null && m.binding == MemberBinding.INSTANCE && m.returns_modified_pointer) {
856                         if (ma != null && ma.inner.symbol_reference is Property && ma.inner is MemberAccess) {
857                                 var prop = (Property) ma.inner.symbol_reference;
858                                 store_property (prop, ((MemberAccess) ma.inner).inner, new GLibValue (expr.value_type, ccall_expr));
859                                 ccall_expr = null;
860                         } else {
861                                 ccall_expr = new CCodeAssignment (instance, ccall_expr);
862                         }
863                 }
864
865                 // real structs are passed by reference for simple generics
866                 if (m != null && get_ccode_simple_generics (m) && m.return_type is GenericType
867                     && expr.value_type.is_real_struct_type () && !expr.value_type.nullable && !(expr.value_type is PointerType)) {
868                     ccall_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeParenthesizedExpression (ccall_expr));
869                 }
870
871                 if (m != null && get_ccode_type (m) != null && get_ccode_type (m) != get_ccode_name (m.return_type)) {
872                         // Bug 699956: Implement cast for method return type if [CCode type=] annotation is specified
873                         ccall_expr = new CCodeCastExpression (ccall_expr, get_ccode_name (m.return_type));
874                 }
875
876                 if (m is ArrayResizeMethod) {
877                         // FIXME: size expression must not be evaluated twice at runtime (potential side effects)
878                         Iterator<Expression> arg_it = expr.get_argument_list ().iterator ();
879                         arg_it.next ();
880                         var new_size = get_cvalue (arg_it.get ());
881
882                         var array_type = (ArrayType) ma.inner.value_type;
883                         var temp_decl = get_temp_variable (array_type.length_type);
884                         var temp_ref = get_variable_cexpression (temp_decl.name);
885
886                         emit_temp_var (temp_decl);
887
888                         /* memset needs string.h */
889                         cfile.add_include ("string.h");
890
891                         var clen = get_array_length_cexpression (ma.inner, 1);
892                         var celems = get_cvalue (ma.inner);
893                         var csizeof = new CCodeIdentifier ("sizeof (%s)".printf (get_ccode_name (array_type.element_type)));
894                         var cdelta = new CCodeBinaryExpression (CCodeBinaryOperator.MINUS, temp_ref, clen);
895                         var ccheck = new CCodeBinaryExpression (CCodeBinaryOperator.GREATER_THAN, temp_ref, clen);
896
897                         var czero = new CCodeFunctionCall (new CCodeIdentifier ("memset"));
898                         czero.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, celems, clen));
899                         czero.add_argument (new CCodeConstant ("0"));
900                         czero.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, csizeof, cdelta));
901
902                         ccode.add_assignment (temp_ref, new_size);
903                         ccode.add_expression (ccall_expr);
904                         ccode.add_expression (new CCodeConditionalExpression (ccheck, czero, new CCodeConstant ("NULL")));
905                         ccode.add_assignment (get_array_length_cexpression (ma.inner, 1), temp_ref);
906
907                         var array_var = ma.inner.symbol_reference;
908                         if (array_var != null && array_var.is_internal_symbol ()
909                             && (array_var is LocalVariable || array_var is Field)) {
910                                 ccode.add_assignment (get_array_size_cvalue (ma.inner.target_value), temp_ref);
911                         }
912
913                         return;
914                 }
915
916                 if (expr.parent_node is ExpressionStatement && !expr.value_type.is_disposable ()) {
917                         if (ccall_expr != null && !return_result_via_out_param) {
918                                 ccode.add_expression (ccall_expr);
919                         }
920                 } else {
921                         var result_type = itype.get_return_type ();
922
923                         if (expr.formal_value_type is GenericType && !(expr.value_type is GenericType)) {
924                                 var type_parameter = ((GenericType) expr.formal_value_type).type_parameter;
925                                 var st = type_parameter.parent_symbol.parent_symbol as Struct;
926                                 if (type_parameter.parent_symbol == garray_type ||
927                                     (st != null && get_ccode_name (st) == "va_list")) {
928                                         // GArray and va_list don't use pointer-based generics
929                                         // above logic copied from visit_expression ()
930                                         // TODO avoid code duplication
931                                         result_type = expr.value_type;
932                                 }
933                                 if (st != null && get_ccode_name (st) == "va_list" && ma.member_name == "arg") {
934                                         if (result_type is DelegateType && ((DelegateType) result_type).delegate_symbol.has_target) {
935                                                 set_cvalue (expr, null);
936                                                 // Initialize target/destroy cvalues to allow assignment of delegates from varargs
937                                                 unowned GLibValue arg_value = (GLibValue) expr.target_value;
938                                                 if (arg_value.delegate_target_cvalue == null) {
939                                                         arg_value.delegate_target_cvalue = new CCodeConstant ("NULL");
940                                                 }
941                                                 if (arg_value.delegate_target_destroy_notify_cvalue == null) {
942                                                         arg_value.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
943                                                 }
944                                         }
945                                 }
946                         }
947
948                         if (m != null && m.get_format_arg_index () >= 0) {
949                                 set_cvalue (expr, ccall_expr);
950                         } else if (m != null && m.get_attribute_bool ("CCode", "use_inplace", false)) {
951                                 set_cvalue (expr, ccall_expr);
952                         } else if (!return_result_via_out_param
953                             && !has_ref_out_argument (expr)
954                             && (result_type is ValueType && !result_type.is_disposable ())) {
955                                 set_cvalue (expr, ccall_expr);
956                         } else if (!return_result_via_out_param) {
957                                 var temp_var = get_temp_variable (result_type, result_type.value_owned, null, false);
958                                 var temp_ref = get_variable_cexpression (temp_var.name);
959
960                                 emit_temp_var (temp_var);
961
962                                 ccode.add_assignment (temp_ref, ccall_expr);
963                                 set_cvalue (expr, temp_ref);
964                                 ((GLibValue) expr.target_value).lvalue = true;
965                         } else {
966                                 set_cvalue (expr, ccall_expr);
967                                 ((GLibValue) expr.target_value).lvalue = true;
968                         }
969                 }
970
971                 params_it = params.iterator ();
972                 foreach (Expression arg in expr.get_argument_list ()) {
973                         Parameter param = null;
974
975                         if (params_it.next ()) {
976                                 param = params_it.get ();
977                         }
978
979                         var unary = arg as UnaryExpression;
980
981                         // update possible stale _*_size_ variable
982                         if (unary != null && unary.operator == UnaryOperator.REF) {
983                                 if (param != null && get_ccode_array_length (param) && param.variable_type is ArrayType
984                                     && !((ArrayType) param.variable_type).fixed_length && ((ArrayType) param.variable_type).rank == 1) {
985                                         unowned Variable? array_var = unary.inner.symbol_reference as Variable;
986                                         if ((array_var is LocalVariable || array_var is Field) && array_var.is_internal_symbol ()
987                                             && array_var.variable_type is ArrayType && !((ArrayType) array_var.variable_type).fixed_length) {
988                                                 ccode.add_assignment (get_array_size_cvalue (unary.inner.target_value), get_array_length_cvalue (unary.inner.target_value, 1));
989                                         }
990                                 }
991                         }
992
993                         if (unary == null || unary.operator != UnaryOperator.OUT) {
994                                 continue;
995                         }
996
997                         if (requires_destroy (unary.inner.value_type)) {
998                                 // unref old value
999                                 ccode.add_expression (destroy_value (unary.inner.target_value));
1000                         }
1001
1002                         // infer type of out-parameter from argument
1003                         if (ma.symbol_reference is DynamicMethod && unary.target_value.value_type == null) {
1004                                 unary.target_value.value_type = unary.inner.value_type.copy ();
1005                         }
1006
1007                         // assign new value
1008                         store_value (unary.inner.target_value, transform_value (unary.target_value, unary.inner.value_type, arg), expr.source_reference);
1009
1010                         // handle out null terminated arrays
1011                         if (param != null && get_ccode_array_null_terminated (param)) {
1012                                 requires_array_length = true;
1013                                 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
1014                                 len_call.add_argument (get_cvalue_ (unary.inner.target_value));
1015
1016                                 ccode.add_assignment (get_array_length_cvalue (unary.inner.target_value, 1), len_call);
1017                         }
1018                 }
1019
1020                 if (m is CreationMethod && m.parent_symbol is Class && ((current_class.is_compact && current_class.base_class != null) || current_class.is_subtype_of (gsource_type))) {
1021                         var cinitcall = new CCodeFunctionCall (new CCodeIdentifier ("%s_instance_init".printf (get_ccode_lower_case_name (current_class, null))));
1022                         cinitcall.add_argument (get_this_cexpression ());
1023                         if (!current_class.is_compact) {
1024                                 cinitcall.add_argument (new CCodeConstant ("NULL"));
1025                         }
1026                         ccode.add_expression (cinitcall);
1027                 }
1028         }
1029
1030         private string generate_enum_to_string_function (Enum en) {
1031                 var to_string_func = "_%s_to_string".printf (get_ccode_lower_case_name (en));
1032
1033                 if (!add_wrapper (to_string_func)) {
1034                         // wrapper already defined
1035                         return to_string_func;
1036                 }
1037                 // declaration
1038
1039                 var function = new CCodeFunction (to_string_func, "const char*");
1040                 function.modifiers = CCodeModifiers.STATIC;
1041
1042                 function.add_parameter (new CCodeParameter ("value", get_ccode_name (en)));
1043
1044                 // definition
1045                 push_context (new EmitContext ());
1046                 push_function (function);
1047
1048                 ccode.open_switch (new CCodeConstant ("value"));
1049                 foreach (var enum_value in en.get_values ()) {
1050                         ccode.add_case (new CCodeIdentifier (get_ccode_name (enum_value)));
1051                         ccode.add_return (new CCodeConstant ("\""+get_ccode_name (enum_value)+"\""));
1052                 }
1053                 ccode.close ();
1054                 ccode.add_return (new CCodeConstant ("NULL"));
1055
1056                 // append to file
1057                 cfile.add_function_declaration (function);
1058                 cfile.add_function (function);
1059
1060                 pop_context ();
1061
1062                 return to_string_func;
1063         }
1064
1065         bool has_ref_out_argument (MethodCall c) {
1066                 foreach (var arg in c.get_argument_list ()) {
1067                         unowned UnaryExpression? unary = arg as UnaryExpression;
1068                         if (unary != null && (unary.operator == UnaryOperator.OUT || unary.operator == UnaryOperator.REF)) {
1069                                 return true;
1070                         }
1071                 }
1072                 return false;
1073         }
1074
1075         string generate_string_printf_function () {
1076                 if (!add_wrapper ("string_printf")) {
1077                         // wrapper already defined
1078                         return "string_printf";
1079                 }
1080
1081                 // declaration
1082                 var function = new CCodeFunction ("string_printf", "char*");
1083                 function.add_parameter (new CCodeParameter ("format", "const char*"));
1084                 function.add_parameter (new CCodeParameter.with_ellipsis ());
1085                 function.modifiers = CCodeModifiers.STATIC | CCodeModifiers.PRINTF;
1086
1087                 // definition
1088                 push_context (new EmitContext ());
1089                 push_function (function);
1090
1091                 ccode.add_declaration ("int", new CCodeVariableDeclarator ("length"));
1092                 ccode.add_declaration ("va_list", new CCodeVariableDeclarator ("ap"));
1093                 ccode.add_declaration ("char*", new CCodeVariableDeclarator ("result"));
1094
1095                 var vastart = new CCodeFunctionCall (new CCodeIdentifier ("va_start"));
1096                 vastart.add_argument (new CCodeIdentifier ("ap"));
1097                 vastart.add_argument (new CCodeIdentifier ("format"));
1098
1099                 ccode.add_expression (vastart);
1100
1101                 if (context.profile == Profile.POSIX) {
1102                         cfile.add_include ("stdio.h");
1103                 }
1104
1105                 var vsnprintf = new CCodeFunctionCall (new CCodeIdentifier ("vsnprintf"));
1106                 vsnprintf.add_argument (new CCodeConstant ("NULL"));
1107                 vsnprintf.add_argument (new CCodeConstant ("0"));
1108                 vsnprintf.add_argument (new CCodeIdentifier ("format"));
1109                 vsnprintf.add_argument (new CCodeIdentifier ("ap"));
1110
1111                 ccode.add_assignment (new CCodeIdentifier ("length"), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, vsnprintf, new CCodeConstant ("1")));
1112
1113                 var va_end = new CCodeFunctionCall (new CCodeIdentifier ("va_end"));
1114                 va_end.add_argument (new CCodeIdentifier ("ap"));
1115
1116                 ccode.add_expression (va_end);
1117
1118                 var malloc = new CCodeFunctionCall (new CCodeIdentifier ("malloc"));
1119                 malloc.add_argument (new CCodeIdentifier ("length"));
1120
1121                 ccode.add_assignment (new CCodeIdentifier ("result"), malloc);
1122
1123                 vastart = new CCodeFunctionCall (new CCodeIdentifier ("va_start"));
1124                 vastart.add_argument (new CCodeIdentifier ("ap"));
1125                 vastart.add_argument (new CCodeIdentifier ("format"));
1126
1127                 ccode.add_expression (vastart);
1128
1129                 vsnprintf = new CCodeFunctionCall (new CCodeIdentifier ("vsnprintf"));
1130                 vsnprintf.add_argument (new CCodeIdentifier ("result"));
1131                 vsnprintf.add_argument (new CCodeIdentifier ("length"));
1132                 vsnprintf.add_argument (new CCodeIdentifier ("format"));
1133                 vsnprintf.add_argument (new CCodeIdentifier ("ap"));
1134
1135                 ccode.add_expression (vsnprintf);
1136
1137                 va_end = new CCodeFunctionCall (new CCodeIdentifier ("va_end"));
1138                 va_end.add_argument (new CCodeIdentifier ("ap"));
1139
1140                 ccode.add_expression (va_end);
1141
1142                 ccode.add_return (new CCodeIdentifier ("result"));
1143
1144                 // append to file
1145                 cfile.add_include ("stdarg.h");
1146                 cfile.add_function_declaration (function);
1147                 cfile.add_function (function);
1148
1149                 pop_context ();
1150
1151                 return "string_printf";
1152         }
1153 }
1154