3 * Copyright (C) 2006-2009 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Jürg Billeter <j@bitron.ch>
27 * Represents an invocation expression in the source code.
29 public class Vala
.MethodCall
: Expression
{
33 public Expression call
{
37 _call
.parent_node
= this
;
41 public CCodeExpression delegate_target
{ get; set; }
43 public Expression _call
;
45 private Gee
.List
<Expression
> argument_list
= new ArrayList
<Expression
> ();
46 private Gee
.List
<CCodeExpression
> array_sizes
= new ArrayList
<CCodeExpression
> ();
49 * Creates a new invocation expression.
51 * @param call method to call
52 * @param source_reference reference to source code
53 * @return newly created invocation expression
55 public MethodCall (Expression call
, SourceReference? source_reference
= null) {
56 this
.source_reference
= source_reference
;
61 * Appends the specified expression to the list of arguments.
63 * @param arg an argument
65 public void add_argument (Expression arg
) {
66 argument_list
.add (arg
);
67 arg
.parent_node
= this
;
71 * Returns a copy of the argument list.
73 * @return argument list
75 public Gee
.List
<Expression
> get_argument_list () {
76 return new ReadOnlyList
<Expression
> (argument_list
);
80 * Add an array size C code expression.
82 public void append_array_size (CCodeExpression size
) {
83 array_sizes
.add (size
);
87 * Get the C code expression for array sizes for all dimensions
88 * ascending from left to right.
90 public Gee
.List
<CCodeExpression
> get_array_sizes () {
91 return new ReadOnlyList
<CCodeExpression
> (array_sizes
);
94 public override void accept (CodeVisitor visitor
) {
95 visitor
.visit_method_call (this
);
97 visitor
.visit_expression (this
);
100 public override void accept_children (CodeVisitor visitor
) {
101 call
.accept (visitor
);
103 foreach (Expression expr
in argument_list
) {
104 expr
.accept (visitor
);
108 public override void replace_expression (Expression old_node
, Expression new_node
) {
109 if (call
== old_node
) {
113 int index
= argument_list
.index_of (old_node
);
114 if (index
>= 0 && new_node
.parent_node
== null) {
115 argument_list
[index
] = new_node
;
116 new_node
.parent_node
= this
;
120 public override bool is_pure () {
124 public override bool check (SemanticAnalyzer analyzer
) {
131 if (!call
.check (analyzer
)) {
132 /* if method resolving didn't succeed, skip this check */
137 // type of target object
138 DataType target_object_type
= null;
140 if (call is MemberAccess
) {
141 var ma
= (MemberAccess
) call
;
142 if (ma
.prototype_access
) {
144 Report
.error (source_reference
, "Access to instance member `%s' denied".printf (call
.symbol_reference
.get_full_name ()));
148 if (ma
.inner
!= null) {
149 target_object_type
= ma
.inner
.value_type
;
153 var mtype
= call
.value_type
;
155 if (mtype is ObjectType
) {
156 // constructor chain-up
157 var cm
= analyzer
.find_current_method () as CreationMethod
;
160 Report
.error (source_reference
, "use `new' operator to create new objects");
162 } else if (cm
.chain_up
) {
164 Report
.error (source_reference
, "Multiple constructor calls in the same constructor are not permitted");
170 // check for struct construction
171 if (call is MemberAccess
&&
172 ((call
.symbol_reference is CreationMethod
173 && call
.symbol_reference
.parent_symbol is Struct
)
174 || call
.symbol_reference is Struct
)) {
175 var struct_creation_expression
= new
ObjectCreationExpression ((MemberAccess
) call
, source_reference
);
176 struct_creation_expression
.struct_creation
= true;
177 foreach (Expression arg
in get_argument_list ()) {
178 struct_creation_expression
.add_argument (arg
);
180 struct_creation_expression
.target_type
= target_type
;
181 analyzer
.replaced_nodes
.add (this
);
182 parent_node
.replace_expression (this
, struct_creation_expression
);
183 struct_creation_expression
.check (analyzer
);
185 } else if (call is MemberAccess
186 && call
.symbol_reference is CreationMethod
) {
187 // constructor chain-up
188 var cm
= analyzer
.find_current_method () as CreationMethod
;
191 Report
.error (source_reference
, "use `new' operator to create new objects");
193 } else if (cm
.chain_up
) {
195 Report
.error (source_reference
, "Multiple constructor calls in the same constructor are not permitted");
201 Gee
.List
<FormalParameter
> params
;
203 if (mtype
!= null && mtype
.is_invokable ()) {
204 params
= mtype
.get_parameters ();
205 } else if (call
.symbol_reference is Class
) {
207 Report
.error (source_reference
, "use `new' operator to create new objects");
211 Report
.error (source_reference
, "invocation not supported in this context");
215 Expression last_arg
= null;
217 var args
= get_argument_list ();
218 Iterator
<Expression
> arg_it
= args
.iterator ();
219 foreach (FormalParameter param
in params
) {
220 if (param
.ellipsis
) {
224 if (param
.params_array
) {
225 var array_type
= (ArrayType
) param
.parameter_type
;
226 while (arg_it
.next ()) {
227 Expression arg
= arg_it
.get ();
229 /* store expected type for callback parameters */
230 arg
.target_type
= array_type
.element_type
;
231 arg
.target_type
.value_owned
= array_type
.value_owned
;
236 if (arg_it
.next ()) {
237 Expression arg
= arg_it
.get ();
239 /* store expected type for callback parameters */
240 arg
.formal_target_type
= param
.parameter_type
;
241 arg
.target_type
= arg
.formal_target_type
.get_actual_type (target_object_type
, this
);
248 if (mtype is MethodType
&& ((MethodType
) mtype
).method_symbol
.printf_format
) {
249 StringLiteral format_literal
= null;
250 if (last_arg
!= null) {
251 // use last argument as format string
252 format_literal
= last_arg as StringLiteral
;
254 // use instance as format string for string.printf (...)
255 var ma
= call as MemberAccess
;
257 format_literal
= ma
.inner as StringLiteral
;
260 if (format_literal
!= null) {
261 string format
= format_literal
.eval ();
263 bool unsupported_format
= false;
265 weak string format_it
= format
;
266 unichar c
= format_it
.get_char ();
269 format_it
= format_it
.next_char ();
270 c
= format_it
.get_char ();
274 format_it
= format_it
.next_char ();
275 c
= format_it
.get_char ();
277 while (c
== '#' || c
== '0' || c
== '-' || c
== ' ' || c
== '+') {
278 format_it
= format_it
.next_char ();
279 c
= format_it
.get_char ();
282 while (c
>= '0' && c
<= '9') {
283 format_it
= format_it
.next_char ();
284 c
= format_it
.get_char ();
288 format_it
= format_it
.next_char ();
289 c
= format_it
.get_char ();
290 while (c
>= '0' && c
<= '9') {
291 format_it
= format_it
.next_char ();
292 c
= format_it
.get_char ();
299 format_it
= format_it
.next_char ();
300 c
= format_it
.get_char ();
303 format_it
= format_it
.next_char ();
304 c
= format_it
.get_char ();
306 } else if (c
== 'l') {
308 format_it
= format_it
.next_char ();
309 c
= format_it
.get_char ();
310 } else if (c
== 'z') {
312 format_it
= format_it
.next_char ();
313 c
= format_it
.get_char ();
315 // conversion specifier
316 DataType param_type
= null;
317 if (c
== 'd' || c
== 'i' || c
== 'c') {
320 param_type
= analyzer
.int8_type
;
321 } else if (length
== -1) {
322 param_type
= analyzer
.short_type
;
323 } else if (length
== 0) {
324 param_type
= analyzer
.int_type
;
325 } else if (length
== 1) {
326 param_type
= analyzer
.long_type
;
327 } else if (length
== 2) {
328 param_type
= analyzer
.ssize_t_type
;
330 } else if (c
== 'o' || c
== 'u' || c
== 'x' || c
== 'X') {
333 param_type
= analyzer
.uchar_type
;
334 } else if (length
== -1) {
335 param_type
= analyzer
.ushort_type
;
336 } else if (length
== 0) {
337 param_type
= analyzer
.uint_type
;
338 } else if (length
== 1) {
339 param_type
= analyzer
.ulong_type
;
340 } else if (length
== 2) {
341 param_type
= analyzer
.size_t_type
;
343 } else if (c
== 'e' || c
== 'E' || c
== 'f' || c
== 'F'
344 || c
== 'g' || c
== 'G' || c
== 'a' || c
== 'A') {
346 param_type
= analyzer
.double_type
;
347 } else if (c
== 's') {
349 param_type
= analyzer
.string_type
;
350 } else if (c
== 'p') {
352 param_type
= new
PointerType (new
VoidType ());
353 } else if (c
== '%') {
356 unsupported_format
= true;
360 format_it
= format_it
.next_char ();
361 c
= format_it
.get_char ();
363 if (param_type
!= null) {
364 if (arg_it
.next ()) {
365 Expression arg
= arg_it
.get ();
367 arg
.target_type
= param_type
;
369 Report
.error (source_reference
, "Too few arguments for specified format");
374 if (!unsupported_format
&& arg_it
.next ()) {
375 Report
.error (source_reference
, "Too many arguments for specified format");
381 foreach (Expression arg
in get_argument_list ()) {
382 arg
.check (analyzer
);
385 DataType ret_type
= mtype
.get_return_type ();
386 params
= mtype
.get_parameters ();
388 if (ret_type is VoidType
) {
390 if (!(parent_node is ExpressionStatement
)
391 && !(parent_node is ForStatement
)
392 && !(parent_node is YieldStatement
)) {
393 // A void method invocation can be in the initializer or
394 // iterator of a for statement
396 Report
.error (source_reference
, "invocation of void method not allowed as expression");
401 formal_value_type
= ret_type
;
402 value_type
= formal_value_type
.get_actual_type (target_object_type
, this
);
404 bool may_throw
= false;
406 if (mtype is MethodType
) {
407 var m
= ((MethodType
) mtype
).method_symbol
;
408 foreach (DataType error_type
in m
.get_error_types ()) {
411 // ensure we can trace back which expression may throw errors of this type
412 var call_error_type
= error_type
.copy ();
413 call_error_type
.source_reference
= source_reference
;
415 add_error_type (call_error_type
);
417 } else if (mtype is DelegateType
) {
418 var d
= ((DelegateType
) mtype
).delegate_symbol
;
419 foreach (DataType error_type
in d
.get_error_types ()) {
422 // ensure we can trace back which expression may throw errors of this type
423 var call_error_type
= error_type
.copy ();
424 call_error_type
.source_reference
= source_reference
;
426 add_error_type (call_error_type
);
430 if (!analyzer
.check_arguments (this
, mtype
, params
, get_argument_list ())) {
436 if (parent_node is LocalVariable
|| parent_node is ExpressionStatement
) {
437 // simple statements, no side effects after method call
439 var old_insert_block
= analyzer
.insert_block
;
440 analyzer
.insert_block
= prepare_condition_split (analyzer
);
442 // store parent_node as we need to replace the expression in the old parent node later on
443 var old_parent_node
= parent_node
;
445 var local
= new
LocalVariable (value_type
, get_temp_name (), null, source_reference
);
446 // use floating variable to avoid unnecessary (and sometimes impossible) copies
447 local
.floating
= true;
448 var decl
= new
DeclarationStatement (local
, source_reference
);
450 insert_statement (analyzer
.insert_block
, decl
);
452 Expression temp_access
= new MemberAccess
.simple (local
.name
, source_reference
);
453 temp_access
.target_type
= target_type
;
455 // don't set initializer earlier as this changes parent_node and parent_statement
456 local
.initializer
= this
;
457 decl
.check (analyzer
);
458 temp_access
.check (analyzer
);
460 // move temp variable to insert block to ensure the
461 // variable is in the same block as the declaration
462 // otherwise there will be scoping issues in the generated code
463 var block
= (Block
) analyzer
.current_symbol
;
464 block
.remove_local_variable (local
);
465 analyzer
.insert_block
.add_local_variable (local
);
467 analyzer
.insert_block
= old_insert_block
;
469 old_parent_node
.replace_expression (this
, temp_access
);
476 public override void get_defined_variables (Collection
<LocalVariable
> collection
) {
477 call
.get_defined_variables (collection
);
479 foreach (Expression arg
in argument_list
) {
480 arg
.get_defined_variables (collection
);
484 public override void get_used_variables (Collection
<LocalVariable
> collection
) {
485 call
.get_used_variables (collection
);
487 foreach (Expression arg
in argument_list
) {
488 arg
.get_used_variables (collection
);