Improve string tests
[vala-lang.git] / vala / valaobjectcreationexpression.vala
blob57a580a8ce7e1f868fa66a4fde7800f37777ca85
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
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
24 using Gee;
26 /**
27 * Represents an object creation expression in the source code.
29 public class Vala.ObjectCreationExpression : Expression {
30 /**
31 * The object type to create.
33 public DataType type_reference {
34 get { return _data_type; }
35 set {
36 _data_type = value;
37 _data_type.parent_node = this;
41 /**
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; }
47 /**
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;
61 /**
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;
73 /**
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;
83 /**
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);
92 /**
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 () {
144 return false;
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) {
154 if (checked) {
155 return !error;
158 checked = true;
160 if (member_name != null) {
161 member_name.check (analyzer);
164 TypeSymbol type = null;
166 if (type_reference == null) {
167 if (member_name == null) {
168 error = true;
169 Report.error (source_reference, "Incomplete object creation expression");
170 return false;
173 if (member_name.symbol_reference == null) {
174 error = true;
175 return false;
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)) {
188 error = true;
189 Report.error (source_reference, "`%s' is not a creation method".printf (constructor.get_full_name ()));
190 return false;
193 symbol_reference = constructor;
195 // inner expression can also be base access when chaining constructors
196 var ma = member_name.inner as MemberAccess;
197 if (ma != null) {
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;
211 } else {
212 error = true;
213 Report.error (source_reference, "`%s' is not a class, struct, or error code".printf (type_sym.get_full_name ()));
214 return false;
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);
222 } else {
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;
234 if (type is Class) {
235 var cl = (Class) type;
237 expected_num_type_args = cl.get_type_parameters ().size;
239 if (struct_creation) {
240 error = true;
241 Report.error (source_reference, "syntax error, use `new' to create new objects");
242 return false;
245 if (cl.is_abstract) {
246 value_type = null;
247 error = true;
248 Report.error (source_reference, "Can't create instance of abstract class `%s'".printf (cl.get_full_name ()));
249 return false;
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;
261 while (cl != null) {
262 if (cl == analyzer.initially_unowned_type) {
263 value_type.floating_reference = true;
264 break;
267 cl = cl.base_class;
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) {
284 error = true;
285 Report.error (source_reference, "too few type arguments");
286 return false;
287 } else if (expected_num_type_args < given_num_type_args) {
288 error = true;
289 Report.error (source_reference, "too many type arguments");
290 return false;
293 if (symbol_reference == null && get_argument_list ().size != 0) {
294 value_type = null;
295 error = true;
296 Report.error (source_reference, "No arguments allowed when constructing type `%s'".printf (type.get_full_name ()));
297 return false;
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) {
307 break;
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) {
349 error = true;
350 Report.error (source_reference, "Too few arguments, errors need at least 1 argument");
351 } else {
352 Iterator<Expression> arg_it = get_argument_list ().iterator ();
353 arg_it.next ();
354 var ex = arg_it.get ();
355 if (ex.value_type == null || !ex.value_type.compatible (analyzer.string_type)) {
356 error = true;
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);
366 return !error;
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);