libxml-2.0: Make Doc.save_format_file return an int
[vala-lang.git] / vala / valaclass.vala
blob1fb579833ae6d810c29a6b0611ea21028efdeb7d
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; private 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 FormalParameter ("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 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 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);
301 prop.get_accessor.access = SymbolAccessibility.PUBLIC;
303 prop.set_accessor = new PropertyAccessor (false, true, false, prop.property_type.copy (), null, f.source_reference);
304 prop.set_accessor.access = SymbolAccessibility.PUBLIC;
306 f.name = "_%s".printf (f.name);
307 f.access = SymbolAccessibility.PRIVATE;
308 prop.field = f;
310 add_property (prop);
311 return;
314 fields.add (f);
315 if (f.access == SymbolAccessibility.PRIVATE && f.binding == MemberBinding.INSTANCE) {
316 has_private_fields = true;
317 } else if (f.access == SymbolAccessibility.PRIVATE && f.binding == MemberBinding.CLASS) {
318 has_class_private_fields = true;
320 scope.add (f.name, f);
324 * Returns a copy of the list of fields.
326 * @return list of fields
328 public List<Field> get_fields () {
329 return fields;
333 * Returns a copy of the list of constants.
335 * @return list of constants
337 public List<Constant> get_constants () {
338 return constants;
342 * Adds the specified method as a member to this class.
344 * @param m a method
346 public void add_method (Method m) {
347 if (m.binding == MemberBinding.INSTANCE || m is CreationMethod) {
348 if (m.this_parameter != null) {
349 m.scope.remove (m.this_parameter.name);
351 m.this_parameter = new FormalParameter ("this", get_this_type ());
352 m.scope.add (m.this_parameter.name, m.this_parameter);
354 if (!(m.return_type is VoidType) && (CodeContext.get ().profile == Profile.DOVA || m.get_postconditions ().size > 0)) {
355 if (m.result_var != null) {
356 m.scope.remove (m.result_var.name);
358 m.result_var = new LocalVariable (m.return_type.copy (), "result", null, source_reference);
359 m.result_var.is_result = true;
361 if (m is CreationMethod) {
362 if (m.name == null) {
363 default_construction_method = m;
364 m.name = ".new";
367 var cm = (CreationMethod) m;
368 if (cm.class_name != null && cm.class_name != name) {
369 // class_name is null for constructors generated by GIdlParser
370 Report.error (m.source_reference, "missing return type in method `%s.%s´".printf (get_full_name (), cm.class_name));
371 m.error = true;
372 return;
376 methods.add (m);
377 scope.add (m.name, m);
381 * Returns a copy of the list of methods.
383 * @return list of methods
385 public override List<Method> get_methods () {
386 return methods;
390 * Adds the specified property as a member to this class.
392 * @param prop a property
394 public void add_property (Property prop) {
395 properties.add (prop);
396 scope.add (prop.name, prop);
398 prop.this_parameter = new FormalParameter ("this", get_this_type ());
399 prop.scope.add (prop.this_parameter.name, prop.this_parameter);
401 if (prop.field != null) {
402 add_field (prop.field);
407 * Returns a copy of the list of properties.
409 * @return list of properties
411 public override List<Property> get_properties () {
412 return properties;
416 * Adds the specified signal as a member to this class.
418 * @param sig a signal
420 public void add_signal (Signal sig) {
421 signals.add (sig);
422 scope.add (sig.name, sig);
426 * Returns a copy of the list of signals.
428 * @return list of signals
430 public override List<Signal> get_signals () {
431 return signals;
435 * Adds the specified class as an inner class.
437 * @param cl a class
439 public void add_class (Class cl) {
440 classes.add (cl);
441 scope.add (cl.name, cl);
445 * Adds the specified struct as an inner struct.
447 * @param st a struct
449 public void add_struct (Struct st) {
450 structs.add (st);
451 scope.add (st.name, st);
455 * Adds the specified enum as an inner enum.
457 * @param en an enum
459 public void add_enum (Enum en) {
460 enums.add (en);
461 scope.add (en.name, en);
465 * Adds the specified delegate as an inner delegate.
467 * @param d a delegate
469 public void add_delegate (Delegate d) {
470 delegates.add (d);
471 scope.add (d.name, d);
474 public override void accept (CodeVisitor visitor) {
475 visitor.visit_class (this);
478 public override void accept_children (CodeVisitor visitor) {
479 foreach (DataType type in base_types) {
480 type.accept (visitor);
483 foreach (TypeParameter p in get_type_parameters ()) {
484 p.accept (visitor);
487 /* process enums first to avoid order problems in C code */
488 foreach (Enum en in enums) {
489 en.accept (visitor);
492 foreach (Field f in fields) {
493 f.accept (visitor);
496 foreach (Constant c in constants) {
497 c.accept (visitor);
500 foreach (Method m in methods) {
501 m.accept (visitor);
504 foreach (Property prop in properties) {
505 prop.accept (visitor);
508 foreach (Signal sig in signals) {
509 sig.accept (visitor);
512 if (constructor != null) {
513 constructor.accept (visitor);
516 if (class_constructor != null) {
517 class_constructor.accept (visitor);
520 if (static_constructor != null) {
521 static_constructor.accept (visitor);
524 if (destructor != null) {
525 destructor.accept (visitor);
528 if (static_destructor != null) {
529 static_destructor.accept (visitor);
532 if (class_destructor != null) {
533 class_destructor.accept (visitor);
536 foreach (Class cl in classes) {
537 cl.accept (visitor);
540 foreach (Struct st in structs) {
541 st.accept (visitor);
544 foreach (Delegate d in delegates) {
545 d.accept (visitor);
549 public override string get_cprefix () {
550 return get_cname ();
553 public override string get_cname (bool const_type = false) {
554 if (const_type) {
555 if (const_cname != null) {
556 return const_cname;
557 } else if (is_immutable) {
558 return "const " + get_cname (false);
562 if (cname == null) {
563 var attr = get_attribute ("CCode");
564 if (attr != null) {
565 cname = attr.get_string ("cname");
567 if (cname == null) {
568 cname = get_default_cname ();
571 return cname;
575 * Returns the default name of this class as it is used in C code.
577 * @return the name to be used in C code by default
579 public string get_default_cname () {
580 return "%s%s".printf (parent_symbol.get_cprefix (), name);
584 * Sets the name of this class as it is used in C code.
586 * @param cname the name to be used in C code
588 public void set_cname (string cname) {
589 this.cname = cname;
592 private string get_lower_case_csuffix () {
593 if (lower_case_csuffix == null) {
594 lower_case_csuffix = camel_case_to_lower_case (name);
596 // remove underscores in some cases to avoid conflicts of type macros
597 if (lower_case_csuffix.has_prefix ("type_")) {
598 lower_case_csuffix = "type" + lower_case_csuffix.offset ("type_".len ());
599 } else if (lower_case_csuffix.has_prefix ("is_")) {
600 lower_case_csuffix = "is" + lower_case_csuffix.offset ("is_".len ());
602 if (lower_case_csuffix.has_suffix ("_class")) {
603 lower_case_csuffix = lower_case_csuffix.substring (0, lower_case_csuffix.len () - "_class".len ()) + "class";
606 return lower_case_csuffix;
609 public override string? get_lower_case_cname (string? infix) {
610 if (infix == null) {
611 infix = "";
613 return "%s%s%s".printf (parent_symbol.get_lower_case_cprefix (), infix, get_lower_case_csuffix ());
616 public override string get_lower_case_cprefix () {
617 if (lower_case_cprefix == null) {
618 lower_case_cprefix = "%s_".printf (get_lower_case_cname (null));
620 return lower_case_cprefix;
623 public override string? get_upper_case_cname (string? infix) {
624 return get_lower_case_cname (infix).up ();
627 public override bool is_reference_type () {
628 return true;
631 private void process_ccode_attribute (Attribute a) {
632 if (a.has_argument ("ref_function")) {
633 set_ref_function (a.get_string ("ref_function"));
635 if (a.has_argument ("ref_function_void")) {
636 this.ref_function_void = a.get_bool ("ref_function_void");
638 if (a.has_argument ("unref_function")) {
639 set_unref_function (a.get_string ("unref_function"));
641 if (a.has_argument ("ref_sink_function")) {
642 set_ref_sink_function (a.get_string ("ref_sink_function"));
644 if (a.has_argument ("copy_function")) {
645 set_dup_function (a.get_string ("copy_function"));
647 if (a.has_argument ("free_function")) {
648 set_free_function (a.get_string ("free_function"));
650 if (a.has_argument ("free_function_address_of")) {
651 free_function_address_of = a.get_bool ("free_function_address_of");
653 if (a.has_argument ("type_id")) {
654 type_id = a.get_string ("type_id");
656 if (a.has_argument ("marshaller_type_name")) {
657 marshaller_type_name = a.get_string ("marshaller_type_name");
659 if (a.has_argument ("get_value_function")) {
660 get_value_function = a.get_string ("get_value_function");
662 if (a.has_argument ("set_value_function")) {
663 set_value_function = a.get_string ("set_value_function");
665 if (a.has_argument ("take_value_function")) {
666 take_value_function = a.get_string ("take_value_function");
669 if (a.has_argument ("const_cname")) {
670 const_cname = a.get_string ("const_cname");
672 if (a.has_argument ("cprefix")) {
673 lower_case_cprefix = a.get_string ("cprefix");
675 if (a.has_argument ("lower_case_csuffix")) {
676 lower_case_csuffix = a.get_string ("lower_case_csuffix");
678 if (a.has_argument ("cheader_filename")) {
679 var val = a.get_string ("cheader_filename");
680 foreach (string filename in val.split (",")) {
681 add_cheader_filename (filename);
684 if (a.has_argument ("type_check_function")) {
685 type_check_function = a.get_string ("type_check_function");
688 if (a.has_argument ("param_spec_function")) {
689 param_spec_function = a.get_string ("param_spec_function");
694 * Process all associated attributes.
696 public void process_attributes () {
697 foreach (Attribute a in attributes) {
698 if (a.name == "CCode") {
699 process_ccode_attribute (a);
700 } else if (a.name == "Compact") {
701 is_compact = true;
702 } else if (a.name == "Immutable") {
703 is_immutable = true;
704 } else if (a.name == "Deprecated") {
705 process_deprecated_attribute (a);
710 public string? get_default_type_id () {
711 if (is_compact) {
712 return "G_TYPE_POINTER";
715 return get_upper_case_cname ("TYPE_");
718 public override string? get_type_id () {
719 if (type_id == null) {
720 type_id = get_default_type_id ();
723 return type_id;
726 public void set_type_id (string type_id) {
727 this.type_id = type_id;
730 public override string? get_marshaller_type_name () {
731 if (marshaller_type_name == null) {
732 if (base_class != null) {
733 marshaller_type_name = base_class.get_marshaller_type_name ();
734 } else if (!is_compact) {
735 marshaller_type_name = get_upper_case_cname ();
736 } else if (get_type_id () == "G_TYPE_POINTER") {
737 marshaller_type_name = "POINTER";
738 } else {
739 marshaller_type_name = "BOXED";
743 return marshaller_type_name;
746 public override string? get_param_spec_function () {
747 if (param_spec_function == null) {
748 param_spec_function = get_default_param_spec_function ();
751 return param_spec_function;
754 public string? get_default_param_spec_function () {
755 if (is_fundamental ()) {
756 return get_lower_case_cname ("param_spec_");
757 } else if (base_class != null) {
758 return base_class.get_param_spec_function ();
759 } else if (get_type_id () == "G_TYPE_POINTER") {
760 return "g_param_spec_pointer";
761 } else {
762 return "g_param_spec_boxed";
766 public override string? get_get_value_function () {
767 if (get_value_function == null) {
768 if (is_fundamental ()) {
769 get_value_function = get_lower_case_cname ("value_get_");
770 } else if (base_class != null) {
771 get_value_function = base_class.get_get_value_function ();
772 } else if (get_type_id () == "G_TYPE_POINTER") {
773 get_value_function = "g_value_get_pointer";
774 } else {
775 get_value_function = "g_value_get_boxed";
779 return get_value_function;
782 public override string? get_set_value_function () {
783 if (set_value_function == null) {
784 if (is_fundamental ()) {
785 set_value_function = get_lower_case_cname ("value_set_");
786 } else if (base_class != null) {
787 set_value_function = base_class.get_set_value_function ();
788 } else if (get_type_id () == "G_TYPE_POINTER") {
789 set_value_function = "g_value_set_pointer";
790 } else {
791 set_value_function = "g_value_set_boxed";
795 return set_value_function;
798 public override string? get_take_value_function () {
799 if (take_value_function == null) {
800 if (is_fundamental ()) {
801 take_value_function = get_lower_case_cname ("value_take_");
802 } else if (base_class != null) {
803 take_value_function = base_class.get_take_value_function ();
804 } else if (get_type_id () == "G_TYPE_POINTER") {
805 take_value_function = "g_value_set_pointer";
806 } else {
807 take_value_function = "g_value_take_boxed";
811 return take_value_function;
814 public override bool is_reference_counting () {
815 return get_ref_function () != null;
818 public bool is_fundamental () {
819 if (!is_compact && base_class == null) {
820 return true;
821 } else if (CodeContext.get ().profile == Profile.DOVA && base_class.base_class == null) {
822 return true;
824 return false;
827 public override string? get_ref_function () {
828 if (ref_function == null && is_fundamental ()) {
829 ref_function = get_lower_case_cprefix () + "ref";
832 if (ref_function == null && base_class != null) {
833 return base_class.get_ref_function ();
834 } else {
835 return ref_function;
839 public void set_ref_function (string? name) {
840 this.ref_function = name;
843 public override string? get_unref_function () {
844 if (unref_function == null && is_fundamental ()) {
845 unref_function = get_lower_case_cprefix () + "unref";
848 if (unref_function == null && base_class != null) {
849 return base_class.get_unref_function ();
850 } else {
851 return unref_function;
855 public void set_unref_function (string? name) {
856 this.unref_function = name;
859 public override string? get_ref_sink_function () {
860 if (ref_sink_function == null && base_class != null) {
861 return base_class.get_ref_sink_function ();
862 } else {
863 return ref_sink_function;
867 public void set_ref_sink_function (string? name) {
868 this.ref_sink_function = name;
871 public override string? get_dup_function () {
872 return copy_function;
875 public void set_dup_function (string? name) {
876 this.copy_function = name;
879 public string get_default_free_function () {
880 return get_lower_case_cprefix () + "free";
883 public override string? get_free_function () {
884 if (free_function == null) {
885 if (base_class != null) {
886 return base_class.get_free_function ();
888 free_function = get_default_free_function ();
890 return free_function;
893 public void set_free_function (string name) {
894 this.free_function = name;
897 public override bool is_subtype_of (TypeSymbol t) {
898 if (this == t) {
899 return true;
902 foreach (DataType base_type in base_types) {
903 if (base_type.data_type != null && base_type.data_type.is_subtype_of (t)) {
904 return true;
908 return false;
911 public override void replace_type (DataType old_type, DataType new_type) {
912 for (int i = 0; i < base_types.size; i++) {
913 if (base_types[i] == old_type) {
914 base_types[i] = new_type;
915 return;
920 private void get_all_prerequisites (Interface iface, List<TypeSymbol> list) {
921 foreach (DataType prereq in iface.get_prerequisites ()) {
922 TypeSymbol type = prereq.data_type;
923 /* skip on previous errors */
924 if (type == null) {
925 continue;
928 list.add (type);
929 if (type is Interface) {
930 get_all_prerequisites ((Interface) type, list);
936 private bool class_is_a (Class cl, TypeSymbol t) {
937 if (cl == t) {
938 return true;
941 foreach (DataType base_type in cl.get_base_types ()) {
942 if (base_type.data_type is Class) {
943 if (class_is_a ((Class) base_type.data_type, t)) {
944 return true;
946 } else if (base_type.data_type == t) {
947 return true;
951 return false;
954 public override bool check (SemanticAnalyzer analyzer) {
955 if (checked) {
956 return !error;
959 checked = true;
961 process_attributes ();
963 var old_source_file = analyzer.current_source_file;
964 var old_symbol = analyzer.current_symbol;
966 if (source_reference != null) {
967 analyzer.current_source_file = source_reference.file;
969 analyzer.current_symbol = this;
971 foreach (DataType base_type_reference in get_base_types ()) {
972 if (!base_type_reference.check (analyzer)) {
973 error = true;
974 return false;
977 if (!(base_type_reference is ObjectType)) {
978 error = true;
979 Report.error (source_reference, "base type `%s` of class `%s` is not an object type".printf (base_type_reference.to_string (), get_full_name ()));
980 return false;
983 // check whether base type is at least as accessible as the class
984 if (!analyzer.is_type_accessible (this, base_type_reference)) {
985 error = true;
986 Report.error (source_reference, "base type `%s` is less accessible than class `%s`".printf (base_type_reference.to_string (), get_full_name ()));
987 return false;
990 int n_type_args = base_type_reference.get_type_arguments ().size;
991 int n_type_params = ((ObjectTypeSymbol) base_type_reference.data_type).get_type_parameters ().size;
992 if (n_type_args < n_type_params) {
993 error = true;
994 Report.error (base_type_reference.source_reference, "too few type arguments");
995 return false;
996 } else if (n_type_args > n_type_params) {
997 error = true;
998 Report.error (base_type_reference.source_reference, "too many type arguments");
999 return false;
1003 foreach (DataType type in base_types) {
1004 type.check (analyzer);
1007 foreach (TypeParameter p in get_type_parameters ()) {
1008 p.check (analyzer);
1011 /* process enums first to avoid order problems in C code */
1012 foreach (Enum en in enums) {
1013 en.check (analyzer);
1016 foreach (Field f in fields) {
1017 f.check (analyzer);
1020 foreach (Constant c in constants) {
1021 c.check (analyzer);
1024 foreach (Method m in methods) {
1025 m.check (analyzer);
1028 foreach (Property prop in properties) {
1029 prop.check (analyzer);
1032 foreach (Signal sig in signals) {
1033 sig.check (analyzer);
1036 if (constructor != null) {
1037 constructor.check (analyzer);
1040 if (class_constructor != null) {
1041 class_constructor.check (analyzer);
1044 if (static_constructor != null) {
1045 static_constructor.check (analyzer);
1048 if (destructor != null) {
1049 destructor.check (analyzer);
1052 if (static_destructor != null) {
1053 static_destructor.check (analyzer);
1056 if (class_destructor != null) {
1057 class_destructor.check (analyzer);
1060 foreach (Class cl in classes) {
1061 cl.check (analyzer);
1064 foreach (Struct st in structs) {
1065 st.check (analyzer);
1068 foreach (Delegate d in delegates) {
1069 d.check (analyzer);
1072 /* compact classes cannot implement interfaces */
1073 if (is_compact) {
1074 foreach (DataType base_type in get_base_types ()) {
1075 if (base_type.data_type is Interface) {
1076 error = true;
1077 Report.error (source_reference, "compact classes `%s` may not implement interfaces".printf (get_full_name ()));
1081 if (!external && !external_package && base_class != null) {
1082 foreach (Field f in fields) {
1083 if (f.binding == MemberBinding.INSTANCE) {
1084 error = true;
1085 Report.error (source_reference, "derived compact classes may not have instance fields");
1086 break;
1092 /* gather all prerequisites */
1093 List<TypeSymbol> prerequisites = new ArrayList<TypeSymbol> ();
1094 foreach (DataType base_type in get_base_types ()) {
1095 if (base_type.data_type is Interface) {
1096 get_all_prerequisites ((Interface) base_type.data_type, prerequisites);
1099 /* check whether all prerequisites are met */
1100 List<string> missing_prereqs = new ArrayList<string> ();
1101 foreach (TypeSymbol prereq in prerequisites) {
1102 if (!class_is_a (this, prereq)) {
1103 missing_prereqs.insert (0, prereq.get_full_name ());
1106 /* report any missing prerequisites */
1107 if (missing_prereqs.size > 0) {
1108 error = true;
1110 string error_string = "%s: some prerequisites (".printf (get_full_name ());
1111 bool first = true;
1112 foreach (string s in missing_prereqs) {
1113 if (first) {
1114 error_string = "%s`%s'".printf (error_string, s);
1115 first = false;
1116 } else {
1117 error_string = "%s, `%s'".printf (error_string, s);
1120 error_string += ") are not met";
1121 Report.error (source_reference, error_string);
1124 /* VAPI classes don't have to specify overridden methods */
1125 if (!external_package) {
1126 /* all abstract symbols defined in base types have to be at least defined (or implemented) also in this type */
1127 foreach (DataType base_type in get_base_types ()) {
1128 if (base_type.data_type is Interface) {
1129 Interface iface = (Interface) base_type.data_type;
1131 if (base_class != null && base_class.is_subtype_of (iface)) {
1132 // reimplementation of interface, class is not required to reimplement all methods
1133 break;
1136 /* We do not need to do expensive equality checking here since this is done
1137 * already. We only need to guarantee the symbols are present.
1140 /* check methods */
1141 foreach (Method m in iface.get_methods ()) {
1142 if (m.is_abstract) {
1143 Symbol sym = null;
1144 var base_class = this;
1145 while (base_class != null && !(sym is Method)) {
1146 sym = base_class.scope.lookup (m.name);
1147 base_class = base_class.base_class;
1149 if (sym is Method) {
1150 // method is used as interface implementation, so it is not unused
1151 sym.check_deprecated (source_reference);
1152 sym.used = true;
1153 } else {
1154 error = true;
1155 Report.error (source_reference, "`%s' does not implement interface method `%s'".printf (get_full_name (), m.get_full_name ()));
1160 /* check properties */
1161 foreach (Property prop in iface.get_properties ()) {
1162 if (prop.is_abstract) {
1163 Symbol sym = null;
1164 var base_class = this;
1165 while (base_class != null && !(sym is Property)) {
1166 sym = base_class.scope.lookup (prop.name);
1167 base_class = base_class.base_class;
1169 if (sym is Property) {
1170 // property is used as interface implementation, so it is not unused
1171 sym.check_deprecated (source_reference);
1172 sym.used = true;
1173 } else {
1174 error = true;
1175 Report.error (source_reference, "`%s' does not implement interface property `%s'".printf (get_full_name (), prop.get_full_name ()));
1182 /* all abstract symbols defined in base classes have to be implemented in non-abstract classes */
1183 if (!is_abstract) {
1184 var base_class = base_class;
1185 while (base_class != null && base_class.is_abstract) {
1186 foreach (Method base_method in base_class.get_methods ()) {
1187 if (base_method.is_abstract) {
1188 var override_method = analyzer.symbol_lookup_inherited (this, base_method.name) as Method;
1189 if (override_method == null || !override_method.overrides) {
1190 error = true;
1191 Report.error (source_reference, "`%s' does not implement abstract method `%s'".printf (get_full_name (), base_method.get_full_name ()));
1195 foreach (Property base_property in base_class.get_properties ()) {
1196 if (base_property.is_abstract) {
1197 var override_property = analyzer.symbol_lookup_inherited (this, base_property.name) as Property;
1198 if (override_property == null || !override_property.overrides) {
1199 error = true;
1200 Report.error (source_reference, "`%s' does not implement abstract property `%s'".printf (get_full_name (), base_property.get_full_name ()));
1204 base_class = base_class.base_class;
1209 analyzer.current_source_file = old_source_file;
1210 analyzer.current_symbol = old_symbol;
1212 return !error;
1216 // vim:sw=8 noet