Add support for async signal handlers
[vala-lang.git] / vala / valaclass.vala
blobd38135ce18778ffdecbdca3e9d5b306fad8ca280
1 /* valaclass.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.Class : ObjectTypeSymbol {
29 /**
30 * Specifies the base class.
32 public Class base_class { get; set; }
34 /**
35 * Specifies whether this class is abstract. Abstract classes may not be
36 * instantiated.
38 public bool is_abstract { get; set; }
40 /**
41 * Instances of compact classes are fast to create and have a
42 * compact memory layout. Compact classes don't support runtime
43 * type information or virtual methods.
45 public bool is_compact {
46 get {
47 if (base_class != null) {
48 return base_class.is_compact;
50 return _is_compact;
52 set {
53 _is_compact = value;
57 /**
58 * Instances of immutable classes are immutable after construction.
60 public bool is_immutable {
61 get {
62 if (base_class != null) {
63 return base_class.is_immutable;
65 return _is_immutable;
67 set {
68 _is_immutable = value;
72 /**
73 * Specifies wheather the ref function returns void instead of the
74 * object.
76 public bool ref_function_void {
77 get {
78 if (base_class != null) {
79 return base_class.ref_function_void;
81 return _ref_function_void;
83 set {
84 _ref_function_void = value;
88 /**
89 * The name of the function to use to check whether a value is an instance of
90 * this class. If this is null then the default type check function should be
91 * used instead.
93 public string? type_check_function { get; set; }
95 /**
96 * Specifies whether this class has private fields.
98 public bool has_private_fields { get; set; }
101 * Specifies whether this class has class fields.
103 public bool has_class_private_fields { get; private set; }
106 * Specifies whether the free function requires the address of a
107 * pointer instead of just the pointer.
109 public bool free_function_address_of { get; private set; }
111 public bool is_gboxed { get { return (free_function == "g_boxed_free"); } }
113 private string cname;
114 public string const_cname { get; set; }
115 private string lower_case_cprefix;
116 private string lower_case_csuffix;
117 private string type_id;
118 private string ref_function;
119 private string unref_function;
120 private bool _ref_function_void;
121 private string ref_sink_function;
122 private string param_spec_function;
123 private string copy_function;
124 private string free_function;
125 private string marshaller_type_name;
126 private string get_value_function;
127 private string set_value_function;
128 private string take_value_function;
129 private bool _is_compact;
130 private bool _is_immutable;
132 private List<DataType> base_types = new ArrayList<DataType> ();
134 private List<Constant> constants = new ArrayList<Constant> ();
135 private List<Field> fields = new ArrayList<Field> ();
136 private List<Method> methods = new ArrayList<Method> ();
137 private List<Property> properties = new ArrayList<Property> ();
138 private List<Signal> signals = new ArrayList<Signal> ();
140 // inner types
141 private List<Class> classes = new ArrayList<Class> ();
142 private List<Struct> structs = new ArrayList<Struct> ();
143 private List<Enum> enums = new ArrayList<Enum> ();
144 private List<Delegate> delegates = new ArrayList<Delegate> ();
147 * Returns a copy of the list of classes.
149 * @return list of classes
151 public List<Class> get_classes () {
152 return classes;
156 * Returns a copy of the list of structs.
158 * @return list of structs
160 public List<Struct> get_structs () {
161 return structs;
165 * Returns a copy of the list of enums.
167 * @return list of enums
169 public List<Enum> get_enums () {
170 return enums;
174 * Returns a copy of the list of delegates.
176 * @return list of delegates
178 public List<Delegate> get_delegates () {
179 return delegates;
183 * Specifies the default construction method.
185 public Method default_construction_method { get; set; }
188 * Specifies the instance constructor.
190 public Constructor constructor { get; set; }
193 * Specifies the class constructor.
195 public Constructor class_constructor { get; set; }
198 * Specifies the static class constructor.
200 public Constructor static_constructor { get; set; }
203 * Specifies the instance destructor.
205 public Destructor? destructor {
206 get { return _destructor; }
207 set {
208 _destructor = value;
209 if (_destructor != null) {
210 if (_destructor.this_parameter != null) {
211 _destructor.scope.remove (_destructor.this_parameter.name);
213 _destructor.this_parameter = new Parameter ("this", get_this_type ());
214 _destructor.scope.add (_destructor.this_parameter.name, _destructor.this_parameter);
220 * Specifies the class destructor.
222 public Destructor? static_destructor { get; set; }
225 * Specifies the class destructor.
227 public Destructor? class_destructor { get; set; }
230 * Specifies whether this class denotes an error base.
232 public bool is_error_base {
233 get {
234 return get_attribute ("ErrorBase") != null;
238 Destructor? _destructor;
241 * Creates a new class.
243 * @param name type name
244 * @param source reference to source code
245 * @param comment class documentation
246 * @return newly created class
248 public Class (string name, SourceReference? source_reference = null, Comment? comment = null) {
249 base (name, source_reference, comment);
253 * Adds the specified class or interface to the list of base types of
254 * this class.
256 * @param type a class or interface reference
258 public void add_base_type (DataType type) {
259 base_types.add (type);
260 type.parent_node = this;
264 * Returns a copy of the base type list.
266 * @return list of base types
268 public List<DataType> get_base_types () {
269 return base_types;
273 * Adds the specified constant as a member to this class.
275 * @param c a constant
277 public override void add_constant (Constant c) {
278 constants.add (c);
279 scope.add (c.name, c);
283 * Adds the specified field as a member to this class.
285 * @param f a field
287 public override void add_field (Field f) {
288 if (CodeContext.get ().profile == Profile.DOVA &&
289 f.binding == MemberBinding.INSTANCE &&
290 (f.access == SymbolAccessibility.PUBLIC || f.access == SymbolAccessibility.PROTECTED) &&
291 name != "any" /* temporary workaround */) {
292 // public/protected instance fields not supported, convert to automatic property
294 var prop = new Property (f.name, f.variable_type.copy (), null, null, f.source_reference, comment);
295 prop.access = access;
297 var get_type = prop.property_type.copy ();
298 get_type.value_owned = true;
300 prop.get_accessor = new PropertyAccessor (true, false, false, get_type, null, f.source_reference);
302 prop.set_accessor = new PropertyAccessor (false, true, false, prop.property_type.copy (), null, f.source_reference);
304 f.name = "_%s".printf (f.name);
305 f.access = SymbolAccessibility.PRIVATE;
306 prop.field = f;
308 add_property (prop);
309 return;
312 fields.add (f);
313 if (f.access == SymbolAccessibility.PRIVATE && f.binding == MemberBinding.INSTANCE) {
314 has_private_fields = true;
315 } else if (f.access == SymbolAccessibility.PRIVATE && f.binding == MemberBinding.CLASS) {
316 has_class_private_fields = true;
318 scope.add (f.name, f);
322 * Returns a copy of the list of fields.
324 * @return list of fields
326 public List<Field> get_fields () {
327 return fields;
331 * Returns a copy of the list of constants.
333 * @return list of constants
335 public List<Constant> get_constants () {
336 return constants;
340 * Adds the specified method as a member to this class.
342 * @param m a method
344 public override void add_method (Method m) {
345 if (m.binding == MemberBinding.INSTANCE || m is CreationMethod) {
346 if (m.this_parameter != null) {
347 m.scope.remove (m.this_parameter.name);
349 m.this_parameter = new Parameter ("this", get_this_type ());
350 m.scope.add (m.this_parameter.name, m.this_parameter);
352 if (!(m.return_type is VoidType) && (CodeContext.get ().profile == Profile.DOVA || m.get_postconditions ().size > 0)) {
353 if (m.result_var != null) {
354 m.scope.remove (m.result_var.name);
356 m.result_var = new LocalVariable (m.return_type.copy (), "result", null, source_reference);
357 m.result_var.is_result = true;
359 if (m is CreationMethod) {
360 if (m.name == null) {
361 default_construction_method = m;
362 m.name = ".new";
365 var cm = (CreationMethod) m;
366 if (cm.class_name != null && cm.class_name != name) {
367 // class_name is null for constructors generated by GIdlParser
368 Report.error (m.source_reference, "missing return type in method `%s.%s´".printf (get_full_name (), cm.class_name));
369 m.error = true;
370 return;
374 methods.add (m);
375 scope.add (m.name, m);
379 * Returns a copy of the list of methods.
381 * @return list of methods
383 public override List<Method> get_methods () {
384 return methods;
388 * Adds the specified property as a member to this class.
390 * @param prop a property
392 public override void add_property (Property prop) {
393 properties.add (prop);
394 scope.add (prop.name, prop);
396 prop.this_parameter = new Parameter ("this", get_this_type ());
397 prop.scope.add (prop.this_parameter.name, prop.this_parameter);
399 if (prop.field != null) {
400 add_field (prop.field);
405 * Returns a copy of the list of properties.
407 * @return list of properties
409 public override List<Property> get_properties () {
410 return properties;
414 * Adds the specified signal as a member to this class.
416 * @param sig a signal
418 public override void add_signal (Signal sig) {
419 signals.add (sig);
420 scope.add (sig.name, sig);
424 * Returns a copy of the list of signals.
426 * @return list of signals
428 public override List<Signal> get_signals () {
429 return signals;
433 * Adds the specified class as an inner class.
435 * @param cl a class
437 public override void add_class (Class cl) {
438 classes.add (cl);
439 scope.add (cl.name, cl);
443 * Adds the specified struct as an inner struct.
445 * @param st a struct
447 public override void add_struct (Struct st) {
448 structs.add (st);
449 scope.add (st.name, st);
453 * Adds the specified enum as an inner enum.
455 * @param en an enum
457 public override void add_enum (Enum en) {
458 enums.add (en);
459 scope.add (en.name, en);
463 * Adds the specified delegate as an inner delegate.
465 * @param d a delegate
467 public override void add_delegate (Delegate d) {
468 delegates.add (d);
469 scope.add (d.name, d);
472 public override void add_constructor (Constructor c) {
473 if (c.binding == MemberBinding.INSTANCE) {
474 if (constructor != null) {
475 Report.error (c.source_reference, "class already contains a constructor");
477 constructor = c;
478 } else if (c.binding == MemberBinding.CLASS) {
479 if (class_constructor != null) {
480 Report.error (c.source_reference, "class already contains a class constructor");
482 class_constructor = c;
483 } else {
484 if (static_constructor != null) {
485 Report.error (c.source_reference, "class already contains a static constructor");
487 static_constructor = c;
491 public override void add_destructor (Destructor d) {
492 if (d.binding == MemberBinding.INSTANCE) {
493 if (destructor != null) {
494 Report.error (d.source_reference, "class already contains a destructor");
496 destructor = d;
497 } else if (d.binding == MemberBinding.CLASS) {
498 if (class_destructor != null) {
499 Report.error (d.source_reference, "class already contains a class destructor");
501 class_destructor = d;
502 } else {
503 if (static_destructor != null) {
504 Report.error (d.source_reference, "class already contains a static destructor");
506 static_destructor = d;
510 public override void accept (CodeVisitor visitor) {
511 visitor.visit_class (this);
514 public override void accept_children (CodeVisitor visitor) {
515 foreach (DataType type in base_types) {
516 type.accept (visitor);
519 foreach (TypeParameter p in get_type_parameters ()) {
520 p.accept (visitor);
523 /* process enums first to avoid order problems in C code */
524 foreach (Enum en in enums) {
525 en.accept (visitor);
528 foreach (Field f in fields) {
529 f.accept (visitor);
532 foreach (Constant c in constants) {
533 c.accept (visitor);
536 foreach (Method m in methods) {
537 m.accept (visitor);
540 foreach (Property prop in properties) {
541 prop.accept (visitor);
544 foreach (Signal sig in signals) {
545 sig.accept (visitor);
548 if (constructor != null) {
549 constructor.accept (visitor);
552 if (class_constructor != null) {
553 class_constructor.accept (visitor);
556 if (static_constructor != null) {
557 static_constructor.accept (visitor);
560 if (destructor != null) {
561 destructor.accept (visitor);
564 if (static_destructor != null) {
565 static_destructor.accept (visitor);
568 if (class_destructor != null) {
569 class_destructor.accept (visitor);
572 foreach (Class cl in classes) {
573 cl.accept (visitor);
576 foreach (Struct st in structs) {
577 st.accept (visitor);
580 foreach (Delegate d in delegates) {
581 d.accept (visitor);
585 public override string get_cprefix () {
586 return get_cname ();
589 public override string get_cname (bool const_type = false) {
590 if (const_type) {
591 if (const_cname != null) {
592 return const_cname;
593 } else if (is_immutable) {
594 return "const " + get_cname (false);
598 if (cname == null) {
599 var attr = get_attribute ("CCode");
600 if (attr != null) {
601 cname = attr.get_string ("cname");
603 if (cname == null) {
604 cname = get_default_cname ();
607 return cname;
611 * Returns the default name of this class as it is used in C code.
613 * @return the name to be used in C code by default
615 public string get_default_cname () {
616 return "%s%s".printf (parent_symbol.get_cprefix (), name);
620 * Sets the name of this class as it is used in C code.
622 * @param cname the name to be used in C code
624 public void set_cname (string cname) {
625 this.cname = cname;
628 private string get_lower_case_csuffix () {
629 if (lower_case_csuffix == null) {
630 lower_case_csuffix = camel_case_to_lower_case (name);
632 // remove underscores in some cases to avoid conflicts of type macros
633 if (lower_case_csuffix.has_prefix ("type_")) {
634 lower_case_csuffix = "type" + lower_case_csuffix.substring ("type_".length);
635 } else if (lower_case_csuffix.has_prefix ("is_")) {
636 lower_case_csuffix = "is" + lower_case_csuffix.substring ("is_".length);
638 if (lower_case_csuffix.has_suffix ("_class")) {
639 lower_case_csuffix = lower_case_csuffix.substring (0, lower_case_csuffix.length - "_class".length) + "class";
642 return lower_case_csuffix;
645 public override string? get_lower_case_cname (string? infix) {
646 if (infix == null) {
647 infix = "";
649 return "%s%s%s".printf (parent_symbol.get_lower_case_cprefix (), infix, get_lower_case_csuffix ());
652 public override string get_lower_case_cprefix () {
653 if (lower_case_cprefix == null) {
654 lower_case_cprefix = "%s_".printf (get_lower_case_cname (null));
656 return lower_case_cprefix;
659 public override string? get_upper_case_cname (string? infix) {
660 return get_lower_case_cname (infix).up ();
663 public override bool is_reference_type () {
664 return true;
667 private void process_gir_attribute (Attribute a) {
668 if (a.has_argument ("name")) {
669 gir_name = a.get_string ("name");
673 private void process_ccode_attribute (Attribute a) {
674 if (a.has_argument ("ref_function")) {
675 set_ref_function (a.get_string ("ref_function"));
677 if (a.has_argument ("ref_function_void")) {
678 this.ref_function_void = a.get_bool ("ref_function_void");
680 if (a.has_argument ("unref_function")) {
681 set_unref_function (a.get_string ("unref_function"));
683 if (a.has_argument ("ref_sink_function")) {
684 set_ref_sink_function (a.get_string ("ref_sink_function"));
686 if (a.has_argument ("copy_function")) {
687 set_dup_function (a.get_string ("copy_function"));
689 if (a.has_argument ("free_function")) {
690 set_free_function (a.get_string ("free_function"));
692 if (a.has_argument ("free_function_address_of")) {
693 free_function_address_of = a.get_bool ("free_function_address_of");
695 if (a.has_argument ("type_id")) {
696 type_id = a.get_string ("type_id");
698 if (a.has_argument ("marshaller_type_name")) {
699 marshaller_type_name = a.get_string ("marshaller_type_name");
701 if (a.has_argument ("get_value_function")) {
702 get_value_function = a.get_string ("get_value_function");
704 if (a.has_argument ("set_value_function")) {
705 set_value_function = a.get_string ("set_value_function");
707 if (a.has_argument ("take_value_function")) {
708 take_value_function = a.get_string ("take_value_function");
711 if (a.has_argument ("const_cname")) {
712 const_cname = a.get_string ("const_cname");
714 if (a.has_argument ("cprefix")) {
715 lower_case_cprefix = a.get_string ("cprefix");
717 if (a.has_argument ("lower_case_csuffix")) {
718 lower_case_csuffix = a.get_string ("lower_case_csuffix");
720 if (a.has_argument ("cheader_filename")) {
721 var val = a.get_string ("cheader_filename");
722 foreach (string filename in val.split (",")) {
723 add_cheader_filename (filename);
726 if (a.has_argument ("type_check_function")) {
727 type_check_function = a.get_string ("type_check_function");
730 if (a.has_argument ("param_spec_function")) {
731 param_spec_function = a.get_string ("param_spec_function");
736 * Process all associated attributes.
738 public void process_attributes () {
739 foreach (Attribute a in attributes) {
740 if (a.name == "CCode") {
741 process_ccode_attribute (a);
742 } else if (a.name == "Compact") {
743 is_compact = true;
744 } else if (a.name == "Immutable") {
745 is_immutable = true;
746 } else if (a.name == "Deprecated") {
747 process_deprecated_attribute (a);
748 } else if (a.name == "GIR") {
749 process_gir_attribute (a);
754 public string? get_default_type_id () {
755 if (is_compact) {
756 return "G_TYPE_POINTER";
759 return get_upper_case_cname ("TYPE_");
762 public override string? get_type_id () {
763 if (type_id == null) {
764 type_id = get_default_type_id ();
767 return type_id;
770 public void set_type_id (string type_id) {
771 this.type_id = type_id;
774 public override string? get_marshaller_type_name () {
775 if (marshaller_type_name == null) {
776 if (base_class != null) {
777 marshaller_type_name = base_class.get_marshaller_type_name ();
778 } else if (!is_compact) {
779 marshaller_type_name = get_upper_case_cname ();
780 } else if (get_type_id () == "G_TYPE_POINTER") {
781 marshaller_type_name = "POINTER";
782 } else {
783 marshaller_type_name = "BOXED";
787 return marshaller_type_name;
790 public override string? get_param_spec_function () {
791 if (param_spec_function == null) {
792 param_spec_function = get_default_param_spec_function ();
795 return param_spec_function;
798 public string? get_default_param_spec_function () {
799 if (is_fundamental ()) {
800 return get_lower_case_cname ("param_spec_");
801 } else if (base_class != null) {
802 return base_class.get_param_spec_function ();
803 } else if (get_type_id () == "G_TYPE_POINTER") {
804 return "g_param_spec_pointer";
805 } else {
806 return "g_param_spec_boxed";
810 public override string? get_get_value_function () {
811 if (get_value_function == null) {
812 if (is_fundamental ()) {
813 get_value_function = get_lower_case_cname ("value_get_");
814 } else if (base_class != null) {
815 get_value_function = base_class.get_get_value_function ();
816 } else if (get_type_id () == "G_TYPE_POINTER") {
817 get_value_function = "g_value_get_pointer";
818 } else {
819 get_value_function = "g_value_get_boxed";
823 return get_value_function;
826 public override string? get_set_value_function () {
827 if (set_value_function == null) {
828 if (is_fundamental ()) {
829 set_value_function = get_lower_case_cname ("value_set_");
830 } else if (base_class != null) {
831 set_value_function = base_class.get_set_value_function ();
832 } else if (get_type_id () == "G_TYPE_POINTER") {
833 set_value_function = "g_value_set_pointer";
834 } else {
835 set_value_function = "g_value_set_boxed";
839 return set_value_function;
842 public override string? get_take_value_function () {
843 if (take_value_function == null) {
844 if (is_fundamental ()) {
845 take_value_function = get_lower_case_cname ("value_take_");
846 } else if (base_class != null) {
847 take_value_function = base_class.get_take_value_function ();
848 } else if (get_type_id () == "G_TYPE_POINTER") {
849 take_value_function = "g_value_set_pointer";
850 } else {
851 take_value_function = "g_value_take_boxed";
855 return take_value_function;
858 public override bool is_reference_counting () {
859 return get_ref_function () != null;
862 public bool is_fundamental () {
863 if (!is_compact && base_class == null) {
864 return true;
865 } else if (CodeContext.get ().profile == Profile.DOVA && base_class.base_class == null) {
866 return true;
868 return false;
871 public override string? get_ref_function () {
872 if (ref_function == null && is_fundamental ()) {
873 ref_function = get_lower_case_cprefix () + "ref";
876 if (ref_function == null && base_class != null) {
877 return base_class.get_ref_function ();
878 } else {
879 return ref_function;
883 public void set_ref_function (string? name) {
884 this.ref_function = name;
887 public override string? get_unref_function () {
888 if (unref_function == null && is_fundamental ()) {
889 unref_function = get_lower_case_cprefix () + "unref";
892 if (unref_function == null && base_class != null) {
893 return base_class.get_unref_function ();
894 } else {
895 return unref_function;
899 public void set_unref_function (string? name) {
900 this.unref_function = name;
903 public override string? get_ref_sink_function () {
904 if (ref_sink_function == null && base_class != null) {
905 return base_class.get_ref_sink_function ();
906 } else {
907 return ref_sink_function;
911 public void set_ref_sink_function (string? name) {
912 this.ref_sink_function = name;
915 public override string? get_dup_function () {
916 return copy_function;
919 public void set_dup_function (string? name) {
920 this.copy_function = name;
923 public string get_default_free_function () {
924 return get_lower_case_cprefix () + "free";
927 public override string? get_free_function () {
928 if (free_function == null) {
929 if (base_class != null) {
930 return base_class.get_free_function ();
932 free_function = get_default_free_function ();
934 return free_function;
937 public void set_free_function (string name) {
938 this.free_function = name;
941 public override bool is_subtype_of (TypeSymbol t) {
942 if (this == t) {
943 return true;
946 foreach (DataType base_type in base_types) {
947 if (base_type.data_type != null && base_type.data_type.is_subtype_of (t)) {
948 return true;
952 return false;
955 public override void replace_type (DataType old_type, DataType new_type) {
956 for (int i = 0; i < base_types.size; i++) {
957 if (base_types[i] == old_type) {
958 base_types[i] = new_type;
959 return;
964 private void get_all_prerequisites (Interface iface, List<TypeSymbol> list) {
965 foreach (DataType prereq in iface.get_prerequisites ()) {
966 TypeSymbol type = prereq.data_type;
967 /* skip on previous errors */
968 if (type == null) {
969 continue;
972 list.add (type);
973 if (type is Interface) {
974 get_all_prerequisites ((Interface) type, list);
980 private bool class_is_a (Class cl, TypeSymbol t) {
981 if (cl == t) {
982 return true;
985 foreach (DataType base_type in cl.get_base_types ()) {
986 if (base_type.data_type is Class) {
987 if (class_is_a ((Class) base_type.data_type, t)) {
988 return true;
990 } else if (base_type.data_type == t) {
991 return true;
995 return false;
998 public override bool check (CodeContext context) {
999 if (checked) {
1000 return !error;
1003 checked = true;
1005 process_attributes ();
1007 var old_source_file = context.analyzer.current_source_file;
1008 var old_symbol = context.analyzer.current_symbol;
1010 if (source_reference != null) {
1011 context.analyzer.current_source_file = source_reference.file;
1013 context.analyzer.current_symbol = this;
1015 foreach (DataType base_type_reference in get_base_types ()) {
1016 if (!base_type_reference.check (context)) {
1017 error = true;
1018 return false;
1021 if (!(base_type_reference is ObjectType)) {
1022 error = true;
1023 Report.error (source_reference, "base type `%s` of class `%s` is not an object type".printf (base_type_reference.to_string (), get_full_name ()));
1024 return false;
1027 // check whether base type is at least as accessible as the class
1028 if (!context.analyzer.is_type_accessible (this, base_type_reference)) {
1029 error = true;
1030 Report.error (source_reference, "base type `%s` is less accessible than class `%s`".printf (base_type_reference.to_string (), get_full_name ()));
1031 return false;
1034 int n_type_args = base_type_reference.get_type_arguments ().size;
1035 int n_type_params = ((ObjectTypeSymbol) base_type_reference.data_type).get_type_parameters ().size;
1036 if (n_type_args < n_type_params) {
1037 error = true;
1038 Report.error (base_type_reference.source_reference, "too few type arguments");
1039 return false;
1040 } else if (n_type_args > n_type_params) {
1041 error = true;
1042 Report.error (base_type_reference.source_reference, "too many type arguments");
1043 return false;
1047 foreach (DataType type in base_types) {
1048 type.check (context);
1051 foreach (TypeParameter p in get_type_parameters ()) {
1052 p.check (context);
1055 /* process enums first to avoid order problems in C code */
1056 foreach (Enum en in enums) {
1057 en.check (context);
1060 foreach (Field f in fields) {
1061 f.check (context);
1064 foreach (Constant c in constants) {
1065 c.check (context);
1068 foreach (Method m in methods) {
1069 m.check (context);
1072 foreach (Property prop in properties) {
1073 prop.check (context);
1076 foreach (Signal sig in signals) {
1077 sig.check (context);
1080 if (constructor != null) {
1081 constructor.check (context);
1084 if (class_constructor != null) {
1085 class_constructor.check (context);
1088 if (static_constructor != null) {
1089 static_constructor.check (context);
1092 if (destructor != null) {
1093 destructor.check (context);
1096 if (static_destructor != null) {
1097 static_destructor.check (context);
1100 if (class_destructor != null) {
1101 class_destructor.check (context);
1104 foreach (Class cl in classes) {
1105 cl.check (context);
1108 foreach (Struct st in structs) {
1109 st.check (context);
1112 foreach (Delegate d in delegates) {
1113 d.check (context);
1116 /* compact classes cannot implement interfaces */
1117 if (is_compact) {
1118 foreach (DataType base_type in get_base_types ()) {
1119 if (base_type.data_type is Interface) {
1120 error = true;
1121 Report.error (source_reference, "compact classes `%s` may not implement interfaces".printf (get_full_name ()));
1125 if (!external && !external_package && base_class != null) {
1126 foreach (Field f in fields) {
1127 if (f.binding == MemberBinding.INSTANCE) {
1128 error = true;
1129 Report.error (source_reference, "derived compact classes may not have instance fields");
1130 break;
1136 /* gather all prerequisites */
1137 List<TypeSymbol> prerequisites = new ArrayList<TypeSymbol> ();
1138 foreach (DataType base_type in get_base_types ()) {
1139 if (base_type.data_type is Interface) {
1140 get_all_prerequisites ((Interface) base_type.data_type, prerequisites);
1143 /* check whether all prerequisites are met */
1144 List<string> missing_prereqs = new ArrayList<string> ();
1145 foreach (TypeSymbol prereq in prerequisites) {
1146 if (!class_is_a (this, prereq)) {
1147 missing_prereqs.insert (0, prereq.get_full_name ());
1150 /* report any missing prerequisites */
1151 if (missing_prereqs.size > 0) {
1152 error = true;
1154 string error_string = "%s: some prerequisites (".printf (get_full_name ());
1155 bool first = true;
1156 foreach (string s in missing_prereqs) {
1157 if (first) {
1158 error_string = "%s`%s'".printf (error_string, s);
1159 first = false;
1160 } else {
1161 error_string = "%s, `%s'".printf (error_string, s);
1164 error_string += ") are not met";
1165 Report.error (source_reference, error_string);
1168 /* VAPI classes don't have to specify overridden methods */
1169 if (source_type == SourceFileType.SOURCE) {
1170 /* all abstract symbols defined in base types have to be at least defined (or implemented) also in this type */
1171 foreach (DataType base_type in get_base_types ()) {
1172 if (base_type.data_type is Interface) {
1173 Interface iface = (Interface) base_type.data_type;
1175 if (base_class != null && base_class.is_subtype_of (iface)) {
1176 // reimplementation of interface, class is not required to reimplement all methods
1177 break;
1180 /* We do not need to do expensive equality checking here since this is done
1181 * already. We only need to guarantee the symbols are present.
1184 /* check methods */
1185 foreach (Method m in iface.get_methods ()) {
1186 if (m.is_abstract) {
1187 Symbol sym = null;
1188 var base_class = this;
1189 while (base_class != null && !(sym is Method)) {
1190 sym = base_class.scope.lookup (m.name);
1191 base_class = base_class.base_class;
1193 if (sym is Method) {
1194 // method is used as interface implementation, so it is not unused
1195 sym.check_deprecated (source_reference);
1196 sym.used = true;
1197 } else {
1198 error = true;
1199 Report.error (source_reference, "`%s' does not implement interface method `%s'".printf (get_full_name (), m.get_full_name ()));
1204 /* check properties */
1205 foreach (Property prop in iface.get_properties ()) {
1206 if (prop.is_abstract) {
1207 Symbol sym = null;
1208 var base_class = this;
1209 while (base_class != null && !(sym is Property)) {
1210 sym = base_class.scope.lookup (prop.name);
1211 base_class = base_class.base_class;
1213 if (sym is Property) {
1214 // property is used as interface implementation, so it is not unused
1215 sym.check_deprecated (source_reference);
1216 sym.used = true;
1217 } else {
1218 error = true;
1219 Report.error (source_reference, "`%s' does not implement interface property `%s'".printf (get_full_name (), prop.get_full_name ()));
1226 /* all abstract symbols defined in base classes have to be implemented in non-abstract classes */
1227 if (!is_abstract) {
1228 var base_class = base_class;
1229 while (base_class != null && base_class.is_abstract) {
1230 foreach (Method base_method in base_class.get_methods ()) {
1231 if (base_method.is_abstract) {
1232 var override_method = context.analyzer.symbol_lookup_inherited (this, base_method.name) as Method;
1233 if (override_method == null || !override_method.overrides) {
1234 error = true;
1235 Report.error (source_reference, "`%s' does not implement abstract method `%s'".printf (get_full_name (), base_method.get_full_name ()));
1239 foreach (Property base_property in base_class.get_properties ()) {
1240 if (base_property.is_abstract) {
1241 var override_property = context.analyzer.symbol_lookup_inherited (this, base_property.name) as Property;
1242 if (override_property == null || !override_property.overrides) {
1243 error = true;
1244 Report.error (source_reference, "`%s' does not implement abstract property `%s'".printf (get_full_name (), base_property.get_full_name ()));
1248 base_class = base_class.base_class;
1253 context.analyzer.current_source_file = old_source_file;
1254 context.analyzer.current_symbol = old_symbol;
1256 return !error;
1260 // vim:sw=8 noet