D-Bus: Remove extra semicolon to avoid C warning
[vala-lang.git] / vala / valaclass.vala
blobf9ec4fab97828528b7713fde7accf5a578601e7d
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);
750 } else if (a.name == "Experimental") {
751 process_experimental_attribute (a);
756 public string? get_default_type_id () {
757 if (is_compact) {
758 return "G_TYPE_POINTER";
761 return get_upper_case_cname ("TYPE_");
764 public override string? get_type_id () {
765 if (type_id == null) {
766 type_id = get_default_type_id ();
769 return type_id;
772 public void set_type_id (string type_id) {
773 this.type_id = type_id;
776 public override string? get_marshaller_type_name () {
777 if (marshaller_type_name == null) {
778 if (base_class != null) {
779 marshaller_type_name = base_class.get_marshaller_type_name ();
780 } else if (!is_compact) {
781 marshaller_type_name = get_upper_case_cname ();
782 } else if (get_type_id () == "G_TYPE_POINTER") {
783 marshaller_type_name = "POINTER";
784 } else {
785 marshaller_type_name = "BOXED";
789 return marshaller_type_name;
792 public override string? get_param_spec_function () {
793 if (param_spec_function == null) {
794 param_spec_function = get_default_param_spec_function ();
797 return param_spec_function;
800 public string? get_default_param_spec_function () {
801 if (is_fundamental ()) {
802 return get_lower_case_cname ("param_spec_");
803 } else if (base_class != null) {
804 return base_class.get_param_spec_function ();
805 } else if (get_type_id () == "G_TYPE_POINTER") {
806 return "g_param_spec_pointer";
807 } else {
808 return "g_param_spec_boxed";
812 public override string? get_get_value_function () {
813 if (get_value_function == null) {
814 if (is_fundamental ()) {
815 get_value_function = get_lower_case_cname ("value_get_");
816 } else if (base_class != null) {
817 get_value_function = base_class.get_get_value_function ();
818 } else if (get_type_id () == "G_TYPE_POINTER") {
819 get_value_function = "g_value_get_pointer";
820 } else {
821 get_value_function = "g_value_get_boxed";
825 return get_value_function;
828 public override string? get_set_value_function () {
829 if (set_value_function == null) {
830 if (is_fundamental ()) {
831 set_value_function = get_lower_case_cname ("value_set_");
832 } else if (base_class != null) {
833 set_value_function = base_class.get_set_value_function ();
834 } else if (get_type_id () == "G_TYPE_POINTER") {
835 set_value_function = "g_value_set_pointer";
836 } else {
837 set_value_function = "g_value_set_boxed";
841 return set_value_function;
844 public override string? get_take_value_function () {
845 if (take_value_function == null) {
846 if (is_fundamental ()) {
847 take_value_function = get_lower_case_cname ("value_take_");
848 } else if (base_class != null) {
849 take_value_function = base_class.get_take_value_function ();
850 } else if (get_type_id () == "G_TYPE_POINTER") {
851 take_value_function = "g_value_set_pointer";
852 } else {
853 take_value_function = "g_value_take_boxed";
857 return take_value_function;
860 public override bool is_reference_counting () {
861 return get_ref_function () != null;
864 public bool is_fundamental () {
865 if (!is_compact && base_class == null) {
866 return true;
867 } else if (CodeContext.get ().profile == Profile.DOVA && base_class.base_class == null) {
868 return true;
870 return false;
873 public override string? get_ref_function () {
874 if (ref_function == null && is_fundamental ()) {
875 ref_function = get_lower_case_cprefix () + "ref";
878 if (ref_function == null && base_class != null) {
879 return base_class.get_ref_function ();
880 } else {
881 return ref_function;
885 public void set_ref_function (string? name) {
886 this.ref_function = name;
889 public override string? get_unref_function () {
890 if (unref_function == null && is_fundamental ()) {
891 unref_function = get_lower_case_cprefix () + "unref";
894 if (unref_function == null && base_class != null) {
895 return base_class.get_unref_function ();
896 } else {
897 return unref_function;
901 public void set_unref_function (string? name) {
902 this.unref_function = name;
905 public override string? get_ref_sink_function () {
906 if (ref_sink_function == null && base_class != null) {
907 return base_class.get_ref_sink_function ();
908 } else {
909 return ref_sink_function;
913 public void set_ref_sink_function (string? name) {
914 this.ref_sink_function = name;
917 public override string? get_dup_function () {
918 return copy_function;
921 public void set_dup_function (string? name) {
922 this.copy_function = name;
925 public string get_default_free_function () {
926 return get_lower_case_cprefix () + "free";
929 public override string? get_free_function () {
930 if (free_function == null) {
931 if (base_class != null) {
932 return base_class.get_free_function ();
934 free_function = get_default_free_function ();
936 return free_function;
939 public void set_free_function (string name) {
940 this.free_function = name;
943 public override bool is_subtype_of (TypeSymbol t) {
944 if (this == t) {
945 return true;
948 foreach (DataType base_type in base_types) {
949 if (base_type.data_type != null && base_type.data_type.is_subtype_of (t)) {
950 return true;
954 return false;
957 public override void replace_type (DataType old_type, DataType new_type) {
958 for (int i = 0; i < base_types.size; i++) {
959 if (base_types[i] == old_type) {
960 base_types[i] = new_type;
961 return;
966 private void get_all_prerequisites (Interface iface, List<TypeSymbol> list) {
967 foreach (DataType prereq in iface.get_prerequisites ()) {
968 TypeSymbol type = prereq.data_type;
969 /* skip on previous errors */
970 if (type == null) {
971 continue;
974 list.add (type);
975 if (type is Interface) {
976 get_all_prerequisites ((Interface) type, list);
982 private bool class_is_a (Class cl, TypeSymbol t) {
983 if (cl == t) {
984 return true;
987 foreach (DataType base_type in cl.get_base_types ()) {
988 if (base_type.data_type is Class) {
989 if (class_is_a ((Class) base_type.data_type, t)) {
990 return true;
992 } else if (base_type.data_type == t) {
993 return true;
997 return false;
1000 public override bool check (CodeContext context) {
1001 if (checked) {
1002 return !error;
1005 checked = true;
1007 process_attributes ();
1009 var old_source_file = context.analyzer.current_source_file;
1010 var old_symbol = context.analyzer.current_symbol;
1012 if (source_reference != null) {
1013 context.analyzer.current_source_file = source_reference.file;
1015 context.analyzer.current_symbol = this;
1017 foreach (DataType base_type_reference in get_base_types ()) {
1018 if (!base_type_reference.check (context)) {
1019 error = true;
1020 return false;
1023 if (!(base_type_reference is ObjectType)) {
1024 error = true;
1025 Report.error (source_reference, "base type `%s` of class `%s` is not an object type".printf (base_type_reference.to_string (), get_full_name ()));
1026 return false;
1029 // check whether base type is at least as accessible as the class
1030 if (!context.analyzer.is_type_accessible (this, base_type_reference)) {
1031 error = true;
1032 Report.error (source_reference, "base type `%s` is less accessible than class `%s`".printf (base_type_reference.to_string (), get_full_name ()));
1033 return false;
1036 int n_type_args = base_type_reference.get_type_arguments ().size;
1037 int n_type_params = ((ObjectTypeSymbol) base_type_reference.data_type).get_type_parameters ().size;
1038 if (n_type_args < n_type_params) {
1039 error = true;
1040 Report.error (base_type_reference.source_reference, "too few type arguments");
1041 return false;
1042 } else if (n_type_args > n_type_params) {
1043 error = true;
1044 Report.error (base_type_reference.source_reference, "too many type arguments");
1045 return false;
1049 foreach (DataType type in base_types) {
1050 type.check (context);
1053 foreach (TypeParameter p in get_type_parameters ()) {
1054 p.check (context);
1057 /* process enums first to avoid order problems in C code */
1058 foreach (Enum en in enums) {
1059 en.check (context);
1062 foreach (Field f in fields) {
1063 f.check (context);
1066 foreach (Constant c in constants) {
1067 c.check (context);
1070 foreach (Method m in methods) {
1071 m.check (context);
1074 foreach (Property prop in properties) {
1075 prop.check (context);
1078 foreach (Signal sig in signals) {
1079 sig.check (context);
1082 if (constructor != null) {
1083 constructor.check (context);
1086 if (class_constructor != null) {
1087 class_constructor.check (context);
1090 if (static_constructor != null) {
1091 static_constructor.check (context);
1094 if (destructor != null) {
1095 destructor.check (context);
1098 if (static_destructor != null) {
1099 static_destructor.check (context);
1102 if (class_destructor != null) {
1103 class_destructor.check (context);
1106 foreach (Class cl in classes) {
1107 cl.check (context);
1110 foreach (Struct st in structs) {
1111 st.check (context);
1114 foreach (Delegate d in delegates) {
1115 d.check (context);
1118 /* compact classes cannot implement interfaces */
1119 if (is_compact) {
1120 foreach (DataType base_type in get_base_types ()) {
1121 if (base_type.data_type is Interface) {
1122 error = true;
1123 Report.error (source_reference, "compact classes `%s` may not implement interfaces".printf (get_full_name ()));
1127 if (!external && !external_package && base_class != null) {
1128 foreach (Field f in fields) {
1129 if (f.binding == MemberBinding.INSTANCE) {
1130 error = true;
1131 Report.error (source_reference, "derived compact classes may not have instance fields");
1132 break;
1138 /* gather all prerequisites */
1139 List<TypeSymbol> prerequisites = new ArrayList<TypeSymbol> ();
1140 foreach (DataType base_type in get_base_types ()) {
1141 if (base_type.data_type is Interface) {
1142 get_all_prerequisites ((Interface) base_type.data_type, prerequisites);
1145 /* check whether all prerequisites are met */
1146 List<string> missing_prereqs = new ArrayList<string> ();
1147 foreach (TypeSymbol prereq in prerequisites) {
1148 if (!class_is_a (this, prereq)) {
1149 missing_prereqs.insert (0, prereq.get_full_name ());
1152 /* report any missing prerequisites */
1153 if (missing_prereqs.size > 0) {
1154 error = true;
1156 string error_string = "%s: some prerequisites (".printf (get_full_name ());
1157 bool first = true;
1158 foreach (string s in missing_prereqs) {
1159 if (first) {
1160 error_string = "%s`%s'".printf (error_string, s);
1161 first = false;
1162 } else {
1163 error_string = "%s, `%s'".printf (error_string, s);
1166 error_string += ") are not met";
1167 Report.error (source_reference, error_string);
1170 /* VAPI classes don't have to specify overridden methods */
1171 if (source_type == SourceFileType.SOURCE) {
1172 /* all abstract symbols defined in base types have to be at least defined (or implemented) also in this type */
1173 foreach (DataType base_type in get_base_types ()) {
1174 if (base_type.data_type is Interface) {
1175 Interface iface = (Interface) base_type.data_type;
1177 if (base_class != null && base_class.is_subtype_of (iface)) {
1178 // reimplementation of interface, class is not required to reimplement all methods
1179 break;
1182 /* We do not need to do expensive equality checking here since this is done
1183 * already. We only need to guarantee the symbols are present.
1186 /* check methods */
1187 foreach (Method m in iface.get_methods ()) {
1188 if (m.is_abstract) {
1189 Symbol sym = null;
1190 var base_class = this;
1191 while (base_class != null && !(sym is Method)) {
1192 sym = base_class.scope.lookup (m.name);
1193 base_class = base_class.base_class;
1195 if (sym is Method) {
1196 // method is used as interface implementation, so it is not unused
1197 sym.check_deprecated (source_reference);
1198 sym.check_experimental (source_reference);
1199 sym.used = true;
1200 } else {
1201 error = true;
1202 Report.error (source_reference, "`%s' does not implement interface method `%s'".printf (get_full_name (), m.get_full_name ()));
1207 /* check properties */
1208 foreach (Property prop in iface.get_properties ()) {
1209 if (prop.is_abstract) {
1210 Symbol sym = null;
1211 var base_class = this;
1212 while (base_class != null && !(sym is Property)) {
1213 sym = base_class.scope.lookup (prop.name);
1214 base_class = base_class.base_class;
1216 if (sym is Property) {
1217 // property is used as interface implementation, so it is not unused
1218 sym.check_deprecated (source_reference);
1219 sym.check_experimental (source_reference);
1220 sym.used = true;
1221 } else {
1222 error = true;
1223 Report.error (source_reference, "`%s' does not implement interface property `%s'".printf (get_full_name (), prop.get_full_name ()));
1230 /* all abstract symbols defined in base classes have to be implemented in non-abstract classes */
1231 if (!is_abstract) {
1232 var base_class = base_class;
1233 while (base_class != null && base_class.is_abstract) {
1234 foreach (Method base_method in base_class.get_methods ()) {
1235 if (base_method.is_abstract) {
1236 var override_method = context.analyzer.symbol_lookup_inherited (this, base_method.name) as Method;
1237 if (override_method == null || !override_method.overrides) {
1238 error = true;
1239 Report.error (source_reference, "`%s' does not implement abstract method `%s'".printf (get_full_name (), base_method.get_full_name ()));
1243 foreach (Property base_property in base_class.get_properties ()) {
1244 if (base_property.is_abstract) {
1245 var override_property = context.analyzer.symbol_lookup_inherited (this, base_property.name) as Property;
1246 if (override_property == null || !override_property.overrides) {
1247 error = true;
1248 Report.error (source_reference, "`%s' does not implement abstract property `%s'".printf (get_full_name (), base_property.get_full_name ()));
1252 base_class = base_class.base_class;
1257 context.analyzer.current_source_file = old_source_file;
1258 context.analyzer.current_symbol = old_symbol;
1260 return !error;
1264 // vim:sw=8 noet