tests: Add "while (false)" test to increase coverage
[vala-gnome.git] / codegen / valaccodememberaccessmodule.vala
blob3efcc34455e446977bcff39193e6c49a1a265f7d
1 /* valaccodememberaccessmodule.vala
3 * Copyright (C) 2006-2010 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
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.
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.
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
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 public abstract class Vala.CCodeMemberAccessModule : CCodeControlFlowModule {
26 public override void visit_member_access (MemberAccess expr) {
27 CCodeExpression pub_inst = null;
29 if (expr.inner != null) {
30 pub_inst = get_cvalue (expr.inner);
33 var array_type = expr.value_type as ArrayType;
34 var delegate_type = expr.value_type as DelegateType;
36 if (expr.symbol_reference is Method) {
37 var m = (Method) expr.symbol_reference;
39 if (!(m is DynamicMethod || m is ArrayMoveMethod || m is ArrayResizeMethod || m is ArrayCopyMethod)) {
40 generate_method_declaration (m, cfile);
42 if (!m.external && m.external_package) {
43 // internal VAPI methods
44 // only add them once per source file
45 if (add_generated_external_symbol (m)) {
46 visit_method (m);
51 if (expr.inner is BaseAccess) {
52 if (m.base_method != null) {
53 var base_class = (Class) m.base_method.parent_symbol;
54 var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (get_ccode_upper_case_name (base_class, null))));
55 vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class, null))));
57 set_cvalue (expr, new CCodeMemberAccess.pointer (vcast, get_ccode_vfunc_name (m)));
58 return;
59 } else if (m.base_interface_method != null) {
60 var base_iface = (Interface) m.base_interface_method.parent_symbol;
61 string parent_iface_var = "%s_%s_parent_iface".printf (get_ccode_lower_case_name (current_class), get_ccode_lower_case_name (base_iface));
63 set_cvalue (expr, new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), get_ccode_vfunc_name (m)));
64 return;
68 if (m.base_method != null) {
69 if (!method_has_wrapper (m.base_method)) {
70 var base_class = (Class) m.base_method.parent_symbol;
71 var vclass = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (get_ccode_upper_case_name (base_class))));
72 vclass.add_argument (pub_inst);
73 set_cvalue (expr, new CCodeMemberAccess.pointer (vclass, get_ccode_vfunc_name (m)));
74 } else {
75 set_cvalue (expr, new CCodeIdentifier (get_ccode_name (m.base_method)));
77 } else if (m.base_interface_method != null) {
78 set_cvalue (expr, new CCodeIdentifier (get_ccode_name (m.base_interface_method)));
79 } else if (m is CreationMethod) {
80 set_cvalue (expr, new CCodeIdentifier (get_ccode_real_name (m)));
81 } else {
82 set_cvalue (expr, new CCodeIdentifier (get_ccode_name (m)));
85 set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
86 if (m.binding == MemberBinding.STATIC) {
87 set_delegate_target (expr, new CCodeConstant ("NULL"));
88 } else if (m.is_async_callback) {
89 if (current_method.closure) {
90 var block = ((Method) m.parent_symbol).body;
91 set_delegate_target (expr, new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), "_async_data_"));
92 } else {
93 set_delegate_target (expr, new CCodeIdentifier ("_data_"));
95 } else if (expr.inner != null && !expr.prototype_access) {
96 // expr.inner is null in the special case of referencing the method in a constant initializer
97 var delegate_target = (CCodeExpression) get_ccodenode (expr.inner);
98 delegate_type = expr.target_type as DelegateType;
99 if ((expr.value_type.value_owned || (delegate_type != null && delegate_type.is_called_once)) && expr.inner.value_type.data_type != null && is_reference_counting (expr.inner.value_type.data_type)) {
100 var ref_call = new CCodeFunctionCall (get_dup_func_expression (expr.inner.value_type, expr.source_reference));
101 ref_call.add_argument (delegate_target);
102 delegate_target = ref_call;
103 set_delegate_target_destroy_notify (expr, get_destroy_func_expression (expr.inner.value_type));
105 set_delegate_target (expr, delegate_target);
107 } else if (expr.symbol_reference is ArrayLengthField) {
108 if (expr.value_type is ArrayType && !(expr.parent_node is ElementAccess)) {
109 Report.error (expr.source_reference, "unsupported use of length field of multi-dimensional array");
111 set_cvalue (expr, get_array_length_cexpression (expr.inner, 1));
112 } else if (expr.symbol_reference is Field) {
113 var field = (Field) expr.symbol_reference;
114 if (expr.lvalue) {
115 expr.target_value = get_field_cvalue (field, expr.inner != null ? expr.inner.target_value : null);
116 } else {
117 expr.target_value = load_field (field, expr.inner != null ? expr.inner.target_value : null);
119 } else if (expr.symbol_reference is EnumValue) {
120 var ev = (EnumValue) expr.symbol_reference;
122 generate_enum_declaration ((Enum) ev.parent_symbol, cfile);
124 set_cvalue (expr, new CCodeConstant (get_ccode_name (ev)));
125 } else if (expr.symbol_reference is Constant) {
126 var c = (Constant) expr.symbol_reference;
128 generate_constant_declaration (c, cfile,
129 c.source_reference != null && expr.source_reference != null &&
130 c.source_reference.file == expr.source_reference.file);
132 string fn = c.get_full_name ();
133 if (fn == "GLib.Log.FILE") {
134 string s = Path.get_basename (expr.source_reference.file.filename);
135 set_cvalue (expr, new CCodeConstant ("\"%s\"".printf (s)));
136 } else if (fn == "GLib.Log.LINE") {
137 int i = expr.source_reference.begin.line;
138 set_cvalue (expr, new CCodeConstant ("%d".printf (i)));
139 } else if (fn == "GLib.Log.METHOD") {
140 string s = "";
141 if (current_method != null) {
142 s = current_method.get_full_name ();
144 set_cvalue (expr, new CCodeConstant ("\"%s\"".printf (s)));
145 } else {
146 set_cvalue (expr, new CCodeIdentifier (get_ccode_name (c)));
149 if (array_type != null) {
150 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_N_ELEMENTS"));
151 ccall.add_argument (new CCodeIdentifier (get_ccode_name (c)));
152 append_array_length (expr, ccall);
154 } else if (expr.symbol_reference is Property) {
155 var prop = (Property) expr.symbol_reference;
157 if (!(prop is DynamicProperty)) {
158 generate_property_accessor_declaration (prop.get_accessor, cfile);
160 if (!prop.external && prop.external_package) {
161 // internal VAPI properties
162 // only add them once per source file
163 if (add_generated_external_symbol (prop)) {
164 visit_property (prop);
169 if (expr.inner is BaseAccess) {
170 var base_prop = prop;
171 if (prop.base_property != null) {
172 base_prop = prop.base_property;
173 } else if (prop.base_interface_property != null) {
174 base_prop = prop.base_interface_property;
176 if (base_prop.parent_symbol is Class) {
177 var base_class = (Class) base_prop.parent_symbol;
178 var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (get_ccode_upper_case_name (base_class, null))));
179 vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class, null))));
181 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "get_%s".printf (prop.name)));
182 ccall.add_argument (get_cvalue (expr.inner));
183 if (prop.property_type.is_real_non_null_struct_type ()) {
184 var temp_value = (GLibValue) create_temp_value (prop.get_accessor.value_type, false, expr);
185 expr.target_value = load_temp_value (temp_value);
186 var ctemp = get_cvalue_ (temp_value);
187 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
188 ccode.add_expression (ccall);
189 } else {
190 set_cvalue (expr, ccall);
192 } else if (base_prop.parent_symbol is Interface) {
193 var base_iface = (Interface) base_prop.parent_symbol;
194 string parent_iface_var = "%s_%s_parent_iface".printf (get_ccode_lower_case_name (current_class), get_ccode_lower_case_name (base_iface));
196 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), "get_%s".printf (prop.name)));
197 ccall.add_argument (get_cvalue (expr.inner));
198 if (prop.property_type.is_real_non_null_struct_type ()) {
199 var temp_value = (GLibValue) create_temp_value (prop.get_accessor.value_type, false, expr);
200 expr.target_value = load_temp_value (temp_value);
201 var ctemp = get_cvalue_ (temp_value);
202 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
203 ccode.add_expression (ccall);
204 } else {
205 set_cvalue (expr, ccall);
208 } else if (prop.binding == MemberBinding.INSTANCE &&
209 prop.get_accessor.automatic_body &&
210 !prop.get_accessor.value_type.value_owned &&
211 current_type_symbol == prop.parent_symbol &&
212 current_type_symbol is Class &&
213 prop.base_property == null &&
214 prop.base_interface_property == null &&
215 !(prop.property_type is ArrayType || prop.property_type is DelegateType)) {
216 CCodeExpression inst;
217 inst = new CCodeMemberAccess.pointer (pub_inst, "priv");
218 set_cvalue (expr, new CCodeMemberAccess.pointer (inst, get_ccode_name (prop.field)));
219 } else if (!get_ccode_no_accessor_method (prop)) {
220 string getter_cname;
221 if (prop is DynamicProperty) {
222 getter_cname = get_dynamic_property_getter_cname ((DynamicProperty) prop);
223 } else {
224 getter_cname = get_ccode_name (prop.get_accessor);
226 var ccall = new CCodeFunctionCall (new CCodeIdentifier (getter_cname));
228 if (prop.binding == MemberBinding.INSTANCE) {
229 if (prop.parent_symbol is Struct && !((Struct) prop.parent_symbol).is_simple_type ()) {
230 // we need to pass struct instance by reference
231 var instance = expr.inner.target_value;
232 if (!get_lvalue (instance)) {
233 instance = store_temp_value (instance, expr);
235 pub_inst = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (instance));
238 ccall.add_argument (pub_inst);
241 bool prop_is_real_non_null_struct_type = prop.property_type.is_real_non_null_struct_type ();
242 var temp_value = (GLibValue) create_temp_value (prop.get_accessor.value_type, prop_is_real_non_null_struct_type, expr);
243 expr.target_value = load_temp_value (temp_value);
244 var ctemp = get_cvalue_ (temp_value);
246 // Property access to real struct types is handled differently
247 // The value is returned by out parameter
248 if (prop_is_real_non_null_struct_type) {
249 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
250 ccode.add_expression (ccall);
251 } else {
252 ccode.add_assignment (ctemp, ccall);
254 array_type = prop.property_type as ArrayType;
255 if (array_type != null) {
256 if (get_ccode_array_null_terminated (prop)) {
257 requires_array_length = true;
258 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
259 len_call.add_argument (ctemp);
261 ccode.add_assignment (temp_value.array_length_cvalues[0], len_call);
262 } else if (get_ccode_array_length (prop)) {
263 for (int dim = 1; dim <= array_type.rank; dim++) {
264 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_length_cvalue (temp_value, dim)));
267 } else {
268 delegate_type = prop.property_type as DelegateType;
269 if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
270 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_delegate_target_cvalue (temp_value)));
274 } else {
275 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
276 ccall.add_argument (pub_inst);
278 // property name is second argument of g_object_get
279 ccall.add_argument (get_property_canonical_cconstant (prop));
281 // g_object_get always returns owned values
282 // therefore, property getters of properties
283 // without accessor methods need to be marked as owned
284 if (!prop.get_accessor.value_type.value_owned) {
285 // only report error for types where there actually
286 // is a difference between `owned' and `unowned'
287 var owned_value_type = prop.get_accessor.value_type.copy ();
288 owned_value_type.value_owned = true;
289 if (requires_copy (owned_value_type)) {
290 Report.error (prop.get_accessor.source_reference, "unowned return value for getter of property `%s' not supported without accessor".printf (prop.get_full_name ()));
294 if (expr.value_type.is_real_struct_type ()) {
295 // gobject allocates structs on heap
296 expr.value_type.nullable = true;
299 var temp_var = get_temp_variable (expr.value_type);
300 var ctemp = get_variable_cexpression (temp_var.name);
301 emit_temp_var (temp_var);
302 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
303 ccall.add_argument (new CCodeConstant ("NULL"));
304 ccode.add_expression (ccall);
305 set_cvalue (expr, ctemp);
307 expr.target_value.value_type = expr.value_type;
308 expr.target_value = store_temp_value (expr.target_value, expr);
309 } else if (expr.symbol_reference is LocalVariable) {
310 var local = (LocalVariable) expr.symbol_reference;
312 if (expr.parent_node is ReturnStatement &&
313 current_return_type.value_owned &&
314 local.variable_type.value_owned &&
315 !local.captured &&
316 !variable_accessible_in_finally (local) &&
317 !(local.variable_type is ArrayType && ((ArrayType) local.variable_type).inline_allocated)) {
318 /* return expression is local variable taking ownership and
319 * current method is transferring ownership */
321 // don't ref expression
322 expr.value_type.value_owned = true;
324 // don't unref variable
325 local.active = false;
327 var glib_value = (GLibValue) get_local_cvalue (local);
328 expr.target_value = glib_value;
329 if (glib_value.delegate_target_cvalue == null) {
330 glib_value.delegate_target_cvalue = new CCodeConstant ("NULL");
332 if (glib_value.delegate_target_destroy_notify_cvalue == null) {
333 glib_value.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
335 } else {
336 if (expr.lvalue) {
337 expr.target_value = get_local_cvalue (local);
338 } else {
339 expr.target_value = load_local (local);
342 } else if (expr.symbol_reference is Parameter) {
343 var param = (Parameter) expr.symbol_reference;
344 if (expr.lvalue) {
345 expr.target_value = get_parameter_cvalue (param);
346 } else {
347 expr.target_value = load_parameter (param);
352 /* Returns lvalue access to the given local variable */
353 public override TargetValue get_local_cvalue (LocalVariable local) {
354 var result = new GLibValue (local.variable_type.copy ());
355 result.lvalue = true;
357 var array_type = local.variable_type as ArrayType;
358 var delegate_type = local.variable_type as DelegateType;
359 if (local.is_result) {
360 // used in postconditions
361 // structs are returned as out parameter
362 if (local.variable_type != null && local.variable_type.is_real_non_null_struct_type ()) {
363 result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result"));
364 } else {
365 result.cvalue = new CCodeIdentifier ("result");
367 if (array_type != null && !array_type.fixed_length && ((current_method != null && get_ccode_array_length (current_method)) || current_property_accessor != null)) {
368 for (int dim = 1; dim <= array_type.rank; dim++) {
369 result.append_array_length_cvalue (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (get_array_length_cname ("result", dim))));
372 } else if (local.captured) {
373 // captured variables are stored on the heap
374 var block = (Block) local.parent_symbol;
375 result.cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_local_cname (local));
376 if (array_type != null && !array_type.fixed_length) {
377 for (int dim = 1; dim <= array_type.rank; dim++) {
378 result.append_array_length_cvalue (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_array_length_cname (get_local_cname (local), dim)));
380 if (array_type.rank == 1) {
381 result.array_size_cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_array_size_cname (get_local_cname (local)));
383 } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
384 result.delegate_target_cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_delegate_target_cname (get_local_cname (local)));
385 if (delegate_type.is_disposable ()) {
386 result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_delegate_target_destroy_notify_cname (get_local_cname (local)));
389 } else {
390 result.cvalue = get_local_cexpression (local);
391 if (array_type != null && !array_type.fixed_length) {
392 for (int dim = 1; dim <= array_type.rank; dim++) {
393 result.append_array_length_cvalue (get_variable_cexpression (get_array_length_cname (get_local_cname (local), dim)));
395 if (array_type.rank == 1) {
396 result.array_size_cvalue = get_variable_cexpression (get_array_size_cname (get_local_cname (local)));
398 } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
399 if (is_in_coroutine ()) {
400 result.delegate_target_cvalue = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), get_delegate_target_cname (get_local_cname (local)));
401 if (local.variable_type.value_owned) {
402 result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), get_delegate_target_destroy_notify_cname (get_local_cname (local)));
404 } else {
405 result.delegate_target_cvalue = new CCodeIdentifier (get_delegate_target_cname (get_local_cname (local)));
406 if (local.variable_type.value_owned) {
407 result.delegate_target_destroy_notify_cvalue = new CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_local_cname (local)));
413 return result;
416 /* Returns access values to the given parameter */
417 public override TargetValue get_parameter_cvalue (Parameter param) {
418 var result = new GLibValue (param.variable_type.copy ());
419 result.lvalue = true;
420 result.array_null_terminated = get_ccode_array_null_terminated (param);
421 if (get_ccode_array_length_expr (param) != null) {
422 result.array_length_cexpr = new CCodeConstant (get_ccode_array_length_expr (param));
424 result.ctype = get_ccode_type (param);
426 var array_type = result.value_type as ArrayType;
427 var delegate_type = result.value_type as DelegateType;
429 bool is_unowned_delegate = delegate_type != null && !param.variable_type.value_owned;
430 if ((param.captured || is_in_coroutine ()) && !is_unowned_delegate) {
431 result.value_type.value_owned = true;
434 if (param.name == "this") {
435 if (is_in_coroutine ()) {
436 // use closure
437 result.cvalue = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "self");
438 } else {
439 var st = result.value_type.data_type as Struct;
440 if (st != null && !st.is_simple_type ()) {
441 result.cvalue = new CCodeIdentifier ("(*self)");
442 } else {
443 result.cvalue = new CCodeIdentifier ("self");
446 } else {
447 string name = param.name;
449 if (param.captured) {
450 // captured variables are stored on the heap
451 var block = param.parent_symbol as Block;
452 if (block == null) {
453 block = ((Method) param.parent_symbol).body;
455 result.cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_variable_cname (param.name));
456 if (array_type != null && get_ccode_array_length (param)) {
457 for (int dim = 1; dim <= array_type.rank; dim++) {
458 result.append_array_length_cvalue (new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_parameter_array_length_cname (param, dim)));
460 } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
461 result.delegate_target_cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_ccode_delegate_target_name (param));
462 if (result.value_type.is_disposable ()) {
463 result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_delegate_target_destroy_notify_cname (get_variable_cname (param.name)));
466 } else if (is_in_coroutine ()) {
467 // use closure
468 result.cvalue = get_variable_cexpression (param.name);
469 if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
470 result.delegate_target_cvalue = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), get_ccode_delegate_target_name (param));
471 if (delegate_type.is_disposable ()) {
472 result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), get_delegate_target_destroy_notify_cname (get_variable_cname (param.name)));
475 } else {
476 var type_as_struct = result.value_type.data_type as Struct;
478 if (param.direction == ParameterDirection.OUT) {
479 name = "_vala_%s".printf (name);
482 if (param.direction == ParameterDirection.REF ||
483 (param.direction == ParameterDirection.IN && type_as_struct != null && !type_as_struct.is_simple_type () && !result.value_type.nullable)) {
484 result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (get_variable_cname (name)));
485 } else {
486 // Property setters of non simple structs shall replace all occurrences
487 // of the "value" formal parameter with a dereferencing version of that
488 // parameter.
489 if (current_property_accessor != null &&
490 current_property_accessor.writable &&
491 current_property_accessor.value_parameter == param &&
492 current_property_accessor.prop.property_type.is_real_struct_type () &&
493 !current_property_accessor.prop.property_type.nullable) {
494 result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("value"));
495 } else {
496 result.cvalue = get_variable_cexpression (name);
499 if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
500 var target_cname = get_ccode_delegate_target_name (param);
501 if (param.direction == ParameterDirection.OUT) {
502 target_cname = "_vala_%s".printf (target_cname);
504 CCodeExpression target_expr = new CCodeIdentifier (target_cname);
505 CCodeExpression delegate_target_destroy_notify = new CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname (name)));
506 if (param.direction == ParameterDirection.REF) {
507 // accessing argument of ref param
508 target_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_expr);
509 delegate_target_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, delegate_target_destroy_notify);
511 result.delegate_target_cvalue = target_expr;
512 if (result.value_type.is_disposable ()) {
513 result.delegate_target_destroy_notify_cvalue = delegate_target_destroy_notify;
517 if (!param.captured && array_type != null) {
518 if (get_ccode_array_length (param) && !get_ccode_array_null_terminated (param)) {
519 for (int dim = 1; dim <= array_type.rank; dim++) {
520 CCodeExpression length_expr = get_variable_cexpression (get_parameter_array_length_cname (param, dim));
521 if (param.direction == ParameterDirection.OUT) {
522 length_expr = get_variable_cexpression (get_array_length_cname (get_variable_cname (name), dim));
523 } else if (param.direction == ParameterDirection.REF) {
524 // accessing argument of ref param
525 length_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, length_expr);
527 result.append_array_length_cvalue (length_expr);
533 return result;
536 /* Returns lvalue access to the given field */
537 public override TargetValue get_field_cvalue (Field field, TargetValue? instance) {
538 var value_type = field.variable_type.copy ();
540 var result = new GLibValue (value_type);
541 if (instance != null) {
542 result.actual_value_type = field.variable_type.get_actual_type (instance.value_type, null, field);
544 result.lvalue = true;
545 result.array_null_terminated = get_ccode_array_null_terminated (field);
546 if (get_ccode_array_length_expr (field) != null) {
547 result.array_length_cexpr = new CCodeConstant (get_ccode_array_length_expr (field));
549 result.ctype = get_ccode_type (field);
551 var array_type = result.value_type as ArrayType;
552 var delegate_type = result.value_type as DelegateType;
553 if (field.binding == MemberBinding.INSTANCE) {
554 CCodeExpression pub_inst = null;
556 if (instance != null) {
557 pub_inst = get_cvalue_ (instance);
560 var instance_target_type = get_data_type_for_symbol ((TypeSymbol) field.parent_symbol);
562 var cl = instance_target_type.data_type as Class;
563 bool is_gtypeinstance = ((instance_target_type.data_type == cl) && (cl == null || !cl.is_compact));
565 CCodeExpression inst;
566 if (is_gtypeinstance && field.access == SymbolAccessibility.PRIVATE) {
567 inst = new CCodeMemberAccess.pointer (pub_inst, "priv");
568 } else {
569 if (cl != null) {
570 generate_class_struct_declaration (cl, cfile);
572 inst = pub_inst;
575 if (inst == null) {
576 // FIXME Report this with proper source-reference on the vala side!
577 Report.error (field.source_reference, "Invalid access to instance member `%s'".printf (field.get_full_name ()));
578 result.cvalue = new CCodeInvalidExpression ();
579 return result;
582 if (instance_target_type.data_type.is_reference_type () || (instance != null && instance.value_type is PointerType)) {
583 result.cvalue = new CCodeMemberAccess.pointer (inst, get_ccode_name (field));
584 } else {
585 result.cvalue = new CCodeMemberAccess (inst, get_ccode_name (field));
588 if (array_type != null && get_ccode_array_length (field)) {
589 for (int dim = 1; dim <= array_type.rank; dim++) {
590 CCodeExpression length_expr = null;
592 string length_cname;
593 if (get_ccode_array_length_name (field) != null) {
594 length_cname = get_ccode_array_length_name (field);
595 } else {
596 length_cname = get_array_length_cname (get_ccode_name (field), dim);
599 if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
600 length_expr = new CCodeMemberAccess.pointer (inst, length_cname);
601 } else {
602 length_expr = new CCodeMemberAccess (inst, length_cname);
605 result.append_array_length_cvalue (length_expr);
607 if (array_type.rank == 1 && field.is_internal_symbol ()) {
608 string size_cname = get_array_size_cname (get_ccode_name (field));
610 if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
611 set_array_size_cvalue (result, new CCodeMemberAccess.pointer (inst, size_cname));
612 } else {
613 set_array_size_cvalue (result, new CCodeMemberAccess (inst, size_cname));
616 } else if (delegate_type != null && delegate_type.delegate_symbol.has_target && get_ccode_delegate_target (field)) {
617 string target_cname = get_ccode_delegate_target_name (field);
618 string target_destroy_notify_cname = get_delegate_target_destroy_notify_cname (get_ccode_name (field));
620 if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
621 result.delegate_target_cvalue = new CCodeMemberAccess.pointer (inst, target_cname);
622 if (result.value_type.is_disposable ()){
623 result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess.pointer (inst, target_destroy_notify_cname);
625 } else {
626 result.delegate_target_cvalue = new CCodeMemberAccess (inst, target_cname);
627 if (result.value_type.is_disposable ()) {
628 result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess (inst, target_destroy_notify_cname);
632 } else if (field.binding == MemberBinding.CLASS) {
633 var cl = (Class) field.parent_symbol;
634 var cast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_upper_case_name (cl, null) + "_CLASS"));
636 CCodeExpression klass;
637 if (instance == null) {
638 if (get_this_type () == null) {
639 // Accessing the field from a static or class constructor
640 klass = new CCodeIdentifier ("klass");
641 } else {
642 // Accessing the field from within an instance method
643 var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
644 k.add_argument (new CCodeIdentifier ("self"));
645 klass = k;
647 } else {
648 // Accessing the field of an instance
649 var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
650 k.add_argument (get_cvalue_ (instance));
651 klass = k;
653 cast.add_argument (klass);
655 if (field.access == SymbolAccessibility.PRIVATE) {
656 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf (get_ccode_upper_case_name (cl))));
657 ccall.add_argument (klass);
658 result.cvalue = new CCodeMemberAccess.pointer (ccall, get_ccode_name (field));
659 } else {
660 result.cvalue = new CCodeMemberAccess.pointer (cast, get_ccode_name (field));
663 } else {
664 generate_field_declaration (field, cfile);
666 result.cvalue = new CCodeIdentifier (get_ccode_name (field));
668 if (array_type != null && get_ccode_array_length (field)) {
669 for (int dim = 1; dim <= array_type.rank; dim++) {
670 string length_cname;
671 if (get_ccode_array_length_name (field) != null) {
672 length_cname = get_ccode_array_length_name (field);
673 } else {
674 length_cname = get_array_length_cname (get_ccode_name (field), dim);
677 result.append_array_length_cvalue (new CCodeIdentifier (length_cname));
679 if (array_type.rank == 1 && field.is_internal_symbol ()) {
680 set_array_size_cvalue (result, new CCodeIdentifier (get_array_size_cname (get_ccode_name (field))));
682 } else if (delegate_type != null && delegate_type.delegate_symbol.has_target && get_ccode_delegate_target (field)) {
683 result.delegate_target_cvalue = new CCodeIdentifier (get_ccode_delegate_target_name (field));
684 if (result.value_type.is_disposable ()) {
685 result.delegate_target_destroy_notify_cvalue = new CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_ccode_name (field)));
690 return result;
693 public override TargetValue load_variable (Variable variable, TargetValue value) {
694 var result = (GLibValue) value;
695 var array_type = result.value_type as ArrayType;
696 var delegate_type = result.value_type as DelegateType;
697 if (array_type != null) {
698 if (array_type.fixed_length) {
699 result.array_length_cvalues = null;
700 result.append_array_length_cvalue (get_ccodenode (array_type.length));
701 result.lvalue = false;
702 } else if (get_ccode_array_null_terminated (variable)) {
703 requires_array_length = true;
704 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
705 len_call.add_argument (result.cvalue);
707 result.array_length_cvalues = null;
708 result.append_array_length_cvalue (len_call);
709 result.lvalue = false;
710 } else if (get_ccode_array_length_expr (variable) != null) {
711 var length_expr = new CCodeConstant (get_ccode_array_length_expr (variable));
713 result.array_length_cvalues = null;
714 result.append_array_length_cvalue (length_expr);
715 result.lvalue = false;
716 } else if (!get_ccode_array_length (variable)) {
717 result.array_length_cvalues = null;
718 for (int dim = 1; dim <= array_type.rank; dim++) {
719 result.append_array_length_cvalue (new CCodeConstant ("-1"));
721 result.lvalue = false;
722 } else if (get_ccode_array_length_type (variable) != null) {
723 for (int dim = 1; dim <= array_type.rank; dim++) {
724 // cast if variable does not use int for array length
725 result.array_length_cvalues[dim - 1] = new CCodeCastExpression (result.array_length_cvalues[dim - 1], "gint");
727 result.lvalue = false;
729 result.array_size_cvalue = null;
730 } else if (delegate_type != null) {
731 if (!delegate_type.delegate_symbol.has_target || !get_ccode_delegate_target (variable)) {
732 result.delegate_target_cvalue = new CCodeConstant ("NULL");
735 result.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
736 result.lvalue = false;
738 result.value_type.value_owned = false;
740 bool use_temp = true;
741 if (!is_lvalue_access_allowed (result.value_type)) {
742 // special handling for types such as va_list
743 use_temp = false;
745 if (variable is Parameter && variable.name == "this") {
746 use_temp = false;
748 if (variable.single_assignment && !result.value_type.is_real_non_null_struct_type ()) {
749 // no need to copy values from variables that are assigned exactly once
750 // as there is no risk of modification
751 // except for structs that are always passed by reference
752 use_temp = false;
754 var local = variable as LocalVariable;
755 if (local != null && local.name[0] == '.') {
756 // already a temporary variable generated internally
757 // and safe to access without temporary variable
758 use_temp = false;
761 if (use_temp) {
762 result = (GLibValue) store_temp_value (result, variable);
765 return result;
768 /* Returns unowned access to the given local variable */
769 public override TargetValue load_local (LocalVariable local) {
770 return load_variable (local, get_local_cvalue (local));
773 /* Returns unowned access to the given parameter */
774 public override TargetValue load_parameter (Parameter param) {
775 return load_variable (param, get_parameter_cvalue (param));
778 /* Convenience method returning access to "this" */
779 public override TargetValue load_this_parameter (TypeSymbol sym) {
780 var param = new Parameter ("this", get_data_type_for_symbol (sym));
781 return load_parameter (param);
784 /* Returns unowned access to the given field */
785 public override TargetValue load_field (Field field, TargetValue? instance) {
786 return load_variable (field, get_field_cvalue (field, instance));