pango: mark several arguments as out
[vala-lang.git] / vala / valainterface.vala
blobdc7248c77d84606bfc6027271c6f73a904506bcd
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 FormalParameter ("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 FormalParameter ("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.offset ("type_".length);
325 } else if (result.has_prefix ("is_")) {
326 result = "is" + result.offset ("is_".length);
328 if (result.has_suffix ("_class")) {
329 result = result.substring (0, result.length - "_class".length) + "class";
332 return result;
336 * Sets the string to be prepended to the name of members of this
337 * interface when used in C code.
339 * @param csuffix the suffix to be used in C code
341 public void set_lower_case_csuffix (string csuffix) {
342 this.lower_case_csuffix = csuffix;
345 public override string? get_lower_case_cname (string? infix) {
346 if (infix == null) {
347 infix = "";
349 return "%s%s%s".printf (parent_symbol.get_lower_case_cprefix (), infix, get_lower_case_csuffix ());
352 public override string get_lower_case_cprefix () {
353 return "%s_".printf (get_lower_case_cname (null));
356 public override string? get_upper_case_cname (string? infix) {
357 return get_lower_case_cname (infix).up ();
360 public override void accept (CodeVisitor visitor) {
361 visitor.visit_interface (this);
364 public override void accept_children (CodeVisitor visitor) {
365 foreach (DataType type in prerequisites) {
366 type.accept (visitor);
369 foreach (TypeParameter p in get_type_parameters ()) {
370 p.accept (visitor);
373 /* process enums first to avoid order problems in C code */
374 foreach (Enum en in enums) {
375 en.accept (visitor);
378 foreach (Method m in methods) {
379 m.accept (visitor);
382 foreach (Field f in fields) {
383 f.accept (visitor);
386 foreach (Constant c in constants) {
387 c.accept (visitor);
390 foreach (Property prop in properties) {
391 prop.accept (visitor);
394 foreach (Signal sig in signals) {
395 sig.accept (visitor);
398 foreach (Class cl in classes) {
399 cl.accept (visitor);
402 foreach (Struct st in structs) {
403 st.accept (visitor);
406 foreach (Delegate d in delegates) {
407 d.accept (visitor);
411 public override bool is_reference_type () {
412 return true;
415 public override bool is_reference_counting () {
416 return true;
419 public override string? get_ref_function () {
420 foreach (DataType prerequisite in prerequisites) {
421 string ref_func = prerequisite.data_type.get_ref_function ();
422 if (ref_func != null) {
423 return ref_func;
426 return null;
429 public override string? get_unref_function () {
430 foreach (DataType prerequisite in prerequisites) {
431 string unref_func = prerequisite.data_type.get_unref_function ();
432 if (unref_func != null) {
433 return unref_func;
436 return null;
439 public override string? get_ref_sink_function () {
440 foreach (DataType prerequisite in prerequisites) {
441 string ref_sink_func = prerequisite.data_type.get_ref_sink_function ();
442 if (ref_sink_func != null) {
443 return ref_sink_func;
446 return null;
449 public override bool is_subtype_of (TypeSymbol t) {
450 if (this == t) {
451 return true;
454 foreach (DataType prerequisite in prerequisites) {
455 if (prerequisite.data_type != null && prerequisite.data_type.is_subtype_of (t)) {
456 return true;
460 return false;
463 private void process_ccode_attribute (Attribute a) {
464 if (a.has_argument ("type_cname")) {
465 set_type_cname (a.get_string ("type_cname"));
467 if (a.has_argument ("cheader_filename")) {
468 var val = a.get_string ("cheader_filename");
469 foreach (string filename in val.split (",")) {
470 add_cheader_filename (filename);
473 if (a.has_argument ("lower_case_csuffix")) {
474 lower_case_csuffix = a.get_string ("lower_case_csuffix");
479 * Process all associated attributes.
481 public void process_attributes () {
482 foreach (Attribute a in attributes) {
483 if (a.name == "CCode") {
484 process_ccode_attribute (a);
485 } else if (a.name == "Deprecated") {
486 process_deprecated_attribute (a);
492 * Returns the name of the type struct as it is used in C code.
494 * @return the type struct name to be used in C code
496 public string get_type_cname () {
497 if (type_cname == null) {
498 type_cname = "%sIface".printf (get_cname ());
500 return type_cname;
504 * Sets the name of the type struct as it is used in C code.
506 * @param type_cname the type struct name to be used in C code
508 public void set_type_cname (string type_cname) {
509 this.type_cname = type_cname;
512 public override string? get_marshaller_type_name () {
513 foreach (DataType prerequisite in prerequisites) {
514 string type_name = prerequisite.data_type.get_marshaller_type_name ();
515 if (type_name != null) {
516 return type_name;
519 return null;
522 public override string? get_get_value_function () {
523 foreach (DataType prerequisite in prerequisites) {
524 string get_value_func = prerequisite.data_type.get_get_value_function ();
525 if (get_value_func != null) {
526 return get_value_func;
529 return null;
532 public override string? get_set_value_function () {
533 foreach (DataType prerequisite in prerequisites) {
534 string set_value_func = prerequisite.data_type.get_set_value_function ();
535 if (set_value_func != null) {
536 return set_value_func;
539 return null;
542 public override string? get_take_value_function () {
543 foreach (DataType prerequisite in prerequisites) {
544 string take_value_func = prerequisite.data_type.get_take_value_function ();
545 if (take_value_func != null) {
546 return take_value_func;
549 return null;
552 public override string? get_type_id () {
553 if (type_id == null) {
554 type_id = get_upper_case_cname ("TYPE_");
557 return type_id;
560 public override void replace_type (DataType old_type, DataType new_type) {
561 for (int i = 0; i < prerequisites.size; i++) {
562 if (prerequisites[i] == old_type) {
563 prerequisites[i] = new_type;
564 return;
569 public override string? get_param_spec_function () {
570 foreach (DataType prerequisite in prerequisites) {
571 var prereq = prerequisite as ObjectType;
572 var cl = prereq.type_symbol as Class;
573 if (cl != null) {
574 return cl.get_param_spec_function ();
576 var interf = prereq.type_symbol as Interface;
577 if (interf != null) {
578 var param_spec_function = interf.get_param_spec_function ();
579 if (param_spec_function != null) {
580 return param_spec_function;
585 return null;
588 public override bool check (SemanticAnalyzer analyzer) {
589 if (checked) {
590 return !error;
593 checked = true;
595 process_attributes ();
597 var old_source_file = analyzer.current_source_file;
598 var old_symbol = analyzer.current_symbol;
600 if (source_reference != null) {
601 analyzer.current_source_file = source_reference.file;
603 analyzer.current_symbol = this;
605 foreach (DataType prerequisite_reference in get_prerequisites ()) {
606 // check whether prerequisite is at least as accessible as the interface
607 if (!analyzer.is_type_accessible (this, prerequisite_reference)) {
608 error = true;
609 Report.error (source_reference, "prerequisite `%s` is less accessible than interface `%s`".printf (prerequisite_reference.to_string (), get_full_name ()));
610 return false;
614 /* check prerequisites */
615 Class prereq_class = null;
616 foreach (DataType prereq in get_prerequisites ()) {
617 TypeSymbol class_or_interface = prereq.data_type;
618 /* skip on previous errors */
619 if (class_or_interface == null) {
620 error = true;
621 continue;
624 if (!(class_or_interface is ObjectTypeSymbol)) {
625 error = true;
626 Report.error (source_reference, "Prerequisite `%s` of interface `%s` is not a class or interface".printf (get_full_name (), class_or_interface.to_string ()));
627 return false;
630 /* interfaces are not allowed to have multiple instantiable prerequisites */
631 if (class_or_interface is Class) {
632 if (prereq_class != null) {
633 error = true;
634 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 ()));
635 return false;
638 prereq_class = (Class) class_or_interface;
642 foreach (DataType type in prerequisites) {
643 type.check (analyzer);
646 foreach (TypeParameter p in get_type_parameters ()) {
647 p.check (analyzer);
650 foreach (Enum en in enums) {
651 en.check (analyzer);
654 foreach (Method m in methods) {
655 m.check (analyzer);
658 foreach (Field f in fields) {
659 f.check (analyzer);
662 foreach (Constant c in constants) {
663 c.check (analyzer);
666 foreach (Property prop in properties) {
667 prop.check (analyzer);
670 foreach (Signal sig in signals) {
671 sig.check (analyzer);
674 foreach (Class cl in classes) {
675 cl.check (analyzer);
678 foreach (Struct st in structs) {
679 st.check (analyzer);
682 foreach (Delegate d in delegates) {
683 d.check (analyzer);
686 analyzer.current_source_file = old_source_file;
687 analyzer.current_symbol = old_symbol;
689 return !error;