codegen: Fix freeing of owned parameters
[vala-lang.git] / vala / valainterface.vala
blob2c98426d5b4fe890205bf5222666953a17a1d41f
1 /* valainterface.vala
3 * Copyright (C) 2006-2010 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;
25 /**
26 * Represents a class declaration in the source code.
28 public class Vala.Interface : ObjectTypeSymbol {
29 private List<DataType> prerequisites = new ArrayList<DataType> ();
31 private List<Method> methods = new ArrayList<Method> ();
32 private List<Field> fields = new ArrayList<Field> ();
33 private List<Constant> constants = new ArrayList<Constant> ();
34 private List<Property> properties = new ArrayList<Property> ();
35 private List<Signal> signals = new ArrayList<Signal> ();
37 // inner types
38 private List<Class> classes = new ArrayList<Class> ();
39 private List<Struct> structs = new ArrayList<Struct> ();
40 private List<Enum> enums = new ArrayList<Enum> ();
41 private List<Delegate> delegates = new ArrayList<Delegate> ();
43 private string cname;
44 private string lower_case_csuffix;
45 private string type_cname;
46 private string type_id;
48 /**
49 * Returns a copy of the list of classes.
51 * @return list of classes
53 public List<Class> get_classes () {
54 return classes;
57 /**
58 * Returns a copy of the list of structs.
60 * @return list of structs
62 public List<Struct> get_structs () {
63 return structs;
66 /**
67 * Returns a copy of the list of enums.
69 * @return list of enums
71 public List<Enum> get_enums () {
72 return enums;
75 /**
76 * Returns a copy of the list of delegates.
78 * @return list of delegates
80 public List<Delegate> get_delegates () {
81 return delegates;
84 /**
85 * Creates a new interface.
87 * @param name type name
88 * @param source reference to source code
89 * @return newly created interface
91 public Interface (string name, SourceReference? source_reference = null, Comment? comment = null) {
92 base (name, source_reference, comment);
95 /**
96 * Adds the specified interface or class to the list of prerequisites of
97 * this interface.
99 * @param type an interface or class reference
101 public void add_prerequisite (DataType type) {
102 prerequisites.add (type);
103 type.parent_node = this;
107 * Prepends the specified interface or class to the list of
108 * prerequisites of this interface.
110 * @param type an interface or class reference
112 public void prepend_prerequisite (DataType type) {
113 prerequisites.insert (0, type);
117 * Returns a copy of the base type list.
119 * @return list of base types
121 public List<DataType> get_prerequisites () {
122 return prerequisites;
126 * Adds the specified method as a member to this interface.
128 * @param m a method
130 public override void add_method (Method m) {
131 if (m is CreationMethod) {
132 Report.error (m.source_reference, "construction methods may only be declared within classes and structs");
134 m.error = true;
135 return;
137 if (m.binding == MemberBinding.INSTANCE) {
138 m.this_parameter = new Parameter ("this", get_this_type ());
139 m.scope.add (m.this_parameter.name, m.this_parameter);
141 if (!(m.return_type is VoidType) && (CodeContext.get ().profile == Profile.DOVA || m.get_postconditions ().size > 0)) {
142 m.result_var = new LocalVariable (m.return_type.copy (), "result", null, source_reference);
143 m.result_var.is_result = true;
146 methods.add (m);
147 scope.add (m.name, m);
151 * Returns a copy of the list of methods.
153 * @return list of methods
155 public override List<Method> get_methods () {
156 return methods;
160 * Adds the specified field as a member to this interface. The field
161 * must be private and static.
163 * @param f a field
165 public override void add_field (Field f) {
166 fields.add (f);
167 scope.add (f.name, f);
171 * Returns a copy of the list of fields.
173 * @return list of fields
175 public List<Field> get_fields () {
176 return fields;
180 * Adds the specified constant as a member to this interface.
182 * @param c a constant
184 public override void add_constant (Constant c) {
185 constants.add (c);
186 scope.add (c.name, c);
190 * Returns a copy of the list of constants.
192 * @return list of constants
194 public List<Constant> get_constants () {
195 return constants;
199 * Adds the specified property as a member to this interface.
201 * @param prop a property
203 public override void add_property (Property prop) {
204 properties.add (prop);
205 scope.add (prop.name, prop);
207 prop.this_parameter = new Parameter ("this", new ObjectType (this));
208 prop.scope.add (prop.this_parameter.name, prop.this_parameter);
212 * Returns a copy of the list of properties.
214 * @return list of properties
216 public override List<Property> get_properties () {
217 return properties;
221 * Adds the specified signal as a member to this interface.
223 * @param sig a signal
225 public override void add_signal (Signal sig) {
226 signals.add (sig);
227 scope.add (sig.name, sig);
231 * Returns a copy of the list of signals.
233 * @return list of signals
235 public override List<Signal> get_signals () {
236 return signals;
240 * Adds the specified class as an inner class.
242 * @param cl a class
244 public override void add_class (Class cl) {
245 classes.add (cl);
246 scope.add (cl.name, cl);
250 * Adds the specified struct as an inner struct.
252 * @param st a struct
254 public override void add_struct (Struct st) {
255 structs.add (st);
256 scope.add (st.name, st);
260 * Adds the specified enum as an inner enum.
262 * @param en an enum
264 public override void add_enum (Enum en) {
265 enums.add (en);
266 scope.add (en.name, en);
270 * Adds the specified delegate as an inner delegate.
272 * @param d a delegate
274 public override void add_delegate (Delegate d) {
275 delegates.add (d);
276 scope.add (d.name, d);
279 public override string get_cprefix () {
280 return get_cname ();
283 public override string get_cname (bool const_type = false) {
284 if (cname == null) {
285 var attr = get_attribute ("CCode");
286 if (attr != null) {
287 cname = attr.get_string ("cname");
289 if (cname == null) {
290 cname = "%s%s".printf (parent_symbol.get_cprefix (), name);
293 return cname;
296 public void set_cname (string cname) {
297 this.cname = cname;
301 * Returns the string to be prepended to the name of members of this
302 * interface when used in C code.
304 * @return the suffix to be used in C code
306 public string get_lower_case_csuffix () {
307 if (lower_case_csuffix == null) {
308 lower_case_csuffix = get_default_lower_case_csuffix ();
310 return lower_case_csuffix;
314 * Returns default string to be prepended to the name of members of this
315 * interface when used in C code.
317 * @return the suffix to be used in C code
319 public string get_default_lower_case_csuffix () {
320 string result = camel_case_to_lower_case (name);
322 // remove underscores in some cases to avoid conflicts of type macros
323 if (result.has_prefix ("type_")) {
324 result = "type" + result.substring ("type_".length);
325 } else if (result.has_prefix ("is_")) {
326 result = "is" + result.substring ("is_".length);
328 if (result.has_suffix ("_class")) {
329 result = result.substring (0, result.length - "_class".length) + "class";
332 return result;
336 * Returns default string for the type struct when used in C code.
338 * @return the type struct to be used in C code
340 public string get_default_type_cname () {
341 return "%sIface".printf (get_cname ());
345 * Sets the string to be prepended to the name of members of this
346 * interface when used in C code.
348 * @param csuffix the suffix to be used in C code
350 public void set_lower_case_csuffix (string csuffix) {
351 this.lower_case_csuffix = csuffix;
354 public override string? get_lower_case_cname (string? infix) {
355 if (infix == null) {
356 infix = "";
358 return "%s%s%s".printf (parent_symbol.get_lower_case_cprefix (), infix, get_lower_case_csuffix ());
361 public override string get_lower_case_cprefix () {
362 return "%s_".printf (get_lower_case_cname (null));
365 public override string? get_upper_case_cname (string? infix) {
366 return get_lower_case_cname (infix).up ();
369 public override void accept (CodeVisitor visitor) {
370 visitor.visit_interface (this);
373 public override void accept_children (CodeVisitor visitor) {
374 foreach (DataType type in prerequisites) {
375 type.accept (visitor);
378 foreach (TypeParameter p in get_type_parameters ()) {
379 p.accept (visitor);
382 /* process enums first to avoid order problems in C code */
383 foreach (Enum en in enums) {
384 en.accept (visitor);
387 foreach (Method m in methods) {
388 m.accept (visitor);
391 foreach (Field f in fields) {
392 f.accept (visitor);
395 foreach (Constant c in constants) {
396 c.accept (visitor);
399 foreach (Property prop in properties) {
400 prop.accept (visitor);
403 foreach (Signal sig in signals) {
404 sig.accept (visitor);
407 foreach (Class cl in classes) {
408 cl.accept (visitor);
411 foreach (Struct st in structs) {
412 st.accept (visitor);
415 foreach (Delegate d in delegates) {
416 d.accept (visitor);
420 public override bool is_reference_type () {
421 return true;
424 public override bool is_reference_counting () {
425 return true;
428 public override string? get_ref_function () {
429 foreach (DataType prerequisite in prerequisites) {
430 string ref_func = prerequisite.data_type.get_ref_function ();
431 if (ref_func != null) {
432 return ref_func;
435 return null;
438 public override string? get_unref_function () {
439 foreach (DataType prerequisite in prerequisites) {
440 string unref_func = prerequisite.data_type.get_unref_function ();
441 if (unref_func != null) {
442 return unref_func;
445 return null;
448 public override string? get_ref_sink_function () {
449 foreach (DataType prerequisite in prerequisites) {
450 string ref_sink_func = prerequisite.data_type.get_ref_sink_function ();
451 if (ref_sink_func != null) {
452 return ref_sink_func;
455 return null;
458 public override bool is_subtype_of (TypeSymbol t) {
459 if (this == t) {
460 return true;
463 foreach (DataType prerequisite in prerequisites) {
464 if (prerequisite.data_type != null && prerequisite.data_type.is_subtype_of (t)) {
465 return true;
469 return false;
472 private void process_ccode_attribute (Attribute a) {
473 if (a.has_argument ("type_cname")) {
474 set_type_cname (a.get_string ("type_cname"));
476 if (a.has_argument ("cheader_filename")) {
477 var val = a.get_string ("cheader_filename");
478 foreach (string filename in val.split (",")) {
479 add_cheader_filename (filename);
482 if (a.has_argument ("lower_case_csuffix")) {
483 lower_case_csuffix = a.get_string ("lower_case_csuffix");
488 * Process all associated attributes.
490 public void process_attributes () {
491 foreach (Attribute a in attributes) {
492 if (a.name == "CCode") {
493 process_ccode_attribute (a);
494 } else if (a.name == "Deprecated") {
495 process_deprecated_attribute (a);
496 } else if (a.name == "Experimental") {
497 process_experimental_attribute (a);
503 * Returns the name of the type struct as it is used in C code.
505 * @return the type struct name to be used in C code
507 public string get_type_cname () {
508 if (type_cname == null) {
509 type_cname = get_default_type_cname ();
511 return type_cname;
515 * Sets the name of the type struct as it is used in C code.
517 * @param type_cname the type struct name to be used in C code
519 public void set_type_cname (string type_cname) {
520 this.type_cname = type_cname;
523 public override string? get_marshaller_type_name () {
524 foreach (DataType prerequisite in prerequisites) {
525 string type_name = prerequisite.data_type.get_marshaller_type_name ();
526 if (type_name != null) {
527 return type_name;
530 return null;
533 public override string? get_get_value_function () {
534 foreach (DataType prerequisite in prerequisites) {
535 string get_value_func = prerequisite.data_type.get_get_value_function ();
536 if (get_value_func != null) {
537 return get_value_func;
540 return null;
543 public override string? get_set_value_function () {
544 foreach (DataType prerequisite in prerequisites) {
545 string set_value_func = prerequisite.data_type.get_set_value_function ();
546 if (set_value_func != null) {
547 return set_value_func;
550 return null;
553 public override string? get_take_value_function () {
554 foreach (DataType prerequisite in prerequisites) {
555 string take_value_func = prerequisite.data_type.get_take_value_function ();
556 if (take_value_func != null) {
557 return take_value_func;
560 return null;
563 public override string? get_type_id () {
564 if (type_id == null) {
565 type_id = get_upper_case_cname ("TYPE_");
568 return type_id;
571 public override void replace_type (DataType old_type, DataType new_type) {
572 for (int i = 0; i < prerequisites.size; i++) {
573 if (prerequisites[i] == old_type) {
574 prerequisites[i] = new_type;
575 return;
580 public override string? get_param_spec_function () {
581 foreach (DataType prerequisite in prerequisites) {
582 var prereq = prerequisite as ObjectType;
583 var cl = prereq.type_symbol as Class;
584 if (cl != null) {
585 return cl.get_param_spec_function ();
587 var interf = prereq.type_symbol as Interface;
588 if (interf != null) {
589 var param_spec_function = interf.get_param_spec_function ();
590 if (param_spec_function != null) {
591 return param_spec_function;
596 return null;
599 public override bool check (CodeContext context) {
600 if (checked) {
601 return !error;
604 checked = true;
606 process_attributes ();
608 var old_source_file = context.analyzer.current_source_file;
609 var old_symbol = context.analyzer.current_symbol;
611 if (source_reference != null) {
612 context.analyzer.current_source_file = source_reference.file;
614 context.analyzer.current_symbol = this;
616 foreach (DataType prerequisite_reference in get_prerequisites ()) {
617 // check whether prerequisite is at least as accessible as the interface
618 if (!context.analyzer.is_type_accessible (this, prerequisite_reference)) {
619 error = true;
620 Report.error (source_reference, "prerequisite `%s` is less accessible than interface `%s`".printf (prerequisite_reference.to_string (), get_full_name ()));
621 return false;
625 /* check prerequisites */
626 Class prereq_class = null;
627 foreach (DataType prereq in get_prerequisites ()) {
628 TypeSymbol class_or_interface = prereq.data_type;
629 /* skip on previous errors */
630 if (class_or_interface == null) {
631 error = true;
632 continue;
635 if (!(class_or_interface is ObjectTypeSymbol)) {
636 error = true;
637 Report.error (source_reference, "Prerequisite `%s` of interface `%s` is not a class or interface".printf (get_full_name (), class_or_interface.to_string ()));
638 return false;
641 /* interfaces are not allowed to have multiple instantiable prerequisites */
642 if (class_or_interface is Class) {
643 if (prereq_class != null) {
644 error = true;
645 Report.error (source_reference, "%s: Interfaces cannot have multiple instantiable prerequisites (`%s' and `%s')".printf (get_full_name (), class_or_interface.get_full_name (), prereq_class.get_full_name ()));
646 return false;
649 prereq_class = (Class) class_or_interface;
653 foreach (DataType type in prerequisites) {
654 type.check (context);
657 foreach (TypeParameter p in get_type_parameters ()) {
658 p.check (context);
661 foreach (Enum en in enums) {
662 en.check (context);
665 foreach (Method m in methods) {
666 m.check (context);
669 foreach (Field f in fields) {
670 f.check (context);
673 foreach (Constant c in constants) {
674 c.check (context);
677 foreach (Property prop in properties) {
678 prop.check (context);
681 foreach (Signal sig in signals) {
682 sig.check (context);
685 foreach (Class cl in classes) {
686 cl.check (context);
689 foreach (Struct st in structs) {
690 st.check (context);
693 foreach (Delegate d in delegates) {
694 d.check (context);
697 context.analyzer.current_source_file = old_source_file;
698 context.analyzer.current_symbol = old_symbol;
700 return !error;