codegen: Fix floating reference regression with Variants
[vala-gnome.git] / codegen / valaccodememberaccessmodule.vala
blob4004486439d1c63de307f42c9b726e2046c95ce6
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 if (!base_class.is_compact) {
72 var vclass = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (get_ccode_upper_case_name (base_class))));
73 vclass.add_argument (pub_inst);
74 set_cvalue (expr, new CCodeMemberAccess.pointer (vclass, get_ccode_vfunc_name (m)));
75 } else {
76 set_cvalue (expr, new CCodeMemberAccess.pointer (pub_inst, get_ccode_vfunc_name (m)));
78 } else {
79 set_cvalue (expr, new CCodeIdentifier (get_ccode_name (m.base_method)));
81 } else if (m.base_interface_method != null) {
82 set_cvalue (expr, new CCodeIdentifier (get_ccode_name (m.base_interface_method)));
83 } else if (m is CreationMethod) {
84 set_cvalue (expr, new CCodeIdentifier (get_ccode_real_name (m)));
85 } else {
86 set_cvalue (expr, new CCodeIdentifier (get_ccode_name (m)));
89 set_delegate_target_destroy_notify (expr, new CCodeConstant ("NULL"));
90 if (m.binding == MemberBinding.STATIC) {
91 set_delegate_target (expr, new CCodeConstant ("NULL"));
92 } else if (m.is_async_callback) {
93 if (current_method.closure) {
94 var block = ((Method) m.parent_symbol).body;
95 set_delegate_target (expr, new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), "_async_data_"));
96 } else {
97 set_delegate_target (expr, new CCodeIdentifier ("_data_"));
99 } else if (expr.inner != null && !expr.prototype_access) {
100 // expr.inner is null in the special case of referencing the method in a constant initializer
101 var delegate_target = (CCodeExpression) get_ccodenode (expr.inner);
102 delegate_type = expr.target_type as DelegateType;
103 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)) {
104 var ref_call = new CCodeFunctionCall (get_dup_func_expression (expr.inner.value_type, expr.source_reference));
105 ref_call.add_argument (delegate_target);
106 delegate_target = ref_call;
107 set_delegate_target_destroy_notify (expr, get_destroy_func_expression (expr.inner.value_type));
109 set_delegate_target (expr, delegate_target);
111 } else if (expr.symbol_reference is ArrayLengthField) {
112 if (expr.value_type is ArrayType && !(expr.parent_node is ElementAccess)) {
113 Report.error (expr.source_reference, "unsupported use of length field of multi-dimensional array");
115 set_cvalue (expr, get_array_length_cexpression (expr.inner, 1));
116 } else if (expr.symbol_reference is Field) {
117 var field = (Field) expr.symbol_reference;
118 if (expr.lvalue) {
119 expr.target_value = get_field_cvalue (field, expr.inner != null ? expr.inner.target_value : null);
120 } else {
121 expr.target_value = load_field (field, expr.inner != null ? expr.inner.target_value : null);
123 } else if (expr.symbol_reference is EnumValue) {
124 var ev = (EnumValue) expr.symbol_reference;
126 generate_enum_declaration ((Enum) ev.parent_symbol, cfile);
128 set_cvalue (expr, new CCodeConstant (get_ccode_name (ev)));
129 } else if (expr.symbol_reference is Constant) {
130 var c = (Constant) expr.symbol_reference;
132 generate_constant_declaration (c, cfile,
133 c.source_reference != null && expr.source_reference != null &&
134 c.source_reference.file == expr.source_reference.file);
136 string fn = c.get_full_name ();
137 if (fn == "GLib.Log.FILE") {
138 string s = Path.get_basename (expr.source_reference.file.filename);
139 set_cvalue (expr, new CCodeConstant ("\"%s\"".printf (s)));
140 } else if (fn == "GLib.Log.LINE") {
141 int i = expr.source_reference.begin.line;
142 set_cvalue (expr, new CCodeConstant ("%d".printf (i)));
143 } else if (fn == "GLib.Log.METHOD") {
144 string s = "";
145 if (current_method != null) {
146 s = current_method.get_full_name ();
148 set_cvalue (expr, new CCodeConstant ("\"%s\"".printf (s)));
149 } else {
150 set_cvalue (expr, new CCodeIdentifier (get_ccode_name (c)));
153 if (array_type != null) {
154 string sub = "";
155 for (int i = 0; i < array_type.rank; i++) {
156 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_N_ELEMENTS"));
157 ccall.add_argument (new CCodeIdentifier (get_ccode_name (c) + sub));
158 append_array_length (expr, ccall);
159 sub += "[0]";
162 } else if (expr.symbol_reference is Property) {
163 var prop = (Property) expr.symbol_reference;
165 if (!(prop is DynamicProperty)) {
166 generate_property_accessor_declaration (prop.get_accessor, cfile);
168 if (!prop.external && prop.external_package) {
169 // internal VAPI properties
170 // only add them once per source file
171 if (add_generated_external_symbol (prop)) {
172 visit_property (prop);
177 if (expr.inner is BaseAccess) {
178 var base_prop = prop;
179 if (prop.base_property != null) {
180 base_prop = prop.base_property;
181 } else if (prop.base_interface_property != null) {
182 base_prop = prop.base_interface_property;
184 if (base_prop.parent_symbol is Class) {
185 var base_class = (Class) base_prop.parent_symbol;
186 var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (get_ccode_upper_case_name (base_class, null))));
187 vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class, null))));
189 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (vcast, "get_%s".printf (prop.name)));
190 ccall.add_argument (get_cvalue (expr.inner));
191 if (prop.property_type.is_real_non_null_struct_type ()) {
192 var temp_value = (GLibValue) create_temp_value (prop.get_accessor.value_type, false, expr);
193 expr.target_value = load_temp_value (temp_value);
194 var ctemp = get_cvalue_ (temp_value);
195 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
196 ccode.add_expression (ccall);
197 } else {
198 set_cvalue (expr, ccall);
200 } else if (base_prop.parent_symbol is Interface) {
201 var base_iface = (Interface) base_prop.parent_symbol;
202 string parent_iface_var = "%s_%s_parent_iface".printf (get_ccode_lower_case_name (current_class), get_ccode_lower_case_name (base_iface));
204 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier (parent_iface_var), "get_%s".printf (prop.name)));
205 ccall.add_argument (get_cvalue (expr.inner));
206 if (prop.property_type.is_real_non_null_struct_type ()) {
207 var temp_value = (GLibValue) create_temp_value (prop.get_accessor.value_type, false, expr);
208 expr.target_value = load_temp_value (temp_value);
209 var ctemp = get_cvalue_ (temp_value);
210 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
211 ccode.add_expression (ccall);
212 } else {
213 set_cvalue (expr, ccall);
216 } else if (prop.binding == MemberBinding.INSTANCE &&
217 prop.get_accessor.automatic_body &&
218 !prop.get_accessor.value_type.value_owned &&
219 current_type_symbol == prop.parent_symbol &&
220 current_type_symbol is Class &&
221 prop.base_property == null &&
222 prop.base_interface_property == null &&
223 !(prop.property_type is ArrayType || prop.property_type is DelegateType)) {
224 CCodeExpression inst;
225 inst = new CCodeMemberAccess.pointer (pub_inst, "priv");
226 set_cvalue (expr, new CCodeMemberAccess.pointer (inst, get_ccode_name (prop.field)));
227 } else if (!get_ccode_no_accessor_method (prop)) {
228 string getter_cname;
229 if (prop is DynamicProperty) {
230 getter_cname = get_dynamic_property_getter_cname ((DynamicProperty) prop);
231 } else {
232 getter_cname = get_ccode_name (prop.get_accessor);
234 var ccall = new CCodeFunctionCall (new CCodeIdentifier (getter_cname));
236 if (prop.binding == MemberBinding.INSTANCE) {
237 if (prop.parent_symbol is Struct && !((Struct) prop.parent_symbol).is_simple_type ()) {
238 // we need to pass struct instance by reference
239 var instance = expr.inner.target_value;
240 if (!get_lvalue (instance)) {
241 instance = store_temp_value (instance, expr);
243 pub_inst = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_cvalue_ (instance));
246 ccall.add_argument (pub_inst);
249 bool prop_is_real_non_null_struct_type = prop.property_type.is_real_non_null_struct_type ();
250 var temp_value = (GLibValue) create_temp_value (prop.get_accessor.value_type, prop_is_real_non_null_struct_type, expr);
251 expr.target_value = load_temp_value (temp_value);
252 var ctemp = get_cvalue_ (temp_value);
254 // Property access to real struct types is handled differently
255 // The value is returned by out parameter
256 if (prop_is_real_non_null_struct_type) {
257 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
258 ccode.add_expression (ccall);
259 } else {
260 ccode.add_assignment (ctemp, ccall);
262 array_type = prop.property_type as ArrayType;
263 if (array_type != null) {
264 if (get_ccode_array_null_terminated (prop)) {
265 requires_array_length = true;
266 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
267 len_call.add_argument (ctemp);
269 ccode.add_assignment (temp_value.array_length_cvalues[0], len_call);
270 } else if (get_ccode_array_length (prop)) {
271 for (int dim = 1; dim <= array_type.rank; dim++) {
272 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_array_length_cvalue (temp_value, dim)));
275 } else {
276 delegate_type = prop.property_type as DelegateType;
277 if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
278 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_delegate_target_cvalue (temp_value)));
282 } else {
283 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
284 ccall.add_argument (pub_inst);
286 // property name is second argument of g_object_get
287 ccall.add_argument (get_property_canonical_cconstant (prop));
289 // g_object_get always returns owned values
290 // therefore, property getters of properties
291 // without accessor methods need to be marked as owned
292 if (!prop.get_accessor.value_type.value_owned) {
293 // only report error for types where there actually
294 // is a difference between `owned' and `unowned'
295 var owned_value_type = prop.get_accessor.value_type.copy ();
296 owned_value_type.value_owned = true;
297 if (requires_copy (owned_value_type)) {
298 Report.error (prop.get_accessor.source_reference, "unowned return value for getter of property `%s' not supported without accessor".printf (prop.get_full_name ()));
302 if (expr.value_type.is_real_struct_type ()) {
303 // gobject allocates structs on heap
304 expr.value_type.nullable = true;
307 var temp_var = get_temp_variable (expr.value_type);
308 var ctemp = get_variable_cexpression (temp_var.name);
309 emit_temp_var (temp_var);
310 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ctemp));
311 ccall.add_argument (new CCodeConstant ("NULL"));
312 ccode.add_expression (ccall);
313 set_cvalue (expr, ctemp);
315 expr.target_value.value_type = expr.value_type;
316 expr.target_value = store_temp_value (expr.target_value, expr);
317 } else if (expr.symbol_reference is LocalVariable) {
318 var local = (LocalVariable) expr.symbol_reference;
320 if (expr.parent_node is ReturnStatement &&
321 current_return_type.value_owned &&
322 local.variable_type.value_owned &&
323 !local.captured &&
324 !variable_accessible_in_finally (local) &&
325 !(local.variable_type is ArrayType && ((ArrayType) local.variable_type).inline_allocated)) {
326 /* return expression is local variable taking ownership and
327 * current method is transferring ownership */
329 // don't ref expression
330 expr.value_type.value_owned = true;
332 // don't unref variable
333 local.active = false;
335 var glib_value = (GLibValue) get_local_cvalue (local);
336 expr.target_value = glib_value;
337 if (glib_value.delegate_target_cvalue == null) {
338 glib_value.delegate_target_cvalue = new CCodeConstant ("NULL");
340 if (glib_value.delegate_target_destroy_notify_cvalue == null) {
341 glib_value.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
343 } else {
344 if (expr.lvalue) {
345 expr.target_value = get_local_cvalue (local);
346 } else {
347 expr.target_value = load_local (local);
350 } else if (expr.symbol_reference is Parameter) {
351 var param = (Parameter) expr.symbol_reference;
352 if (expr.lvalue) {
353 expr.target_value = get_parameter_cvalue (param);
354 } else {
355 expr.target_value = load_parameter (param);
360 /* Returns lvalue access to the given local variable */
361 public override TargetValue get_local_cvalue (LocalVariable local) {
362 var result = new GLibValue (local.variable_type.copy ());
363 result.lvalue = true;
365 var array_type = local.variable_type as ArrayType;
366 var delegate_type = local.variable_type as DelegateType;
367 if (local.is_result) {
368 // used in postconditions
369 // structs are returned as out parameter
370 if (local.variable_type != null && local.variable_type.is_real_non_null_struct_type ()) {
371 result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result"));
372 } else {
373 result.cvalue = new CCodeIdentifier ("result");
375 if (array_type != null && !array_type.fixed_length && ((current_method != null && get_ccode_array_length (current_method)) || current_property_accessor != null)) {
376 for (int dim = 1; dim <= array_type.rank; dim++) {
377 result.append_array_length_cvalue (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, get_variable_cexpression (get_array_length_cname ("result", dim))));
380 } else if (local.captured) {
381 // captured variables are stored on the heap
382 var block = (Block) local.parent_symbol;
383 result.cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_local_cname (local));
384 if (array_type != null && !array_type.fixed_length) {
385 for (int dim = 1; dim <= array_type.rank; dim++) {
386 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)));
388 if (array_type.rank == 1) {
389 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)));
391 } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
392 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)));
393 if (delegate_type.is_disposable ()) {
394 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)));
397 } else {
398 result.cvalue = get_local_cexpression (local);
399 if (array_type != null && !array_type.fixed_length) {
400 for (int dim = 1; dim <= array_type.rank; dim++) {
401 result.append_array_length_cvalue (get_variable_cexpression (get_array_length_cname (get_local_cname (local), dim)));
403 if (array_type.rank == 1) {
404 result.array_size_cvalue = get_variable_cexpression (get_array_size_cname (get_local_cname (local)));
406 } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
407 if (is_in_coroutine ()) {
408 result.delegate_target_cvalue = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), get_delegate_target_cname (get_local_cname (local)));
409 if (local.variable_type.is_disposable ()) {
410 result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), get_delegate_target_destroy_notify_cname (get_local_cname (local)));
412 } else {
413 result.delegate_target_cvalue = new CCodeIdentifier (get_delegate_target_cname (get_local_cname (local)));
414 if (local.variable_type.is_disposable ()) {
415 result.delegate_target_destroy_notify_cvalue = new CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_local_cname (local)));
421 return result;
424 /* Returns access values to the given parameter */
425 public override TargetValue get_parameter_cvalue (Parameter param) {
426 var result = new GLibValue (param.variable_type.copy ());
427 result.lvalue = true;
428 result.array_null_terminated = get_ccode_array_null_terminated (param);
429 if (get_ccode_array_length_expr (param) != null) {
430 result.array_length_cexpr = new CCodeConstant (get_ccode_array_length_expr (param));
432 result.ctype = get_ccode_type (param);
434 var array_type = result.value_type as ArrayType;
435 var delegate_type = result.value_type as DelegateType;
437 bool is_unowned_delegate = delegate_type != null && !param.variable_type.value_owned;
438 if ((param.captured || is_in_coroutine ()) && !is_unowned_delegate) {
439 result.value_type.value_owned = true;
442 if (param.name == "this") {
443 if (is_in_coroutine ()) {
444 // use closure
445 result.cvalue = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "self");
446 } else {
447 var st = result.value_type.data_type as Struct;
448 if (st != null && !st.is_simple_type ()) {
449 result.cvalue = new CCodeIdentifier ("(*self)");
450 } else {
451 result.cvalue = new CCodeIdentifier ("self");
454 } else {
455 string name = param.name;
457 if (param.captured) {
458 // captured variables are stored on the heap
459 var block = param.parent_symbol as Block;
460 if (block == null) {
461 block = ((Method) param.parent_symbol).body;
463 result.cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_variable_cname (param.name));
464 if (array_type != null && get_ccode_array_length (param)) {
465 for (int dim = 1; dim <= array_type.rank; dim++) {
466 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)));
468 } else if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
469 result.delegate_target_cvalue = new CCodeMemberAccess.pointer (get_variable_cexpression ("_data%d_".printf (get_block_id (block))), get_ccode_delegate_target_name (param));
470 if (result.value_type.is_disposable ()) {
471 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)));
474 } else if (is_in_coroutine ()) {
475 // use closure
476 result.cvalue = get_variable_cexpression (param.name);
477 if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
478 result.delegate_target_cvalue = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), get_ccode_delegate_target_name (param));
479 if (delegate_type.is_disposable ()) {
480 result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), get_delegate_target_destroy_notify_cname (get_variable_cname (param.name)));
483 } else {
484 var type_as_struct = result.value_type.data_type as Struct;
486 if (param.direction == ParameterDirection.OUT) {
487 name = "_vala_%s".printf (name);
490 if (param.direction == ParameterDirection.REF ||
491 (param.direction == ParameterDirection.IN && type_as_struct != null && !type_as_struct.is_simple_type () && !result.value_type.nullable)) {
492 result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (get_variable_cname (name)));
493 } else {
494 // Property setters of non simple structs shall replace all occurrences
495 // of the "value" formal parameter with a dereferencing version of that
496 // parameter.
497 if (current_property_accessor != null &&
498 current_property_accessor.writable &&
499 current_property_accessor.value_parameter == param &&
500 current_property_accessor.prop.property_type.is_real_struct_type () &&
501 !current_property_accessor.prop.property_type.nullable) {
502 result.cvalue = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("value"));
503 } else {
504 result.cvalue = get_variable_cexpression (name);
507 if (delegate_type != null && delegate_type.delegate_symbol.has_target) {
508 var target_cname = get_ccode_delegate_target_name (param);
509 if (param.direction == ParameterDirection.OUT) {
510 target_cname = "_vala_%s".printf (target_cname);
512 CCodeExpression target_expr = new CCodeIdentifier (target_cname);
513 CCodeExpression delegate_target_destroy_notify = new CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_variable_cname (name)));
514 if (param.direction == ParameterDirection.REF) {
515 // accessing argument of ref param
516 target_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, target_expr);
517 delegate_target_destroy_notify = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, delegate_target_destroy_notify);
519 result.delegate_target_cvalue = target_expr;
520 if (result.value_type.is_disposable ()) {
521 result.delegate_target_destroy_notify_cvalue = delegate_target_destroy_notify;
525 if (!param.captured && array_type != null) {
526 if (get_ccode_array_length (param) && !get_ccode_array_null_terminated (param)) {
527 for (int dim = 1; dim <= array_type.rank; dim++) {
528 CCodeExpression length_expr = get_variable_cexpression (get_parameter_array_length_cname (param, dim));
529 if (param.direction == ParameterDirection.OUT) {
530 length_expr = get_variable_cexpression (get_array_length_cname (get_variable_cname (name), dim));
531 } else if (param.direction == ParameterDirection.REF) {
532 // accessing argument of ref param
533 length_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, length_expr);
535 result.append_array_length_cvalue (length_expr);
541 return result;
544 /* Returns lvalue access to the given field */
545 public override TargetValue get_field_cvalue (Field field, TargetValue? instance) {
546 var value_type = field.variable_type.copy ();
548 var result = new GLibValue (value_type);
549 if (instance != null) {
550 result.actual_value_type = field.variable_type.get_actual_type (instance.value_type, null, field);
552 result.lvalue = true;
553 result.array_null_terminated = get_ccode_array_null_terminated (field);
554 if (get_ccode_array_length_expr (field) != null) {
555 result.array_length_cexpr = new CCodeConstant (get_ccode_array_length_expr (field));
557 result.ctype = get_ccode_type (field);
559 var array_type = result.value_type as ArrayType;
560 var delegate_type = result.value_type as DelegateType;
561 if (field.binding == MemberBinding.INSTANCE) {
562 CCodeExpression pub_inst = null;
564 if (instance != null) {
565 pub_inst = get_cvalue_ (instance);
568 var instance_target_type = get_data_type_for_symbol ((TypeSymbol) field.parent_symbol);
570 var cl = instance_target_type.data_type as Class;
571 bool is_gtypeinstance = ((instance_target_type.data_type == cl) && (cl == null || !cl.is_compact));
573 CCodeExpression inst;
574 if (is_gtypeinstance && field.access == SymbolAccessibility.PRIVATE) {
575 inst = new CCodeMemberAccess.pointer (pub_inst, "priv");
576 } else {
577 if (cl != null) {
578 generate_class_struct_declaration (cl, cfile);
580 inst = pub_inst;
583 if (inst == null) {
584 // FIXME Report this with proper source-reference on the vala side!
585 Report.error (field.source_reference, "Invalid access to instance member `%s'".printf (field.get_full_name ()));
586 result.cvalue = new CCodeInvalidExpression ();
587 return result;
590 if (instance_target_type.data_type.is_reference_type () || (instance != null && instance.value_type is PointerType)) {
591 result.cvalue = new CCodeMemberAccess.pointer (inst, get_ccode_name (field));
592 } else {
593 result.cvalue = new CCodeMemberAccess (inst, get_ccode_name (field));
596 if (array_type != null && get_ccode_array_length (field)) {
597 for (int dim = 1; dim <= array_type.rank; dim++) {
598 CCodeExpression length_expr = null;
600 string length_cname;
601 if (get_ccode_array_length_name (field) != null) {
602 length_cname = get_ccode_array_length_name (field);
603 } else {
604 length_cname = get_array_length_cname (get_ccode_name (field), dim);
607 if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
608 length_expr = new CCodeMemberAccess.pointer (inst, length_cname);
609 } else {
610 length_expr = new CCodeMemberAccess (inst, length_cname);
613 result.append_array_length_cvalue (length_expr);
615 if (array_type.rank == 1 && field.is_internal_symbol ()) {
616 string size_cname = get_array_size_cname (get_ccode_name (field));
618 if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
619 set_array_size_cvalue (result, new CCodeMemberAccess.pointer (inst, size_cname));
620 } else {
621 set_array_size_cvalue (result, new CCodeMemberAccess (inst, size_cname));
624 } else if (delegate_type != null && delegate_type.delegate_symbol.has_target && get_ccode_delegate_target (field)) {
625 string target_cname = get_ccode_delegate_target_name (field);
626 string target_destroy_notify_cname = get_delegate_target_destroy_notify_cname (get_ccode_name (field));
628 if (((TypeSymbol) field.parent_symbol).is_reference_type ()) {
629 result.delegate_target_cvalue = new CCodeMemberAccess.pointer (inst, target_cname);
630 if (result.value_type.is_disposable ()){
631 result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess.pointer (inst, target_destroy_notify_cname);
633 } else {
634 result.delegate_target_cvalue = new CCodeMemberAccess (inst, target_cname);
635 if (result.value_type.is_disposable ()) {
636 result.delegate_target_destroy_notify_cvalue = new CCodeMemberAccess (inst, target_destroy_notify_cname);
640 } else if (field.binding == MemberBinding.CLASS) {
641 var cl = (Class) field.parent_symbol;
642 var cast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_upper_case_name (cl, null) + "_CLASS"));
644 CCodeExpression klass;
645 if (instance == null) {
646 if (get_this_type () == null) {
647 // Accessing the field from a static or class constructor
648 klass = new CCodeIdentifier ("klass");
649 } else {
650 // Accessing the field from within an instance method
651 var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
652 k.add_argument (new CCodeIdentifier ("self"));
653 klass = k;
655 } else {
656 // Accessing the field of an instance
657 var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
658 k.add_argument (get_cvalue_ (instance));
659 klass = k;
661 cast.add_argument (klass);
663 if (field.access == SymbolAccessibility.PRIVATE) {
664 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf (get_ccode_upper_case_name (cl))));
665 ccall.add_argument (klass);
666 result.cvalue = new CCodeMemberAccess.pointer (ccall, get_ccode_name (field));
667 } else {
668 result.cvalue = new CCodeMemberAccess.pointer (cast, get_ccode_name (field));
671 } else {
672 generate_field_declaration (field, cfile);
674 result.cvalue = new CCodeIdentifier (get_ccode_name (field));
676 if (array_type != null && get_ccode_array_length (field)) {
677 for (int dim = 1; dim <= array_type.rank; dim++) {
678 string length_cname;
679 if (get_ccode_array_length_name (field) != null) {
680 length_cname = get_ccode_array_length_name (field);
681 } else {
682 length_cname = get_array_length_cname (get_ccode_name (field), dim);
685 result.append_array_length_cvalue (new CCodeIdentifier (length_cname));
687 if (array_type.rank == 1 && field.is_internal_symbol ()) {
688 set_array_size_cvalue (result, new CCodeIdentifier (get_array_size_cname (get_ccode_name (field))));
690 } else if (delegate_type != null && delegate_type.delegate_symbol.has_target && get_ccode_delegate_target (field)) {
691 result.delegate_target_cvalue = new CCodeIdentifier (get_ccode_delegate_target_name (field));
692 if (result.value_type.is_disposable ()) {
693 result.delegate_target_destroy_notify_cvalue = new CCodeIdentifier (get_delegate_target_destroy_notify_cname (get_ccode_name (field)));
698 return result;
701 public override TargetValue load_variable (Variable variable, TargetValue value) {
702 var result = (GLibValue) value;
703 var array_type = result.value_type as ArrayType;
704 var delegate_type = result.value_type as DelegateType;
705 if (array_type != null) {
706 if (array_type.fixed_length) {
707 result.array_length_cvalues = null;
708 result.append_array_length_cvalue (get_ccodenode (array_type.length));
709 result.lvalue = false;
710 } else if (get_ccode_array_null_terminated (variable)) {
711 requires_array_length = true;
712 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("_vala_array_length"));
713 len_call.add_argument (result.cvalue);
715 result.array_length_cvalues = null;
716 result.append_array_length_cvalue (len_call);
717 result.lvalue = false;
718 } else if (get_ccode_array_length_expr (variable) != null) {
719 var length_expr = new CCodeConstant (get_ccode_array_length_expr (variable));
721 result.array_length_cvalues = null;
722 result.append_array_length_cvalue (length_expr);
723 result.lvalue = false;
724 } else if (!get_ccode_array_length (variable)) {
725 result.array_length_cvalues = null;
726 for (int dim = 1; dim <= array_type.rank; dim++) {
727 result.append_array_length_cvalue (new CCodeConstant ("-1"));
729 result.lvalue = false;
730 } else if (get_ccode_array_length_type (variable) != null) {
731 for (int dim = 1; dim <= array_type.rank; dim++) {
732 // cast if variable does not use int for array length
733 result.array_length_cvalues[dim - 1] = new CCodeCastExpression (result.array_length_cvalues[dim - 1], "gint");
735 result.lvalue = false;
737 result.array_size_cvalue = null;
738 } else if (delegate_type != null) {
739 if (!delegate_type.delegate_symbol.has_target || !get_ccode_delegate_target (variable)) {
740 result.delegate_target_cvalue = new CCodeConstant ("NULL");
743 result.delegate_target_destroy_notify_cvalue = new CCodeConstant ("NULL");
744 result.lvalue = false;
746 result.value_type.value_owned = false;
748 bool use_temp = true;
749 if (!is_lvalue_access_allowed (result.value_type)) {
750 // special handling for types such as va_list
751 use_temp = false;
753 if (variable is Parameter) {
754 var param = (Parameter) variable;
755 if (variable.name == "this") {
756 use_temp = false;
757 } else if ((param.direction != ParameterDirection.OUT)
758 && !(param.variable_type.is_real_non_null_struct_type ())) {
759 use_temp = false;
762 if (variable.single_assignment && !result.value_type.is_real_non_null_struct_type ()) {
763 // no need to copy values from variables that are assigned exactly once
764 // as there is no risk of modification
765 // except for structs that are always passed by reference
766 use_temp = false;
768 var local = variable as LocalVariable;
769 if (local != null && local.name[0] == '.') {
770 // already a temporary variable generated internally
771 // and safe to access without temporary variable
772 use_temp = false;
775 if (use_temp) {
776 result = (GLibValue) store_temp_value (result, variable);
779 return result;
782 /* Returns unowned access to the given local variable */
783 public override TargetValue load_local (LocalVariable local) {
784 return load_variable (local, get_local_cvalue (local));
787 /* Returns unowned access to the given parameter */
788 public override TargetValue load_parameter (Parameter param) {
789 return load_variable (param, get_parameter_cvalue (param));
792 /* Convenience method returning access to "this" */
793 public override TargetValue load_this_parameter (TypeSymbol sym) {
794 var param = new Parameter ("this", get_data_type_for_symbol (sym));
795 return load_parameter (param);
798 /* Returns unowned access to the given field */
799 public override TargetValue load_field (Field field, TargetValue? instance) {
800 return load_variable (field, get_field_cvalue (field, instance));