1 /* valaobjectcreationexpression.vala
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 object creation expression in the source code.
29 public class Vala
.ObjectCreationExpression
: Expression
{
31 * The object type to create.
33 public DataType type_reference
{
34 get { return _data_type
; }
37 _data_type
.parent_node
= this
;
42 * The construction method to use. May be null to indicate that
43 * the default construction method should be used.
45 public Method constructor
{ get; set; }
48 * The construction method to use or the data type to be created
49 * with the default construction method.
51 public MemberAccess member_name
{ get; set; }
53 public bool struct_creation
{ get; set; }
55 private Gee
.List
<Expression
> argument_list
= new ArrayList
<Expression
> ();
57 private Gee
.List
<MemberInitializer
> object_initializer
= new ArrayList
<MemberInitializer
> ();
59 private DataType _data_type
;
62 * Creates a new object creation expression.
64 * @param member_name object type to create
65 * @param source_reference reference to source code
66 * @return newly created object creation expression
68 public ObjectCreationExpression (MemberAccess member_name
, SourceReference source_reference
) {
69 this
.source_reference
= source_reference
;
70 this
.member_name
= member_name
;
74 * Appends the specified expression to the list of arguments.
76 * @param arg an argument
78 public void add_argument (Expression arg
) {
79 argument_list
.add (arg
);
80 arg
.parent_node
= this
;
84 * Returns a copy of the argument list.
86 * @return argument list
88 public Gee
.List
<Expression
> get_argument_list () {
89 return new ReadOnlyList
<Expression
> (argument_list
);
93 * Appends the specified member initializer to the object initializer.
95 * @param init a member initializer
97 public void add_member_initializer (MemberInitializer init
) {
98 object_initializer
.add (init
);
99 init
.parent_node
= this
;
103 * Returns the object initializer.
105 * @return member initializer list
107 public Gee
.List
<MemberInitializer
> get_object_initializer () {
108 return new ReadOnlyList
<MemberInitializer
> (object_initializer
);
111 public override void accept (CodeVisitor visitor
) {
112 visitor
.visit_object_creation_expression (this
);
114 visitor
.visit_expression (this
);
117 public override void accept_children (CodeVisitor visitor
) {
118 if (type_reference
!= null) {
119 type_reference
.accept (visitor
);
122 if (member_name
!= null) {
123 member_name
.accept (visitor
);
126 foreach (Expression arg
in argument_list
) {
127 arg
.accept (visitor
);
130 foreach (MemberInitializer init
in object_initializer
) {
131 init
.accept (visitor
);
135 public override void replace_expression (Expression old_node
, Expression new_node
) {
136 int index
= argument_list
.index_of (old_node
);
137 if (index
>= 0 && new_node
.parent_node
== null) {
138 argument_list
[index
] = new_node
;
139 new_node
.parent_node
= this
;
143 public override bool is_pure () {
147 public override void replace_type (DataType old_type
, DataType new_type
) {
148 if (type_reference
== old_type
) {
149 type_reference
= new_type
;
153 public override bool check (SemanticAnalyzer analyzer
) {
160 if (member_name
!= null) {
161 member_name
.check (analyzer
);
164 TypeSymbol type
= null;
166 if (type_reference
== null) {
167 if (member_name
== null) {
169 Report
.error (source_reference
, "Incomplete object creation expression");
173 if (member_name
.symbol_reference
== null) {
178 var constructor_sym
= member_name
.symbol_reference
;
179 var type_sym
= member_name
.symbol_reference
;
181 var type_args
= member_name
.get_type_arguments ();
183 if (constructor_sym is Method
) {
184 type_sym
= constructor_sym
.parent_symbol
;
186 var constructor
= (Method
) constructor_sym
;
187 if (!(constructor_sym is CreationMethod
)) {
189 Report
.error (source_reference
, "`%s' is not a creation method".printf (constructor
.get_full_name ()));
193 symbol_reference
= constructor
;
195 // inner expression can also be base access when chaining constructors
196 var ma
= member_name
.inner as MemberAccess
;
198 type_args
= ma
.get_type_arguments ();
202 if (type_sym is Class
) {
203 type
= (TypeSymbol
) type_sym
;
204 type_reference
= new
ObjectType ((Class
) type
);
205 } else if (type_sym is Struct
) {
206 type
= (TypeSymbol
) type_sym
;
207 type_reference
= new
StructValueType ((Struct
) type
);
208 } else if (type_sym is ErrorCode
) {
209 type_reference
= new
ErrorType ((ErrorDomain
) type_sym
.parent_symbol
, (ErrorCode
) type_sym
, source_reference
);
210 symbol_reference
= type_sym
;
213 Report
.error (source_reference
, "`%s' is not a class, struct, or error code".printf (type_sym
.get_full_name ()));
217 foreach (DataType type_arg
in type_args
) {
218 type_reference
.add_type_argument (type_arg
);
220 analyzer
.current_source_file
.add_type_dependency (type_arg
, SourceFileDependencyType
.SOURCE
);
223 type
= type_reference
.data_type
;
226 analyzer
.current_source_file
.add_symbol_dependency (type
, SourceFileDependencyType
.SOURCE
);
228 value_type
= type_reference
.copy ();
229 value_type
.value_owned
= true;
231 int given_num_type_args
= type_reference
.get_type_arguments ().size
;
232 int expected_num_type_args
= 0;
235 var cl
= (Class
) type
;
237 expected_num_type_args
= cl
.get_type_parameters ().size
;
239 if (struct_creation
) {
241 Report
.error (source_reference
, "syntax error, use `new' to create new objects");
245 if (cl
.is_abstract
) {
248 Report
.error (source_reference
, "Can't create instance of abstract class `%s'".printf (cl
.get_full_name ()));
252 if (symbol_reference
== null) {
253 symbol_reference
= cl
.default_construction_method
;
255 if (symbol_reference
!= null) {
256 // track usage for flow analyzer
257 symbol_reference
.used
= true;
262 if (cl
== analyzer
.initially_unowned_type
) {
263 value_type
.floating_reference
= true;
269 } else if (type is Struct
) {
270 var st
= (Struct
) type
;
272 expected_num_type_args
= st
.get_type_parameters ().size
;
274 if (!struct_creation
&& !analyzer
.context
.deprecated
) {
275 Report
.warning (source_reference
, "deprecated syntax, don't use `new' to initialize structs");
278 if (symbol_reference
== null) {
279 symbol_reference
= st
.default_construction_method
;
283 if (expected_num_type_args
> given_num_type_args
) {
285 Report
.error (source_reference
, "too few type arguments");
287 } else if (expected_num_type_args
< given_num_type_args
) {
289 Report
.error (source_reference
, "too many type arguments");
293 if (symbol_reference
== null && get_argument_list ().size
!= 0) {
296 Report
.error (source_reference
, "No arguments allowed when constructing type `%s'".printf (type
.get_full_name ()));
300 if (symbol_reference is Method
) {
301 var m
= (Method
) symbol_reference
;
303 var args
= get_argument_list ();
304 Iterator
<Expression
> arg_it
= args
.iterator ();
305 foreach (FormalParameter param
in m
.get_parameters ()) {
306 if (param
.ellipsis
) {
310 if (arg_it
.next ()) {
311 Expression arg
= arg_it
.get ();
313 /* store expected type for callback parameters */
314 arg
.target_type
= param
.parameter_type
;
318 foreach (Expression arg
in args
) {
319 arg
.check (analyzer
);
322 analyzer
.check_arguments (this
, new
MethodType (m
), m
.get_parameters (), args
);
324 foreach (DataType error_type
in m
.get_error_types ()) {
325 // ensure we can trace back which expression may throw errors of this type
326 var call_error_type
= error_type
.copy ();
327 call_error_type
.source_reference
= source_reference
;
329 add_error_type (call_error_type
);
331 } else if (type_reference is ErrorType
) {
332 if (type_reference
!= null) {
333 type_reference
.check (analyzer
);
336 if (member_name
!= null) {
337 member_name
.check (analyzer
);
340 foreach (Expression arg
in argument_list
) {
341 arg
.check (analyzer
);
344 foreach (MemberInitializer init
in object_initializer
) {
345 init
.check (analyzer
);
348 if (get_argument_list ().size
== 0) {
350 Report
.error (source_reference
, "Too few arguments, errors need at least 1 argument");
352 Iterator
<Expression
> arg_it
= get_argument_list ().iterator ();
354 var ex
= arg_it
.get ();
355 if (ex
.value_type
== null || !ex
.value_type
.compatible (analyzer
.string_type
)) {
357 Report
.error (source_reference
, "Invalid type for argument 1");
362 foreach (MemberInitializer init
in get_object_initializer ()) {
363 analyzer
.visit_member_initializer (init
, type_reference
);
369 public override void get_defined_variables (Collection
<LocalVariable
> collection
) {
370 foreach (Expression arg
in argument_list
) {
371 arg
.get_defined_variables (collection
);
375 public override void get_used_variables (Collection
<LocalVariable
> collection
) {
376 foreach (Expression arg
in argument_list
) {
377 arg
.get_used_variables (collection
);