LCOV - code coverage report
Current view: top level - vala - valaclass.vala (source / functions) Coverage Total Hit
Test: vala 0.57.0.298-a8cae1 Lines: 98.0 % 408 400
Test Date: 2024-04-25 11:34:36 Functions: - 0 0

            Line data    Source code
       1              : /* valaclass.vala
       2              :  *
       3              :  * Copyright (C) 2006-2012  Jürg Billeter
       4              :  *
       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.
       9              : 
      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.
      14              : 
      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
      18              :  *
      19              :  * Author:
      20              :  *      Jürg Billeter <j@bitron.ch>
      21              :  */
      22              : 
      23              : using GLib;
      24              : 
      25              : /**
      26              :  * Represents a class declaration in the source code.
      27              :  */
      28       750242 : public class Vala.Class : ObjectTypeSymbol {
      29              :         /**
      30              :          * Specifies the base class.
      31              :          */
      32      3546756 :         public Class base_class { get; set; }
      33              : 
      34              :         /**
      35              :          * Specifies whether this class is abstract. Abstract classes may not be
      36              :          * instantiated.
      37              :          */
      38        68285 :         public bool is_abstract { get; set; }
      39              : 
      40       747473 :         public bool is_partial { get; set; }
      41              : 
      42              :         /**
      43              :          * Specifies whether this class is sealed. Sealed classes may not be
      44              :          * sub-classed.
      45              :          */
      46        59567 :         public bool is_sealed { get; set; }
      47              : 
      48              :         /**
      49              :          * Instances of compact classes are fast to create and have a
      50              :          * compact memory layout. Compact classes don't support runtime
      51              :          * type information or virtual methods.
      52              :          */
      53              :         public bool is_compact {
      54      2297588 :                 get {
      55      2297588 :                         if (_is_compact == null) {
      56       347332 :                                 if (base_class != null && !base_class.is_subtype_of (this)) {
      57      1537014 :                                         _is_compact = base_class.is_compact;
      58              :                                 } else {
      59       134266 :                                         _is_compact = has_attribute ("Compact");
      60              :                                 }
      61              :                         }
      62      2297588 :                         return _is_compact;
      63              :                 }
      64              :         }
      65              : 
      66              :         /**
      67              :          * Opaque compact classes hide their memory layout, only allowing private or
      68              :          * internal instance members.
      69              :          */
      70              :         public bool is_opaque {
      71       426342 :                 get {
      72       426342 :                         if (_is_opaque == null) {
      73        71487 :                                 _is_opaque = get_attribute_bool ("Compact", "opaque");
      74              :                         }
      75       426342 :                         return _is_opaque;
      76              :                 }
      77              :         }
      78              : 
      79              :         /**
      80              :          * Instances of immutable classes are immutable after construction.
      81              :          */
      82              :         public bool is_immutable {
      83         5225 :                 get {
      84         5225 :                         if (_is_immutable == null) {
      85         2355 :                                 if (base_class != null && !base_class.is_subtype_of (this)) {
      86         1272 :                                         _is_immutable = base_class.is_immutable;
      87              :                                 } else {
      88         1083 :                                         _is_immutable = has_attribute ("Immutable");
      89              :                                 }
      90              :                         }
      91         5225 :                         return _is_immutable;
      92              :                 }
      93              :         }
      94              : 
      95              :         /**
      96              :          * Instances of immutable classes are immutable after construction.
      97              :          */
      98              :         public bool is_singleton {
      99       908095 :                 get {
     100       908095 :                         if (_is_singleton == null) {
     101       347333 :                                 _is_singleton = has_attribute ("SingleInstance");
     102              :                         }
     103       908095 :                         return _is_singleton;
     104              :                 }
     105              :         }
     106              : 
     107              :         /**
     108              :          * Specifies whether this class has private fields.
     109              :          */
     110         7510 :         public bool has_private_fields { get; set; }
     111              : 
     112              :         /**
     113              :          * Specifies whether this class has class fields.
     114              :          */
     115         4099 :         public bool has_class_private_fields { get; private set; }
     116              : 
     117       374351 :         private bool? _is_compact;
     118       374351 :         private bool? _is_opaque;
     119       374351 :         private bool? _is_immutable;
     120       374351 :         private bool? _is_singleton;
     121              : 
     122       748704 :         private List<DataType> base_types = new ArrayList<DataType> ();
     123       748704 :         private HashMap<Method,Method> implicit_implementations = new HashMap<Method,Method> (Symbol.hash_func, Symbol.equal_func);
     124              : 
     125              :         /**
     126              :          * Specifies the default construction method.
     127              :          */
     128      1032378 :         public CreationMethod? default_construction_method { get; private set; }
     129              : 
     130              :         /**
     131              :          * Specifies the instance constructor.
     132              :          */
     133              :         public Constructor? constructor {
     134      1173123 :                 get { return _constructor; }
     135           28 :                 private set {
     136           56 :                         _constructor = value;
     137           28 :                         if (_constructor != null) {
     138           28 :                                 _constructor.owner = scope;
     139              :                         }
     140              :                 }
     141              :         }
     142              : 
     143              :         /**
     144              :          * Specifies the class constructor.
     145              :          */
     146              :         public Constructor? class_constructor {
     147      1175872 :                 get { return _class_constructor; }
     148           10 :                 private set {
     149           20 :                         _class_constructor = value;
     150           10 :                         if (_class_constructor != null) {
     151           10 :                                 _class_constructor.owner = scope;
     152              :                         }
     153              :                 }
     154              :         }
     155              : 
     156              :         /**
     157              :          * Specifies the static class constructor.
     158              :          */
     159              :         public Constructor? static_constructor {
     160      1172600 :                 get { return _static_constructor; }
     161            9 :                 private set {
     162           18 :                         _static_constructor = value;
     163            9 :                         if (_static_constructor != null) {
     164            9 :                                 _static_constructor.owner = scope;
     165              :                         }
     166              :                 }
     167              :         }
     168              : 
     169              :         /**
     170              :          * Specifies the instance destructor.
     171              :          */
     172              :         public Destructor? destructor {
     173      1174352 :                 get { return _destructor; }
     174           18 :                 private set {
     175           36 :                         _destructor = value;
     176           18 :                         if (_destructor != null) {
     177           18 :                                 _destructor.owner = scope;
     178              :                         }
     179              :                 }
     180              :         }
     181              : 
     182              :         /**
     183              :          * Specifies the class destructor.
     184              :          */
     185              :         public Destructor? static_destructor {
     186      1176659 :                 get { return _static_destructor; }
     187            3 :                 private set {
     188            6 :                         _static_destructor = value;
     189            3 :                         if (_static_destructor != null) {
     190            3 :                                 _static_destructor.owner = scope;
     191              :                         }
     192              :                 }
     193              :         }
     194              : 
     195              :         /**
     196              :          * Specifies the class destructor.
     197              :          */
     198              :         public Destructor? class_destructor {
     199      1174232 :                 get { return _class_destructor; }
     200            5 :                 private set {
     201           10 :                         _class_destructor = value;
     202            5 :                         if (_class_destructor != null) {
     203            5 :                                 _class_destructor.owner = scope;
     204              :                         }
     205              :                 }
     206              :         }
     207              : 
     208              :         /**
     209              :          * Specifies whether this class denotes an error base.
     210              :          */
     211              :         public bool is_error_base {
     212      7289962 :                 get {
     213      7289962 :                         return has_attribute ("ErrorBase");
     214              :                 }
     215              :         }
     216              : 
     217       374351 :         Constructor? _constructor;
     218       374351 :         Constructor? _class_constructor;
     219       374351 :         Constructor? _static_constructor;
     220       374351 :         Destructor? _destructor;
     221       374351 :         Destructor? _class_destructor;
     222       374351 :         Destructor? _static_destructor;
     223              : 
     224              :         /**
     225              :          * Creates a new class.
     226              :          *
     227              :          * @param name             type name
     228              :          * @param source_reference reference to source code
     229              :          * @param comment          class documentation
     230              :          * @return                 newly created class
     231              :          */
     232      1123058 :         public Class (string name, SourceReference? source_reference = null, Comment? comment = null) {
     233       374353 :                 base (name, source_reference, comment);
     234              :         }
     235              : 
     236              :         /**
     237              :          * Adds the specified class or interface to the list of base types of
     238              :          * this class.
     239              :          *
     240              :          * @param type a class or interface reference
     241              :          */
     242       338706 :         public void add_base_type (DataType type) {
     243       338706 :                 base_types.add (type);
     244       338706 :                 type.parent_node = this;
     245              :         }
     246              : 
     247              :         /**
     248              :          * Returns the base type list.
     249              :          *
     250              :          * @return list of base types
     251              :          */
     252      5962790 :         public unowned List<DataType> get_base_types () {
     253      5962790 :                 return base_types;
     254              :         }
     255              : 
     256              :         /**
     257              :          * Adds the specified field as a member to this class.
     258              :          *
     259              :          * @param f a field
     260              :          */
     261       285576 :         public override void add_field (Field f) {
     262       285576 :                 base.add_field (f);
     263              : 
     264       285576 :                 if (f.access == SymbolAccessibility.PRIVATE && f.binding == MemberBinding.INSTANCE) {
     265         2578 :                         has_private_fields = true;
     266       282998 :                 } else if (f.access == SymbolAccessibility.PRIVATE && f.binding == MemberBinding.CLASS) {
     267            4 :                         has_class_private_fields = true;
     268              :                 }
     269              :         }
     270              : 
     271              :         /**
     272              :          * Adds the specified method as a member to this class.
     273              :          *
     274              :          * @param m a method
     275              :          */
     276      4159527 :         public override void add_method (Method m) {
     277      4159527 :                 if (m.binding != MemberBinding.STATIC || m is CreationMethod) {
     278      3883260 :                         if (m.this_parameter != null) {
     279            0 :                                 m.scope.remove (m.this_parameter.name);
     280              :                         }
     281      3883260 :                         m.this_parameter = new Parameter ("this", SemanticAnalyzer.get_this_type (m, this), m.source_reference);
     282      3883260 :                         m.scope.add (m.this_parameter.name, m.this_parameter);
     283              :                 }
     284      4159527 :                 if (!(m.return_type is VoidType) && m.get_postconditions ().size > 0) {
     285            3 :                         if (m.result_var != null) {
     286            0 :                                 m.scope.remove (m.result_var.name);
     287              :                         }
     288            3 :                         m.result_var = new LocalVariable (m.return_type.copy (), "result", null, m.source_reference);
     289            3 :                         m.result_var.is_result = true;
     290              :                 }
     291      4159527 :                 if (m is CreationMethod) {
     292       537197 :                         if (m.name == null) {
     293       316388 :                                 default_construction_method = (CreationMethod) m;
     294       316388 :                                 m.name = ".new";
     295              :                         }
     296              : 
     297       537197 :                         unowned CreationMethod cm = (CreationMethod) m;
     298       537197 :                         if (cm.class_name != null && cm.class_name != name) {
     299              :                                 // class_name is null for constructors generated by GIdlParser
     300            1 :                                 Report.error (m.source_reference, "missing return type in method `%s.%s´", get_full_name (), cm.class_name);
     301            1 :                                 m.error = true;
     302            1 :                                 return;
     303              :                         }
     304       537196 :                         if (is_abstract && cm.access == SymbolAccessibility.PUBLIC) {
     305              :                                 //TODO Report an error for external constructors too
     306            1 :                                 if (external_package) {
     307            0 :                                         Report.warning (m.source_reference, "Creation method of abstract class cannot be public.");
     308              :                                 } else {
     309            1 :                                         Report.error (m.source_reference, "Creation method of abstract class cannot be public.");
     310            1 :                                         error = true;
     311            1 :                                         return;
     312              :                                 }
     313              :                         }
     314              :                 }
     315              : 
     316      4159525 :                 base.add_method (m);
     317              :         }
     318              : 
     319          124 :         public HashMap<Method,Method> get_implicit_implementations () {
     320          124 :                 return implicit_implementations;
     321              :         }
     322              : 
     323              :         /**
     324              :          * Adds the specified property as a member to this class.
     325              :          *
     326              :          * @param prop a property
     327              :          */
     328       400046 :         public override void add_property (Property prop) {
     329       400046 :                 base.add_property (prop);
     330              : 
     331       400046 :                 if (prop.binding != MemberBinding.STATIC) {
     332       400042 :                         prop.this_parameter = new Parameter ("this", SemanticAnalyzer.get_this_type (prop, this), prop.source_reference);
     333       400042 :                         prop.scope.add (prop.this_parameter.name, prop.this_parameter);
     334              :                 }
     335              : 
     336       400046 :                 if (prop.field != null) {
     337          496 :                         add_field (prop.field);
     338              :                 }
     339              :         }
     340              : 
     341           47 :         public override void add_constructor (Constructor c) {
     342           47 :                 switch (c.binding) {
     343              :                 case MemberBinding.INSTANCE:
     344           28 :                         if (constructor != null) {
     345            1 :                                 Report.error (c.source_reference, "class already contains a constructor");
     346              :                         }
     347           28 :                         constructor = c;
     348           28 :                         break;
     349              :                 case MemberBinding.CLASS:
     350           10 :                         if (class_constructor != null) {
     351            1 :                                 Report.error (c.source_reference, "class already contains a class constructor");
     352              :                         }
     353           10 :                         class_constructor = c;
     354           10 :                         break;
     355              :                 case MemberBinding.STATIC:
     356            9 :                         if (static_constructor != null) {
     357            1 :                                 Report.error (c.source_reference, "class already contains a static constructor");
     358              :                         }
     359            9 :                         static_constructor = c;
     360            9 :                         break;
     361              :                 default:
     362            0 :                         assert_not_reached ();
     363              :                 }
     364              : 
     365           47 :                 if (c.binding != MemberBinding.STATIC) {
     366           38 :                         if (c.this_parameter != null) {
     367            0 :                                 c.scope.remove (c.this_parameter.name);
     368              :                         }
     369           38 :                         c.this_parameter = new Parameter ("this", SemanticAnalyzer.get_this_type (c, this), c.source_reference);
     370           38 :                         c.scope.add (c.this_parameter.name, c.this_parameter);
     371              :                 }
     372              :         }
     373              : 
     374           26 :         public override void add_destructor (Destructor d) {
     375           26 :                 switch (d.binding) {
     376              :                 case MemberBinding.INSTANCE:
     377           18 :                         if (destructor != null) {
     378            1 :                                 Report.error (d.source_reference, "class already contains a destructor");
     379              :                         }
     380           18 :                         destructor = d;
     381           18 :                         break;
     382              :                 case MemberBinding.CLASS:
     383            5 :                         if (class_destructor != null) {
     384            1 :                                 Report.error (d.source_reference, "class already contains a class destructor");
     385              :                         }
     386            5 :                         class_destructor = d;
     387            5 :                         break;
     388              :                 case MemberBinding.STATIC:
     389            3 :                         if (static_destructor != null) {
     390            1 :                                 Report.error (d.source_reference, "class already contains a static destructor");
     391              :                         }
     392            3 :                         static_destructor = d;
     393            3 :                         break;
     394              :                 default:
     395            0 :                         assert_not_reached ();
     396              :                 }
     397              : 
     398           26 :                 if (d.binding != MemberBinding.STATIC) {
     399           23 :                         if (d.this_parameter != null) {
     400            0 :                                 d.scope.remove (d.this_parameter.name);
     401              :                         }
     402           23 :                         d.this_parameter = new Parameter ("this", SemanticAnalyzer.get_this_type (d, this), d.source_reference);
     403           23 :                         d.scope.add (d.this_parameter.name, d.this_parameter);
     404              :                 }
     405              :         }
     406              : 
     407       847705 :         public override void accept (CodeVisitor visitor) {
     408       847705 :                 visitor.visit_class (this);
     409              :         }
     410              : 
     411       824357 :         public override void accept_children (CodeVisitor visitor) {
     412      2324833 :                 foreach (DataType type in base_types) {
     413       750238 :                         type.accept (visitor);
     414              :                 }
     415              : 
     416              :                 // Invoke common implementation in ObjectTypeSymbol
     417       824357 :                 base.accept_children (visitor);
     418              : 
     419       824357 :                 if (constructor != null) {
     420           83 :                         constructor.accept (visitor);
     421              :                 }
     422              : 
     423       824357 :                 if (class_constructor != null) {
     424           29 :                         class_constructor.accept (visitor);
     425              :                 }
     426              : 
     427       824357 :                 if (static_constructor != null) {
     428           28 :                         static_constructor.accept (visitor);
     429              :                 }
     430              : 
     431       824357 :                 if (destructor != null) {
     432           52 :                         destructor.accept (visitor);
     433              :                 }
     434              : 
     435       824357 :                 if (static_destructor != null) {
     436            4 :                         static_destructor.accept (visitor);
     437              :                 }
     438              : 
     439       824357 :                 if (class_destructor != null) {
     440           12 :                         class_destructor.accept (visitor);
     441              :                 }
     442              :         }
     443              : 
     444       150042 :         public override bool is_reference_type () {
     445       150042 :                 return true;
     446              :         }
     447              : 
     448         5015 :         public bool is_fundamental () {
     449         5015 :                 if (!is_compact && base_class == null) {
     450              :                         return true;
     451              :                 }
     452              :                 return false;
     453              :         }
     454              : 
     455      5589897 :         public override bool is_subtype_of (TypeSymbol t) {
     456      5589897 :                 if (this == t) {
     457      3735478 :                         return true;
     458              :                 }
     459              : 
     460      4411824 :                 foreach (DataType base_type in base_types) {
     461      4326038 :                         if (base_type.type_symbol != null && base_type.type_symbol != this
     462      2140790 :                             && base_type.type_symbol.is_subtype_of (t)) {
     463      1813091 :                                 return true;
     464              :                         }
     465              :                 }
     466              : 
     467      5589897 :                 return false;
     468              :         }
     469              : 
     470       316346 :         public override void replace_type (DataType old_type, DataType new_type) {
     471       456846 :                 for (int i = 0; i < base_types.size; i++) {
     472       456846 :                         if (base_types[i] == old_type) {
     473       316346 :                                 base_types[i] = new_type;
     474       316346 :                                 new_type.parent_node = this;
     475       316346 :                                 return;
     476              :                         }
     477              :                 }
     478              :         }
     479              : 
     480       107389 :         private void get_all_prerequisites (Interface iface, List<TypeSymbol> list) {
     481       327797 :                 foreach (DataType prereq in iface.get_prerequisites ()) {
     482       110204 :                         TypeSymbol type = prereq.type_symbol;
     483              :                         /* skip on previous errors */
     484       110204 :                         if (type == null) {
     485            0 :                                 continue;
     486              :                         }
     487              : 
     488       110204 :                         list.add (type);
     489       110204 :                         if (type is Interface) {
     490         5685 :                                 get_all_prerequisites ((Interface) type, list);
     491              : 
     492              :                         }
     493              :                 }
     494              :         }
     495              : 
     496       298949 :         public bool is_a (ObjectTypeSymbol t) {
     497       298949 :                 if (this == t) {
     498       293264 :                         return true;
     499              :                 }
     500              : 
     501       208798 :                 foreach (DataType base_type in get_base_types ()) {
     502       195929 :                         if (base_type.type_symbol is Class) {
     503       188745 :                                 if (((Class) base_type.type_symbol).is_a (t)) {
     504       183062 :                                         return true;
     505              :                                 }
     506         7184 :                         } else if (base_type.type_symbol == t) {
     507         5683 :                                 return true;
     508              :                         }
     509              :                 }
     510              : 
     511       298949 :                 return false;
     512              :         }
     513              : 
     514            8 :         public bool implements (Interface i) {
     515           24 :                 foreach (DataType base_type in get_base_types ()) {
     516            9 :                         if (base_type.type_symbol == i) {
     517            1 :                                 return true;
     518              :                         }
     519              :                 }
     520              : 
     521            8 :                 return false;
     522              :         }
     523              : 
     524     19504791 :         public override bool check (CodeContext context) {
     525     19504791 :                 if (checked) {
     526     19157453 :                         return !error;
     527              :                 }
     528              : 
     529       347338 :                 if (!base.check (context)) {
     530            9 :                         return false;
     531              :                 }
     532              : 
     533       347338 :                 checked = true;
     534              : 
     535       347338 :                 var old_source_file = context.analyzer.current_source_file;
     536       347338 :                 var old_symbol = context.analyzer.current_symbol;
     537              : 
     538       347338 :                 if (source_reference != null) {
     539       347338 :                         context.analyzer.current_source_file = source_reference.file;
     540              :                 }
     541       347338 :                 context.analyzer.current_symbol = this;
     542              : 
     543       662431 :                 foreach (DataType base_type_reference in get_base_types ()) {
     544       315098 :                         if (!base_type_reference.check (context)) {
     545            2 :                                 error = true;
     546            2 :                                 return false;
     547              :                         }
     548              : 
     549       315096 :                         if (!(base_type_reference is ObjectType)) {
     550            1 :                                 error = true;
     551            1 :                                 Report.error (source_reference, "base type `%s' of class `%s' is not an object type", base_type_reference.to_string (), get_full_name ());
     552            1 :                                 return false;
     553              :                         }
     554              : 
     555              :                         // check whether base type is at least as accessible as the class
     556       315095 :                         if (!base_type_reference.is_accessible (this)) {
     557            1 :                                 error = true;
     558            1 :                                 Report.error (source_reference, "base type `%s' is less accessible than class `%s'", base_type_reference.to_string (), get_full_name ());
     559            1 :                                 return false;
     560              :                         }
     561              : 
     562              :                         // check whether there is the expected amount of type-arguments
     563       315094 :                         if (!base_type_reference.check_type_arguments (context)) {
     564            1 :                                 error = true;
     565            1 :                                 return false;
     566              :                         }
     567              :                 }
     568              : 
     569       977519 :                 foreach (DataType type in base_types) {
     570       315093 :                         type.check (context);
     571       315093 :                         context.analyzer.check_type (type);
     572              :                 }
     573              : 
     574       347333 :                 if (base_class != null && base_class.is_singleton) {
     575            1 :                         error = true;
     576            1 :                         Report.error (source_reference, "`%s' cannot inherit from SingleInstance class `%s'", get_full_name (), base_class.get_full_name ());
     577              :                 }
     578              : 
     579       347333 :                 if (is_singleton && !is_subtype_of (context.analyzer.object_type)) {
     580            1 :                         error = true;
     581            1 :                         Report.error (source_reference, "SingleInstance class `%s' requires inheritance from `GLib.Object'", get_full_name ());
     582              :                 }
     583              : 
     584              :                 /* singleton classes require an instance constructor */
     585       347337 :                 if (is_singleton && constructor == null) {
     586            4 :                         var c = new Constructor (source_reference);
     587            4 :                         c.body = new Block (source_reference);
     588            4 :                         add_constructor (c);
     589              :                 }
     590              : 
     591       347333 :                 if (!external_package && base_class != null && base_class.is_sealed) {
     592            1 :                         error = true;
     593            1 :                         Report.error (source_reference, "`%s' cannot inherit from sealed class `%s'", get_full_name (), base_class.get_full_name ());
     594              :                 }
     595              : 
     596       347333 :                 if (is_sealed) {
     597        46859 :                         if (is_compact) {
     598            1 :                                 error = true;
     599            1 :                                 Report.error (source_reference, "Sealed class `%s' cannot be compact", get_full_name ());
     600            1 :                                 return false;
     601              :                         }
     602        46858 :                         if (is_abstract) {
     603            1 :                                 error = true;
     604            1 :                                 Report.error (source_reference, "Sealed class `%s' cannot be abstract", get_full_name ());
     605            1 :                                 return false;
     606              :                         }
     607              :                 }
     608              : 
     609       347331 :                 if (base_class != null && !base_class.is_compact && has_attribute ("Compact")) {
     610            1 :                         error = true;
     611            1 :                         Report.error (source_reference, "Compact class `%s' cannot inherit from non-compact class `%s'", get_full_name (), base_class.get_full_name ());
     612            1 :                         return false;
     613              :                 }
     614              : 
     615              :                 /* process enums first to avoid order problems in C code */
     616       350242 :                 foreach (Enum en in get_enums ()) {
     617         1456 :                         en.check (context);
     618              :                 }
     619              : 
     620       879224 :                 foreach (Field f in get_fields ()) {
     621       265947 :                         if (is_compact && f.binding != MemberBinding.STATIC) {
     622              :                                 //FIXME Should external bindings follow this too?
     623       135242 :                                 if (!external_package && !is_opaque && f.access == SymbolAccessibility.PRIVATE) {
     624            2 :                                         Report.error (f.source_reference, "private fields are only supported in opaque compact classes, use [Compact (opaque = true)]");
     625            2 :                                         error = true;
     626              :                                 }
     627       135242 :                                 if (!external_package && is_opaque && (f.access == SymbolAccessibility.PUBLIC || f.access == SymbolAccessibility.PROTECTED)) {
     628            1 :                                         Report.error (f.source_reference, "fields in opaque compact classes must be private or internal");
     629            1 :                                         error = true;
     630              :                                 }
     631       135242 :                                 if (f.binding == MemberBinding.CLASS) {
     632            2 :                                         Report.error (f.source_reference, "class fields are not supported in compact classes");
     633            2 :                                         error = true;
     634              :                                 }
     635              :                         }
     636              : 
     637       265947 :                         f.check (context);
     638              :                 }
     639              : 
     640       431644 :                 foreach (Constant c in get_constants ()) {
     641        42157 :                         c.check (context);
     642              :                 }
     643              : 
     644      8066762 :                 foreach (Method m in get_methods ()) {
     645      3859716 :                         m.check (context);
     646              :                 }
     647              : 
     648      1092220 :                 foreach (Property prop in get_properties ()) {
     649       372446 :                         if (prop.has_attribute ("NoAccessorMethod") && !is_subtype_of (context.analyzer.object_type)) {
     650            1 :                                 error = true;
     651            1 :                                 Report.error (prop.source_reference, "NoAccessorMethod is only allowed for properties in classes derived from GLib.Object");
     652            1 :                                 return false;
     653              :                         }
     654       372445 :                         prop.check (context);
     655              :                 }
     656              : 
     657       535129 :                 foreach (Signal sig in get_signals ()) {
     658        93900 :                         sig.check (context);
     659              :                 }
     660              : 
     661       347329 :                 if (constructor != null) {
     662           24 :                         constructor.check (context);
     663              :                 }
     664              : 
     665       347329 :                 if (class_constructor != null) {
     666            8 :                         class_constructor.check (context);
     667              :                 }
     668              : 
     669       347329 :                 if (static_constructor != null) {
     670            7 :                         static_constructor.check (context);
     671              :                 }
     672              : 
     673       347329 :                 if (destructor != null) {
     674           13 :                         destructor.check (context);
     675              :                 }
     676              : 
     677       347329 :                 if (static_destructor != null) {
     678            1 :                         static_destructor.check (context);
     679              :                 }
     680              : 
     681       347329 :                 if (class_destructor != null) {
     682            3 :                         class_destructor.check (context);
     683              :                 }
     684              : 
     685       347369 :                 foreach (Class cl in get_classes ()) {
     686           20 :                         cl.check (context);
     687              :                 }
     688              : 
     689       347333 :                 foreach (Interface iface in get_interfaces ()) {
     690            2 :                         iface.check (context);
     691              :                 }
     692              : 
     693       347337 :                 foreach (Struct st in get_structs ()) {
     694            4 :                         st.check (context);
     695              :                 }
     696              : 
     697       347371 :                 foreach (Delegate d in get_delegates ()) {
     698           21 :                         d.check (context);
     699              :                 }
     700              : 
     701              :                 /* compact classes cannot implement interfaces */
     702       347329 :                 if (is_compact) {
     703       194423 :                         foreach (DataType base_type in get_base_types ()) {
     704        22302 :                                 if (base_type.type_symbol is Interface) {
     705            1 :                                         error = true;
     706            1 :                                         Report.error (source_reference, "compact classes `%s' may not implement interfaces", get_full_name ());
     707              :                                 }
     708              :                         }
     709              : 
     710       149819 :                         if (!external && !external_package && base_class != null && !base_class.is_subtype_of (context.analyzer.gsource_type)) {
     711           15 :                                 foreach (Field f in get_fields ()) {
     712            1 :                                         if (f.binding == MemberBinding.INSTANCE) {
     713            1 :                                                 error = true;
     714            1 :                                                 Report.error (source_reference, "derived compact classes may not have instance fields");
     715            1 :                                                 break;
     716              :                                         }
     717              :                                 }
     718              :                         }
     719              :                 }
     720              : 
     721              :                 /* gather all prerequisites */
     722       347329 :                 List<TypeSymbol> prerequisites = new ArrayList<TypeSymbol> ();
     723       977513 :                 foreach (DataType base_type in get_base_types ()) {
     724       315092 :                         if (base_type.type_symbol is Interface) {
     725       101704 :                                 get_all_prerequisites ((Interface) base_type.type_symbol, prerequisites);
     726              :                         }
     727              :                 }
     728              :                 /* check whether all prerequisites are met */
     729       347329 :                 List<string> missing_prereqs = new ArrayList<string> (str_equal);
     730       567737 :                 foreach (TypeSymbol prereq in prerequisites) {
     731       110204 :                         if (!is_a ((ObjectTypeSymbol) prereq)) {
     732            2 :                                 missing_prereqs.insert (0, prereq.get_full_name ());
     733              :                         }
     734              :                 }
     735              :                 /* report any missing prerequisites */
     736       347330 :                 if (missing_prereqs.size > 0) {
     737            1 :                         error = true;
     738              : 
     739            1 :                         string error_string = "%s: some prerequisites (".printf (get_full_name ());
     740            1 :                         bool first = true;
     741            5 :                         foreach (string s in missing_prereqs) {
     742            2 :                                 if (first) {
     743            1 :                                         error_string = "%s`%s'".printf (error_string, s);
     744              :                                         first = false;
     745              :                                 } else {
     746            1 :                                         error_string = "%s, `%s'".printf (error_string, s);
     747              :                                 }
     748              :                         }
     749            1 :                         error_string += ") are not met";
     750            1 :                         Report.error (source_reference, error_string);
     751              :                 }
     752              : 
     753              :                 /* VAPI classes don't have to specify overridden methods */
     754       347329 :                 if (source_type == SourceFileType.SOURCE) {
     755              :                         /* all abstract symbols defined in base types have to be at least defined (or implemented) also in this type */
     756         2680 :                         foreach (DataType base_type in get_base_types ()) {
     757          787 :                                 if (base_type.type_symbol is Interface) {
     758          146 :                                         unowned Interface iface = (Interface) base_type.type_symbol;
     759              : 
     760          146 :                                         if (base_class != null && base_class.is_subtype_of (iface)) {
     761              :                                                 // reimplementation of interface, class is not required to reimplement all methods
     762            3 :                                                 break;
     763              :                                         }
     764              : 
     765              :                                         /* We do not need to do expensive equality checking here since this is done
     766              :                                          * already. We only need to guarantee the symbols are present.
     767              :                                          */
     768              : 
     769              :                                         /* check methods */
     770          415 :                                         foreach (Method m in iface.get_methods ()) {
     771          136 :                                                 if (m.is_abstract) {
     772              :                                                         var implemented = false;
     773              :                                                         unowned Class? base_class = this;
     774          203 :                                                         while (base_class != null && !implemented) {
     775         1370 :                                                                 foreach (var impl in base_class.get_methods ()) {
     776          725 :                                                                         if (impl.base_interface_method == m || (base_class != this
     777          298 :                                                                             && impl.base_interface_method == null && impl.name == m.name
     778            3 :                                                                             && (impl.base_interface_type == null || impl.base_interface_type.type_symbol == iface)
     779            3 :                                                                             && impl.compatible_no_error (m))) {
     780              :                                                                                 // method is used as interface implementation, so it is not unused
     781           90 :                                                                                 impl.version.check (context, source_reference);
     782           90 :                                                                                 impl.used = true;
     783           90 :                                                                                 implemented = true;
     784           90 :                                                                                 if (impl.base_interface_method == null) {
     785            2 :                                                                                         implicit_implementations.set (m, impl);
     786              :                                                                                 }
     787           90 :                                                                                 break;
     788              :                                                                         }
     789              :                                                                 }
     790          106 :                                                                 base_class = base_class.base_class;
     791              :                                                         }
     792           97 :                                                         if (!implemented) {
     793            7 :                                                                 error = true;
     794            7 :                                                                 Report.error (source_reference, "`%s' does not implement interface method `%s'", get_full_name (), m.get_full_name ());
     795              :                                                         }
     796              :                                                 }
     797              :                                         }
     798              : 
     799              :                                         /* check properties */
     800          229 :                                         foreach (Property prop in iface.get_properties ()) {
     801           84 :                                                 if (prop.is_abstract) {
     802              :                                                         Symbol sym = null;
     803              :                                                         unowned Class? base_class = this;
     804           85 :                                                         while (base_class != null && !(sym is Property)) {
     805           44 :                                                                 sym = base_class.scope.lookup (prop.name);
     806           44 :                                                                 base_class = base_class.base_class;
     807              :                                                         }
     808           81 :                                                         if (sym is Property) {
     809           40 :                                                                 var base_prop = (Property) sym;
     810           40 :                                                                 string? invalid_match = null;
     811              :                                                                 // No check at all for "new" classified properties, really?
     812           40 :                                                                 if (!base_prop.hides && !base_prop.compatible (prop, out invalid_match)) {
     813            4 :                                                                         error = true;
     814            4 :                                                                         Report.error (source_reference, "Type and/or accessors of inherited properties `%s' and `%s' do not match: %s.", prop.get_full_name (), base_prop.get_full_name (), invalid_match);
     815              :                                                                 }
     816              :                                                                 // property is used as interface implementation, so it is not unused
     817           40 :                                                                 sym.version.check (context, source_reference);
     818           40 :                                                                 sym.used = true;
     819              :                                                         } else {
     820            1 :                                                                 error = true;
     821            1 :                                                                 Report.error (source_reference, "`%s' does not implement interface property `%s'", get_full_name (), prop.get_full_name ());
     822              :                                                         }
     823              :                                                 }
     824              :                                         }
     825              :                                 }
     826              :                         }
     827              : 
     828              :                         /* all abstract symbols defined in base classes have to be implemented in non-abstract classes */
     829         1112 :                         if (!is_abstract) {
     830         1050 :                                 unowned Class? base_class = base_class;
     831         1303 :                                 while (base_class != null && base_class.is_abstract) {
     832         5713 :                                         foreach (Method base_method in base_class.get_methods ()) {
     833         3017 :                                                 if (base_method.is_abstract) {
     834          287 :                                                         var override_method = SemanticAnalyzer.symbol_lookup_inherited (this, base_method.name) as Method;
     835          287 :                                                         if (override_method == null || !override_method.overrides) {
     836            1 :                                                                 error = true;
     837            1 :                                                                 Report.error (source_reference, "`%s' does not implement abstract method `%s'", get_full_name (), base_method.get_full_name ());
     838              :                                                         }
     839              :                                                 }
     840              :                                         }
     841         1177 :                                         foreach (Property base_property in base_class.get_properties ()) {
     842          491 :                                                 if (base_property.is_abstract) {
     843           29 :                                                         var override_property = SemanticAnalyzer.symbol_lookup_inherited (this, base_property.name) as Property;
     844           29 :                                                         if (override_property == null || !override_property.overrides) {
     845            1 :                                                                 error = true;
     846            1 :                                                                 Report.error (source_reference, "`%s' does not implement abstract property `%s'", get_full_name (), base_property.get_full_name ());
     847              :                                                         }
     848              :                                                 }
     849              :                                         }
     850          253 :                                         base_class = base_class.base_class;
     851              :                                 }
     852              :                         }
     853              :                 }
     854              : 
     855       347329 :                 context.analyzer.current_source_file = old_source_file;
     856       347329 :                 context.analyzer.current_symbol = old_symbol;
     857              : 
     858       347329 :                 return !error;
     859              :         }
     860              : }
     861              : 
     862              : // vim:sw=8 noet
        

Generated by: LCOV version 2.0-1