Insert "%s" argument in printf calls with non-literal format string
[vala-lang.git] / vala / valadatatype.vala
blobfc4791b4edfe8530455aeca45d16e04519281c98
1 /* valadatatype.vala
3 * Copyright (C) 2006-2009 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 using GLib;
26 using Gee;
28 /**
29 * A reference to a data type. This is used to specify static types of
30 * expressions.
32 public abstract class Vala.DataType : CodeNode {
33 /**
34 * Specifies that the expression or variable owns the value.
36 public bool value_owned { get; set; }
38 /**
39 * Specifies that the expression may be null.
41 public bool nullable { get; set; }
43 /**
44 * The referred data type.
46 public weak TypeSymbol data_type { get; set; }
48 /**
49 * The referred generic type parameter.
51 public TypeParameter type_parameter { get; set; }
53 /**
54 * Specifies that the expression transfers a floating reference.
56 public bool floating_reference { get; set; }
58 /**
59 * Specifies that the type supports dynamic lookup.
61 public bool is_dynamic { get; set; }
63 private Gee.List<DataType> type_argument_list;
64 private static Gee.List<DataType> _empty_type_list;
66 /**
67 * Appends the specified type as generic type argument.
69 * @param arg a type reference
71 public void add_type_argument (DataType arg) {
72 if (type_argument_list == null) {
73 type_argument_list = new ArrayList<DataType> ();
75 type_argument_list.add (arg);
76 arg.parent_node = this;
79 /**
80 * Returns a copy of the list of generic type arguments.
82 * @return type argument list
84 public Gee.List<DataType> get_type_arguments () {
85 if (type_argument_list != null) {
86 return type_argument_list;
88 if (_empty_type_list == null) {
89 _empty_type_list = new ReadOnlyList<DataType> (new ArrayList<DataType> ());
91 return _empty_type_list;
94 /**
95 * Removes all generic type arguments.
97 public void remove_all_type_arguments () {
98 type_argument_list = null;
101 public override void accept (CodeVisitor visitor) {
102 if (type_argument_list != null && type_argument_list.size > 0) {
103 foreach (DataType type_arg in type_argument_list) {
104 type_arg.accept (visitor);
108 visitor.visit_data_type (this);
112 * Returns the name and qualifiers of this type as it is used in C code.
114 * @return the type string to be used in C code
116 public virtual string? get_cname () {
117 // raise error
118 Report.error (source_reference, "unresolved type reference");
119 return null;
122 public virtual string get_cdeclarator_suffix () {
123 return "";
127 * Returns the name and qualifiers of this type as it is used in C code
128 * in a const declaration.
130 * @return the type string to be used in C code const declarations
132 public string get_const_cname () {
133 string ptr;
134 TypeSymbol t;
135 // FIXME: workaround to make constant arrays possible
136 if (this is ArrayType) {
137 t = ((ArrayType) this).element_type.data_type;
138 } else {
139 t = data_type;
141 if (!t.is_reference_type ()) {
142 ptr = "";
143 } else {
144 ptr = "*";
147 return "const %s%s".printf (t.get_cname (), ptr);
151 * Returns the C name of this data type in lower case. Words are
152 * separated by underscores.
154 * @param infix a string to be placed between namespace and data type
155 * name or null
156 * @return the lower case name to be used in C code
158 public virtual string? get_lower_case_cname (string? infix = null) {
159 return data_type.get_lower_case_cname (infix);
162 public override string to_string () {
163 return to_qualified_string (null);
166 public virtual string to_qualified_string (Scope? scope = null) {
167 string s;
169 if (data_type != null) {
170 Symbol global_symbol = data_type;
171 while (global_symbol.parent_symbol.name != null) {
172 global_symbol = global_symbol.parent_symbol;
175 Symbol sym = null;
176 Scope parent_scope = scope;
177 while (sym == null && parent_scope != null) {
178 sym = parent_scope.lookup (global_symbol.name);
179 parent_scope = parent_scope.parent_scope;
182 if (sym != null && global_symbol != sym) {
183 s = "global::" + data_type.get_full_name ();;
184 } else {
185 s = data_type.get_full_name ();
187 } else {
188 s = "null";
191 var type_args = get_type_arguments ();
192 if (type_args.size > 0) {
193 s += "<";
194 bool first = true;
195 foreach (DataType type_arg in type_args) {
196 if (!first) {
197 s += ",";
198 } else {
199 first = false;
201 if (!type_arg.value_owned) {
202 s += "weak ";
204 s += type_arg.to_qualified_string (scope);
206 s += ">";
208 if (nullable) {
209 s += "?";
212 return s;
216 * Creates a shallow copy of this type reference.
218 * @return copy of this type reference
220 public abstract DataType copy ();
223 * Checks two type references for equality. May only be used with
224 * resolved type references.
226 * @param type2 a type reference
227 * @return true if this type reference is equal to type2, false
228 * otherwise
230 public virtual bool equals (DataType type2) {
231 if (type2.value_owned != value_owned) {
232 return false;
234 if (type2.nullable != nullable) {
235 return false;
237 if (type2.data_type != data_type) {
238 return false;
240 if (type2.type_parameter != null || type_parameter != null) {
241 if (type2.type_parameter == null || type_parameter == null) {
242 return false;
244 if (!type2.type_parameter.equals (type_parameter)) {
245 return false;
248 if (type2.floating_reference != floating_reference) {
249 return false;
252 return true;
256 * Checks whether this type reference is at least as strict as the
257 * specified type reference type2.
259 * @param type2 a type reference
260 * @return true if this type reference is stricter or equal
262 public virtual bool stricter (DataType type2) {
263 if (type2.value_owned != value_owned) {
264 return false;
267 if (!type2.nullable && nullable) {
268 return false;
271 /* temporarily ignore type parameters */
272 if (type_parameter != null || type2.type_parameter != null) {
273 return true;
276 if (type2.data_type != data_type) {
277 // FIXME: allow this type reference to refer to a
278 // subtype of the type type2 is referring to
279 return false;
282 if (type2.floating_reference != floating_reference) {
283 return false;
286 return true;
289 public override void replace_type (DataType old_type, DataType new_type) {
290 if (type_argument_list != null) {
291 for (int i = 0; i < type_argument_list.size; i++) {
292 if (type_argument_list[i] == old_type) {
293 type_argument_list[i] = new_type;
294 return;
300 public virtual bool compatible (DataType target_type) {
301 if (target_type.get_type_id () == "G_TYPE_VALUE" && get_type_id () != null) {
302 // allow implicit conversion to GValue
303 return true;
306 if (target_type is DelegateType && this is DelegateType) {
307 return ((DelegateType) target_type).delegate_symbol == ((DelegateType) this).delegate_symbol;
310 if (target_type is PointerType) {
311 /* any reference or array type or pointer type can be cast to a generic pointer */
312 if (type_parameter != null ||
313 (data_type != null && (
314 data_type.is_reference_type () ||
315 this is DelegateType))) {
316 return true;
319 return false;
322 /* temporarily ignore type parameters */
323 if (target_type.type_parameter != null) {
324 return true;
327 if (this is ArrayType != target_type is ArrayType) {
328 return false;
331 if (data_type is Enum && target_type.data_type is Struct && ((Struct) target_type.data_type).is_integer_type ()) {
332 return true;
335 if (data_type == target_type.data_type) {
336 // check compatibility of generic type arguments
337 if (type_argument_list != null
338 && type_argument_list.size > 0
339 && type_argument_list.size == target_type.get_type_arguments ().size) {
340 for (int i = 0; i < type_argument_list.size; i++) {
341 var type_arg = type_argument_list[i];
342 var target_type_arg = target_type.get_type_arguments ()[i];
343 // mutable generic types require type argument equality,
344 // not just one way compatibility
345 // as we do not currently have immutable generic container types,
346 // the additional check would be very inconvenient, so we
347 // skip the additional check for now
348 if (!type_arg.compatible (target_type_arg)) {
349 return false;
353 return true;
356 if (data_type is Struct && target_type.data_type is Struct) {
357 var expr_struct = (Struct) data_type;
358 var expect_struct = (Struct) target_type.data_type;
360 /* integer types may be implicitly cast to floating point types */
361 if (expr_struct.is_integer_type () && expect_struct.is_floating_type ()) {
362 return true;
365 if ((expr_struct.is_integer_type () && expect_struct.is_integer_type ()) ||
366 (expr_struct.is_floating_type () && expect_struct.is_floating_type ())) {
367 if (expr_struct.get_rank () <= expect_struct.get_rank ()) {
368 return true;
373 if (data_type != null && target_type.data_type != null && data_type.is_subtype_of (target_type.data_type)) {
374 return true;
377 return false;
381 * Returns whether instances of this type are invokable.
383 * @return true if invokable, false otherwise
385 public virtual bool is_invokable () {
386 return false;
390 * Returns the return type of this invokable.
392 * @return return type
394 public virtual DataType? get_return_type () {
395 return null;
399 * Returns copy of the list of invocation parameters.
401 * @return parameter list
403 public virtual Gee.List<FormalParameter>? get_parameters () {
404 return null;
407 public virtual bool is_reference_type_or_type_parameter () {
408 return (data_type != null &&
409 data_type.is_reference_type ()) ||
410 type_parameter != null;
413 public virtual bool is_array () {
414 return false;
418 * Returns a list of symbols that define this type.
420 * @return symbol list
422 public virtual Gee.List<Symbol> get_symbols () {
423 var symbols = new ArrayList<Symbol> ();
424 if (data_type != null) {
425 symbols.add (data_type);
427 return symbols;
430 public virtual Symbol? get_member (string member_name) {
431 if (data_type != null) {
432 return SemanticAnalyzer.symbol_lookup_inherited (data_type, member_name);
434 return null;
437 public virtual Symbol? get_pointer_member (string member_name) {
438 return null;
442 * Checks whether this data type references a real struct. A real struct
443 * is a struct which is not a simple (fundamental) type.
445 public virtual bool is_real_struct_type () {
446 var s = data_type as Struct;
447 if (s != null && !s.is_simple_type ()) {
448 return true;
450 return false;
453 public bool is_real_non_null_struct_type () {
454 return is_real_struct_type () && !nullable;
457 public virtual string? get_type_id () {
458 if (data_type != null) {
459 return data_type.get_type_id ();
460 } else {
461 return null;
466 * Returns type signature as used for GVariant and D-Bus.
468 public virtual string? get_type_signature () {
469 if (data_type != null) {
470 string sig = data_type.get_type_signature ();
472 var type_args = get_type_arguments ();
473 if (sig != null && sig.str ("%s") != null && type_args.size > 0) {
474 string element_sig = "";
475 foreach (DataType type_arg in type_args) {
476 var s = type_arg.get_type_signature ();
477 if (s != null) {
478 element_sig += s;
482 sig = sig.printf (element_sig);
485 return sig;
486 } else {
487 return null;
492 * Returns whether the value needs to be disposed, i.e. whether
493 * allocated memory or other resources need to be released when
494 * the value is no longer needed.
496 public virtual bool is_disposable () {
497 if (!value_owned) {
498 return false;
501 if (is_reference_type_or_type_parameter ()) {
502 return true;
504 return false;
507 public DataType get_actual_type (DataType? derived_instance_type, MemberAccess? method_access, CodeNode node_reference) {
508 if (derived_instance_type == null && method_access == null) {
509 return this;
512 DataType result = this;
514 if (result is GenericType) {
515 result = SemanticAnalyzer.get_actual_type (derived_instance_type, method_access, (GenericType) result, node_reference);
516 // don't try to resolve type arguments of returned actual type
517 // they can never be resolved and are not related to the instance type
518 } else if (result.type_argument_list != null) {
519 // recursely get actual types for type arguments
520 result = result.copy ();
521 for (int i = 0; i < result.type_argument_list.size; i++) {
522 result.type_argument_list[i] = result.type_argument_list[i].get_actual_type (derived_instance_type, method_access, node_reference);
526 return result;