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

            Line data    Source code
       1              : /* valadelegate.vala
       2              :  *
       3              :  * Copyright (C) 2006-2010  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 function callback type.
      27              :  */
      28       386930 : public class Vala.Delegate : TypeSymbol, Callable, GenericSymbol {
      29              :         /**
      30              :          * The return type of this callback.
      31              :          */
      32              :         public DataType return_type {
      33       775346 :                 get { return _return_type; }
      34       268822 :                 set {
      35       282072 :                         _return_type = value;
      36       268822 :                         _return_type.parent_node = this;
      37              :                 }
      38              :         }
      39              : 
      40              :         /**
      41              :          * Specifies whether callback supports calling instance methods.
      42              :          * The reference to the object instance will be appended to the end of
      43              :          * the argument list in the generated C code.
      44              :          */
      45              :         public bool has_target {
      46        54166 :                 get {
      47        54166 :                         if (_has_target == null) {
      48        44444 :                                 _has_target = get_attribute_bool ("CCode", "has_target", true);
      49              :                         }
      50        54166 :                         return _has_target;
      51              :                 }
      52          338 :                 set {
      53          338 :                         _has_target = value;
      54          338 :                         if (value) {
      55          103 :                                 remove_attribute_argument ("CCode", "has_target");
      56              :                         } else {
      57          235 :                                 set_attribute_bool ("CCode", "has_target", false);
      58              :                         }
      59              :                 }
      60              :         }
      61              : 
      62       198590 :         public DataType? sender_type { get; set; }
      63              : 
      64       382316 :         private List<TypeParameter> type_parameters = new ArrayList<TypeParameter> ();
      65              : 
      66       382316 :         private List<Parameter> parameters = new ArrayList<Parameter> ();
      67              : 
      68       191158 :         private DataType _return_type;
      69       191158 :         private bool? _has_target;
      70              : 
      71       191158 :         private List<DataType> error_types;
      72              : 
      73              :         /**
      74              :          * Creates a new delegate.
      75              :          *
      76              :          * @param name              delegate type name
      77              :          * @param return_type       return type
      78              :          * @param source_reference  reference to source code
      79              :          * @return                  newly created delegate
      80              :          */
      81       573474 :         public Delegate (string? name, DataType return_type, SourceReference? source_reference = null, Comment? comment = null) {
      82       191158 :                 base (name, source_reference, comment);
      83       191158 :                 this.return_type = return_type;
      84              :         }
      85              : 
      86              :         /**
      87              :          * Appends the specified parameter to the list of type parameters.
      88              :          *
      89              :          * @param p a type parameter
      90              :          */
      91        42866 :         public void add_type_parameter (TypeParameter p) {
      92        42866 :                 type_parameters.add (p);
      93        42866 :                 scope.add (p.name, p);
      94              :         }
      95              : 
      96      1090758 :         public unowned List<TypeParameter> get_type_parameters () {
      97      1090758 :                 return type_parameters;
      98              :         }
      99              : 
     100          108 :         public bool has_type_parameters () {
     101          108 :                 return (type_parameters != null && type_parameters.size > 0);
     102              :         }
     103              : 
     104        32593 :         public override int get_type_parameter_index (string name) {
     105        32593 :                 int i = 0;
     106        38259 :                 foreach (TypeParameter parameter in type_parameters) {
     107        35426 :                         if (parameter.name == name) {
     108        32593 :                                 return i;
     109              :                         }
     110         2833 :                         i++;
     111              :                 }
     112        32593 :                 return -1;
     113              :         }
     114              : 
     115              :         /**
     116              :          * Appends parameter to this callback function.
     117              :          *
     118              :          * @param param a formal parameter
     119              :          */
     120       405983 :         public void add_parameter (Parameter param) {
     121       405983 :                 parameters.add (param);
     122       405983 :                 scope.add (param.name, param);
     123              :         }
     124              : 
     125              :         /**
     126              :          * Return the parameter list.
     127              :          *
     128              :          * @return parameter list
     129              :          */
     130        21873 :         public unowned List<Parameter> get_parameters () {
     131        21873 :                 return parameters;
     132              :         }
     133              : 
     134              :         /**
     135              :          * Checks whether the arguments and return type of the specified method
     136              :          * matches this callback.
     137              :          *
     138              :          * @param m a method
     139              :          * @return  true if the specified method is compatible to this callback
     140              :          */
     141         7740 :         public bool matches_method (Method m, DataType dt) {
     142         7740 :                 if (m.coroutine && !(parent_symbol is Signal)) {
     143              :                         // async delegates are not yet supported
     144            8 :                         return false;
     145              :                 }
     146              : 
     147              :                 // method is allowed to ensure stricter return type (stronger postcondition)
     148         7740 :                 if (!m.return_type.stricter (return_type.get_actual_type (dt, null, this))) {
     149            8 :                         return false;
     150              :                 }
     151              : 
     152         7740 :                 var method_params = m.get_parameters ();
     153         7740 :                 Iterator<Parameter> method_params_it = method_params.iterator ();
     154              : 
     155         7753 :                 if (sender_type != null && method_params.size == parameters.size + 1) {
     156              :                         // method has sender parameter
     157           14 :                         method_params_it.next ();
     158              : 
     159              :                         // method is allowed to accept arguments of looser types (weaker precondition)
     160           14 :                         var method_param = method_params_it.get ();
     161           14 :                         if (!sender_type.stricter (method_param.variable_type)) {
     162            1 :                                 return false;
     163              :                         }
     164              :                 }
     165              : 
     166         7739 :                 bool first = true;
     167        33973 :                 foreach (Parameter param in parameters) {
     168        13165 :                         Parameter? method_param = null;
     169              :                         DataType method_param_type;
     170              :                         /* use first callback parameter as instance parameter if
     171              :                          * an instance method is being compared to a static
     172              :                          * callback
     173              :                          */
     174        13165 :                         if (first && m.binding == MemberBinding.INSTANCE && !has_target) {
     175            6 :                                 first = false;
     176            6 :                                 method_param_type = SemanticAnalyzer.get_data_type_for_symbol (m.parent_symbol);
     177              :                         } else {
     178              :                                 /* method is allowed to accept less arguments */
     179        13159 :                                 if (!method_params_it.next ()) {
     180           23 :                                         break;
     181              :                                 }
     182        13136 :                                 method_param = method_params_it.get ();
     183        13136 :                                 method_param_type = method_param.variable_type;
     184              :                         }
     185              : 
     186        13142 :                         if (method_param != null && (param.ellipsis || param.params_array)) {
     187           23 :                                 if (param.ellipsis != method_param.ellipsis || param.params_array != method_param.params_array) {
     188            0 :                                         return false;
     189              :                                 }
     190           23 :                                 break;
     191              :                         }
     192              : 
     193              :                         // method is allowed to accept arguments of looser types (weaker precondition)
     194        13119 :                         if (!param.variable_type.get_actual_type (dt, null, this).stricter (method_param_type)) {
     195            2 :                                 return false;
     196              :                         }
     197              :                 }
     198              : 
     199              :                 // delegate without target for instance method or closure
     200         7737 :                 if (first && !has_target && (m.binding == MemberBinding.INSTANCE || m.closure) && (parameters.size == 0 || m.closure)) {
     201            3 :                         return false;
     202              :                 }
     203              : 
     204              :                 /* method may not expect more arguments */
     205         7734 :                 if (method_params_it.next ()) {
     206            0 :                         return false;
     207              :                 }
     208              : 
     209         7734 :                 var method_error_types = new ArrayList<DataType> ();
     210         7734 :                 m.get_error_types (method_error_types);
     211              : 
     212              :                 // method must throw error if the delegate does
     213         7734 :                 if (error_types != null && error_types.size > 0 && method_error_types.size == 0) {
     214            1 :                         return false;
     215              :                 }
     216              : 
     217              :                 // method may throw less but not more errors than the delegate
     218         8125 :                 foreach (DataType method_error_type in method_error_types) {
     219          197 :                         bool match = false;
     220          197 :                         if (error_types != null) {
     221          199 :                                 foreach (DataType delegate_error_type in error_types) {
     222          197 :                                         if (method_error_type.compatible (delegate_error_type)) {
     223          196 :                                                 match = true;
     224          196 :                                                 break;
     225              :                                         }
     226              :                                 }
     227              :                         }
     228              : 
     229          196 :                         if (!match) {
     230            1 :                                 return false;
     231              :                         }
     232              :                 }
     233              : 
     234         7732 :                 return true;
     235              :         }
     236              : 
     237       430342 :         public override void accept (CodeVisitor visitor) {
     238       430342 :                 visitor.visit_delegate (this);
     239              :         }
     240              : 
     241       297579 :         public override void accept_children (CodeVisitor visitor) {
     242       430515 :                 foreach (TypeParameter p in type_parameters) {
     243        66468 :                         p.accept (visitor);
     244              :                 }
     245              : 
     246       297579 :                 return_type.accept (visitor);
     247              : 
     248      1563891 :                 foreach (Parameter param in parameters) {
     249       633156 :                         param.accept (visitor);
     250              :                 }
     251              : 
     252       297579 :                 if (error_types != null) {
     253        58341 :                         foreach (DataType error_type in error_types) {
     254        19447 :                                 error_type.accept (visitor);
     255              :                         }
     256              :                 }
     257              :         }
     258              : 
     259          361 :         public override bool is_reference_type () {
     260          361 :                 return false;
     261              :         }
     262              : 
     263              :         /**
     264              :          * Adds an error type to the exceptions that can be
     265              :          * thrown by this delegate.
     266              :          */
     267        12495 :         public void add_error_type (DataType error_type) {
     268        12495 :                 if (error_types == null) {
     269        12495 :                         error_types = new ArrayList<DataType> ();
     270              :                 }
     271        12495 :                 error_types.add (error_type);
     272        12495 :                 error_type.parent_node = this;
     273              :         }
     274              : 
     275        45446 :         public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
     276        45446 :                 if (error_types != null) {
     277          804 :                         foreach (var error_type in error_types) {
     278          370 :                                 if (source_reference != null) {
     279          102 :                                         var type = error_type.copy ();
     280          102 :                                         type.source_reference = source_reference;
     281          102 :                                         collection.add (type);
     282              :                                 } else {
     283          166 :                                         collection.add (error_type);
     284              :                                 }
     285              :                         }
     286              :                 }
     287              :         }
     288              : 
     289        89247 :         public override void replace_type (DataType old_type, DataType new_type) {
     290        89247 :                 if (return_type == old_type) {
     291        77621 :                         return_type = new_type;
     292        77621 :                         return;
     293              :                 }
     294        11626 :                 if (error_types != null) {
     295        11626 :                         for (int i = 0; i < error_types.size; i++) {
     296        11626 :                                 if (error_types[i] == old_type) {
     297        11626 :                                         error_types[i] = new_type;
     298        11626 :                                         return;
     299              :                                 }
     300              :                         }
     301              :                 }
     302              :         }
     303              : 
     304      1090044 :         public override bool check (CodeContext context) {
     305      1090044 :                 if (checked) {
     306       912862 :                         return !error;
     307              :                 }
     308              : 
     309       177182 :                 checked = true;
     310              : 
     311       177182 :                 var old_source_file = context.analyzer.current_source_file;
     312              : 
     313       177182 :                 if (source_reference != null) {
     314       177182 :                         context.analyzer.current_source_file = source_reference.file;
     315              :                 }
     316              : 
     317       256530 :                 foreach (TypeParameter p in get_type_parameters ()) {
     318        39674 :                         if (!p.check (context)) {
     319            0 :                                 error = true;
     320              :                         }
     321              :                 }
     322              : 
     323       177182 :                 return_type.check (context);
     324       177182 :                 if (!external_package) {
     325          262 :                         context.analyzer.check_type (return_type);
     326          262 :                         return_type.check_type_arguments (context, !(return_type is DelegateType));
     327              :                 }
     328              : 
     329       177182 :                 if (return_type.type_symbol == context.analyzer.va_list_type.type_symbol) {
     330            1 :                         error = true;
     331            1 :                         Report.error (source_reference, "`%s' not supported as return type", return_type.type_symbol.get_full_name ());
     332            1 :                         return false;
     333              :                 }
     334              : 
     335       930381 :                 foreach (Parameter param in parameters) {
     336       376600 :                         if (!param.check (context)) {
     337            0 :                                 error = true;
     338              :                         }
     339              :                 }
     340              : 
     341       177181 :                 if (error_types != null) {
     342        34738 :                         foreach (DataType error_type in error_types) {
     343        11580 :                                 if (!(error_type is ErrorType)) {
     344            1 :                                         error = true;
     345            1 :                                         Report.error (error_type.source_reference, "`%s' is not an error type", error_type.to_string ());
     346              :                                 }
     347        11580 :                                 error_type.check (context);
     348              : 
     349              :                                 // check whether error type is at least as accessible as the delegate
     350        11580 :                                 if (!error_type.is_accessible (this)) {
     351            1 :                                         error = true;
     352            1 :                                         Report.error (source_reference, "error type `%s' is less accessible than delegate `%s'", error_type.to_string (), get_full_name ());
     353            1 :                                         return false;
     354              :                                 }
     355              :                         }
     356              :                 }
     357              : 
     358       177180 :                 context.analyzer.current_source_file = old_source_file;
     359              : 
     360       177180 :                 return !error;
     361              :         }
     362              : }
        

Generated by: LCOV version 2.0-1