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

            Line data    Source code
       1              : /* valamethod.vala
       2              :  *
       3              :  * Copyright (C) 2006-2010  Jürg Billeter
       4              :  * Copyright (C) 2006-2008  Raffaele Sandrini
       5              :  *
       6              :  * This library is free software; you can redistribute it and/or
       7              :  * modify it under the terms of the GNU Lesser General Public
       8              :  * License as published by the Free Software Foundation; either
       9              :  * version 2.1 of the License, or (at your option) any later version.
      10              : 
      11              :  * This library is distributed in the hope that it will be useful,
      12              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14              :  * Lesser General Public License for more details.
      15              : 
      16              :  * You should have received a copy of the GNU Lesser General Public
      17              :  * License along with this library; if not, write to the Free Software
      18              :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
      19              :  *
      20              :  * Author:
      21              :  *      Jürg Billeter <j@bitron.ch>
      22              :  *      Raffaele Sandrini <raffaele@sandrini.ch>
      23              :  */
      24              : 
      25              : using GLib;
      26              : 
      27              : /**
      28              :  * Represents a type or namespace method.
      29              :  */
      30     13368761 : public class Vala.Method : Subroutine, Callable, GenericSymbol {
      31      6682072 :         List<TypeParameter> type_parameters;
      32              : 
      33              :         /**
      34              :          * The return type of this method.
      35              :          */
      36              :         public DataType return_type {
      37     60037200 :                 get { return _return_type; }
      38     10543656 :                 set {
      39     21424392 :                         _return_type = value;
      40     10543656 :                         _return_type.parent_node = this;
      41              :                 }
      42              :         }
      43              : 
      44              :         public override bool has_result {
      45        11743 :                 get { return !(return_type is VoidType); }
      46              :         }
      47              : 
      48              :         /**
      49              :          * Specifies whether this method may only be called with an instance of
      50              :          * the contained type.
      51              :          */
      52     22835275 :         public MemberBinding binding { get; set; default = MemberBinding.INSTANCE; }
      53              : 
      54              :         /**
      55              :          * Specifies whether this method is abstract. Abstract methods have no
      56              :          * body, may only be specified within abstract classes, and must be
      57              :          * overridden by derived non-abstract classes.
      58              :          */
      59      9738933 :         public bool is_abstract { get; set; }
      60              : 
      61              :         /**
      62              :          * Specifies whether this method is virtual. Virtual methods may be
      63              :          * overridden by derived classes.
      64              :          */
      65      5760327 :         public bool is_virtual { get; set; }
      66              : 
      67              :         /**
      68              :          * Specifies whether this method overrides a virtual or abstract method
      69              :          * of a base type.
      70              :          */
      71       664711 :         public bool overrides { get; set; }
      72              : 
      73              :         /**
      74              :          * Specifies whether this method should be inlined.
      75              :          */
      76        10513 :         public bool is_inline { get; set; }
      77              : 
      78              :         public bool returns_floating_reference {
      79      5868943 :                 get {
      80      5868943 :                         return get_attribute_bool ("CCode", "returns_floating_reference");
      81              :                 }
      82            0 :                 set {
      83            0 :                         set_attribute_bool ("CCode", "returns_floating_reference", value);
      84              :                 }
      85              :         }
      86              : 
      87              :         /*
      88              :          * Specifies whether the C method returns a new instance pointer which
      89              :          * may be different from the previous instance pointer. Only valid for
      90              :          * imported methods.
      91              :          */
      92              :         public bool returns_modified_pointer {
      93       196631 :                 get {
      94       196631 :                         return has_attribute ("ReturnsModifiedPointer");
      95              :                 }
      96           18 :                 set {
      97           18 :                         set_attribute ("ReturnsModifiedPointer", value);
      98              :                 }
      99              :         }
     100              : 
     101              :         /**
     102              :          * Specifies the virtual or abstract method this method overrides.
     103              :          * Reference must be weak as virtual and abstract methods set
     104              :          * base_method to themselves.
     105              :          */
     106              :         public Method base_method {
     107     13640984 :                 get {
     108     13640984 :                         find_base_methods ();
     109     13640984 :                         return _base_method;
     110              :                 }
     111              :         }
     112              : 
     113              :         /**
     114              :          * Specifies the abstract interface method this method implements.
     115              :          */
     116              :         public Method base_interface_method {
     117     13730759 :                 get {
     118     13730759 :                         find_base_methods ();
     119     13730759 :                         return _base_interface_method;
     120              :                 }
     121              :         }
     122              : 
     123              :         /**
     124              :          * Specifies the explicit interface containing the method this method implements.
     125              :          */
     126              :         public DataType base_interface_type {
     127     28649644 :                 get { return _base_interface_type; }
     128           24 :                 set {
     129           48 :                         _base_interface_type = value;
     130           24 :                         _base_interface_type.parent_node = this;
     131              :                 }
     132              :         }
     133              : 
     134       107607 :         public bool entry_point { get; private set; }
     135              : 
     136            5 :         public bool is_main_block { get; private set; }
     137              : 
     138              :         /**
     139              :          * Specifies the generated `this` parameter for instance methods.
     140              :          */
     141     33155727 :         public Parameter? this_parameter { get; set; }
     142              : 
     143              :         /**
     144              :          * Specifies whether this method expects printf-style format arguments.
     145              :          */
     146              :         public bool printf_format {
     147       236806 :                 get {
     148       236806 :                         return has_attribute ("PrintfFormat");
     149              :                 }
     150            0 :                 set {
     151            0 :                         set_attribute ("PrintfFormat", value);
     152              :                 }
     153              :         }
     154              : 
     155              :         /**
     156              :          * Specifies whether this method expects scanf-style format arguments.
     157              :          */
     158              :         public bool scanf_format {
     159        41780 :                 get {
     160        41780 :                         return has_attribute ("ScanfFormat");
     161              :                 }
     162            0 :                 set {
     163            0 :                         set_attribute ("ScanfFormat", value);
     164              :                 }
     165              :         }
     166              : 
     167              :         /**
     168              :          * Specifies whether a construct function with a GType parameter is
     169              :          * available. This is only applicable to creation methods.
     170              :          */
     171              :         public bool has_construct_function {
     172         2632 :                 get {
     173         2632 :                         return get_attribute_bool ("CCode", "has_construct_function", true);
     174              :                 }
     175          599 :                 set {
     176          599 :                         set_attribute_bool ("CCode", "has_construct_function", value);
     177              :                 }
     178              :         }
     179              : 
     180      6682165 :         public LocalVariable? params_array_var { get; protected set; }
     181              : 
     182       131782 :         public weak Signal signal_reference { get; set; }
     183              : 
     184        65819 :         public bool closure { get; set; }
     185              : 
     186      2722399 :         public bool coroutine { get; set; }
     187              : 
     188       288265 :         public bool is_async_callback { get; set; }
     189              : 
     190     13364147 :         private List<Parameter> parameters = new ArrayList<Parameter> ();
     191      6682072 :         private List<Parameter>? async_begin_parameters;
     192      6682072 :         private List<Parameter>? async_end_parameters;
     193      6682072 :         private List<Expression> preconditions;
     194      6682072 :         private List<Expression> postconditions;
     195      6682072 :         private DataType _return_type;
     196              : 
     197      6682072 :         protected List<DataType> error_types;
     198              : 
     199              :         private weak Method _base_method;
     200              :         private weak Method _base_interface_method;
     201      6682072 :         private DataType _base_interface_type;
     202              :         private bool base_methods_valid;
     203              : 
     204      6682072 :         Method? callback_method;
     205      6682072 :         Method? end_method;
     206              : 
     207              :         // only valid for closures
     208      6682072 :         List<LocalVariable> captured_variables;
     209              : 
     210              :         static List<Expression> _empty_expression_list;
     211              :         static List<TypeParameter> _empty_type_parameter_list;
     212              : 
     213              :         /**
     214              :          * Creates a new method.
     215              :          *
     216              :          * @param name              method name
     217              :          * @param return_type       method return type
     218              :          * @param source_reference  reference to source code
     219              :          * @return                  newly created method
     220              :          */
     221     19479641 :         public Method (string? name, DataType return_type, SourceReference? source_reference = null, Comment? comment = null) {
     222      6682070 :                 base (name, source_reference, comment);
     223      6682070 :                 this.return_type = return_type;
     224              :         }
     225              : 
     226              :         /**
     227              :          * Creates a new main block method.
     228              :          *
     229              :          * @param source_reference  reference to source code
     230              :          * @return                  newly created method
     231              :          */
     232            5 :         public Method.main_block (SourceReference? source_reference = null) {
     233            5 :                 base ("main", source_reference, null);
     234            5 :                 return_type = new VoidType ();
     235            5 :                 is_main_block = true;
     236              :         }
     237              : 
     238              :         /**
     239              :          * Appends parameter to this method.
     240              :          *
     241              :          * @param param a formal parameter
     242              :          */
     243      8594782 :         public void add_parameter (Parameter param) {
     244              :                 // default C parameter position
     245      8594782 :                 parameters.add (param);
     246      8594782 :                 scope.add (param.name, param);
     247              :         }
     248              : 
     249      2088720 :         public unowned List<Parameter> get_parameters () {
     250      2088720 :                 return parameters;
     251              :         }
     252              : 
     253              :         /**
     254              :          * Remove all parameters from this method.
     255              :          */
     256            1 :         public void clear_parameters () {
     257            3 :                 foreach (Parameter param in parameters) {
     258            1 :                         if (!param.ellipsis) {
     259            0 :                                 scope.remove (param.name);
     260              :                         }
     261              :                 }
     262            1 :                 parameters.clear ();
     263              :         }
     264              : 
     265      5670094 :         public bool is_variadic () {
     266     19557530 :                 foreach (Parameter param in parameters) {
     267      7052802 :                         if (param.ellipsis || param.params_array) {
     268       109084 :                                 return true;
     269              :                         }
     270              :                 }
     271      5670094 :                 return false;
     272              :         }
     273              : 
     274     13288223 :         public override void accept (CodeVisitor visitor) {
     275     13288223 :                 visitor.visit_method (this);
     276              :         }
     277              : 
     278      9495657 :         public override void accept_children (CodeVisitor visitor) {
     279      9652451 :                 foreach (TypeParameter p in get_type_parameters ()) {
     280        78397 :                         p.accept (visitor);
     281              :                 }
     282              : 
     283      9495657 :                 if (base_interface_type != null) {
     284           28 :                         base_interface_type.accept (visitor);
     285              :                 }
     286              : 
     287      9495657 :                 if (return_type != null) {
     288      9495657 :                         return_type.accept (visitor);
     289              :                 }
     290              : 
     291     33166219 :                 foreach (Parameter param in parameters) {
     292     11835281 :                         param.accept (visitor);
     293              :                 }
     294              : 
     295      9495657 :                 if (error_types != null) {
     296      3858097 :                         foreach (DataType error_type in error_types) {
     297      1298649 :                         error_type.accept (visitor);
     298              :                 }
     299              :                 }
     300              : 
     301      9495657 :                 if (result_var != null) {
     302           42 :                         result_var.accept (visitor);
     303              :                 }
     304              : 
     305      9495657 :                 if (preconditions != null) {
     306          102 :                         foreach (Expression precondition in preconditions) {
     307           34 :                                 precondition.accept (visitor);
     308              :                         }
     309              :                 }
     310              : 
     311      9495657 :                 if (postconditions != null) {
     312          183 :                         foreach (Expression postcondition in postconditions) {
     313           61 :                                 postcondition.accept (visitor);
     314              :                         }
     315              :                 }
     316              : 
     317      9495657 :                 if (body != null) {
     318       298674 :                         body.accept (visitor);
     319              :                 }
     320              :         }
     321              : 
     322              :         /**
     323              :          * Checks whether the parameters and return type of this method are
     324              :          * compatible with the specified method
     325              :          *
     326              :          * @param base_method a method
     327              :          * @param invalid_match error string about which check failed
     328              :          * @return true if the specified method is compatible to this method
     329              :          */
     330       344629 :         public bool compatible (Method base_method, out string? invalid_match) {
     331       344629 :                 return compatible_internal (base_method, out invalid_match, this);
     332              :         }
     333              : 
     334              :         /**
     335              :          * Checks whether the parameters and return type of this method are
     336              :          * compatible with the specified method
     337              :          *
     338              :          * @param base_method a method
     339              :          * @return true if the specified method is compatible to this method
     340              :          */
     341            3 :         public bool compatible_no_error (Method base_method) {
     342            3 :                 return compatible_internal (base_method, null, null);
     343              :         }
     344              : 
     345       344632 :         bool compatible_internal (Method base_method, out string? invalid_match, CodeNode? node_reference) {
     346              :                 // method is always compatible to itself
     347       344632 :                 if (this == base_method) {
     348       314459 :                         invalid_match = null;
     349       314459 :                         return true;
     350              :                 }
     351              : 
     352        30173 :                 if (binding != base_method.binding) {
     353            0 :                         invalid_match = "incompatible binding";
     354            0 :                         return false;
     355              :                 }
     356              : 
     357        30173 :                 ObjectType object_type = null;
     358        30173 :                 if (parent_symbol is ObjectTypeSymbol) {
     359        30173 :                         object_type = new ObjectType ((ObjectTypeSymbol) parent_symbol);
     360        30907 :                         foreach (TypeParameter type_parameter in object_type.object_type_symbol.get_type_parameters ()) {
     361          367 :                                 var type_arg = new GenericType (type_parameter);
     362          367 :                                 type_arg.value_owned = true;
     363          367 :                                 object_type.add_type_argument (type_arg);
     364              :                         }
     365              :                 }
     366              : 
     367        30173 :                 if (this.get_type_parameters ().size < base_method.get_type_parameters ().size) {
     368            0 :                         invalid_match = "too few type parameters";
     369            0 :                         return false;
     370        30173 :                 } else if (this.get_type_parameters ().size > base_method.get_type_parameters ().size) {
     371            0 :                         invalid_match = "too many type parameters";
     372            0 :                         return false;
     373              :                 }
     374              : 
     375        30173 :                 List<DataType> method_type_args = null;
     376        30173 :                 if (this.has_type_parameters ()) {
     377            3 :                         method_type_args = new ArrayList<DataType> ();
     378           11 :                         foreach (TypeParameter type_parameter in this.get_type_parameters ()) {
     379            4 :                                 var type_arg = new GenericType (type_parameter);
     380            4 :                                 type_arg.value_owned = true;
     381            4 :                                 method_type_args.add (type_arg);
     382              :                         }
     383              :                 }
     384              : 
     385        30173 :                 var return_type = this.return_type.copy ();
     386        30173 :                 if (has_attribute_argument ("CCode", "returns_floating_reference")) {
     387            2 :                         return_type.floating_reference = returns_floating_reference;
     388              :                 } else {
     389        30171 :                         return_type.floating_reference = base_method.returns_floating_reference;
     390              :                 }
     391              : 
     392        30173 :                 var actual_base_type = base_method.return_type.get_actual_type (object_type, method_type_args, node_reference);
     393        30173 :                 if (!return_type.equals (actual_base_type)) {
     394            7 :                         invalid_match = "Base method expected return type `%s', but `%s' was provided".printf (actual_base_type.to_prototype_string (), return_type.to_prototype_string ());
     395            7 :                         return false;
     396              :                 }
     397              : 
     398        30166 :                 Iterator<Parameter> method_params_it = parameters.iterator ();
     399        30166 :                 int param_index = 1;
     400        82902 :                 foreach (Parameter base_param in base_method.parameters) {
     401              :                         /* this method may not expect less arguments */
     402        26370 :                         if (!method_params_it.next ()) {
     403            0 :                                 invalid_match = "too few parameters";
     404            0 :                                 return false;
     405              :                         }
     406              : 
     407        26370 :                         var param = method_params_it.get ();
     408        26370 :                         if (base_param.ellipsis != param.ellipsis) {
     409            0 :                                 invalid_match = "ellipsis parameter mismatch";
     410            0 :                                 return false;
     411              :                         }
     412        26370 :                         if (base_param.params_array != param.params_array) {
     413            0 :                                 invalid_match = "params array parameter mismatch";
     414            0 :                                 return false;
     415              :                         }
     416        26370 :                         if (!base_param.ellipsis) {
     417        26370 :                                 if (base_param.direction != param.direction) {
     418            0 :                                         invalid_match = "incompatible direction of parameter %d".printf (param_index);
     419            0 :                                         return false;
     420              :                                 }
     421              : 
     422        26370 :                                 actual_base_type = base_param.variable_type.get_actual_type (object_type, method_type_args, node_reference);
     423        26370 :                                 if (!actual_base_type.equals (param.variable_type)) {
     424            2 :                                         invalid_match = "incompatible type of parameter %d".printf (param_index);
     425            2 :                                         return false;
     426              :                                 }
     427              :                         }
     428        26368 :                         param_index++;
     429              :                 }
     430              : 
     431              :                 /* this method may not expect more arguments */
     432        30164 :                 if (method_params_it.next ()) {
     433            0 :                         invalid_match = "too many parameters";
     434            0 :                         return false;
     435              :                 }
     436              : 
     437              :                 /* this method may throw less but not more errors than the base method */
     438        30164 :                 var base_method_errors = new ArrayList<DataType> ();
     439        30164 :                 base_method.get_error_types (base_method_errors);
     440        30164 :                 if (error_types != null) {
     441        12615 :                         foreach (DataType method_error_type in error_types) {
     442         4205 :                         bool match = false;
     443         4205 :                                 foreach (DataType base_method_error_type in base_method_errors) {
     444         4205 :                                 if (method_error_type.compatible (base_method_error_type)) {
     445         4205 :                                         match = true;
     446         4205 :                                         break;
     447              :                                 }
     448              :                         }
     449              : 
     450         4205 :                         if (!match) {
     451            0 :                                 invalid_match = "incompatible error type `%s'".printf (method_error_type.to_string ());
     452            0 :                                 return false;
     453              :                         }
     454              :                 }
     455              :                 }
     456        30164 :                 if (base_method.coroutine != this.coroutine) {
     457            0 :                         invalid_match = "async mismatch";
     458            0 :                         return false;
     459              :                 }
     460              : 
     461        30164 :                 invalid_match = null;
     462        30164 :                 return true;
     463              :         }
     464              : 
     465              :         /**
     466              :          * Appends the specified parameter to the list of type parameters.
     467              :          *
     468              :          * @param p a type parameter
     469              :          */
     470        50648 :         public void add_type_parameter (TypeParameter p) {
     471        50648 :                 if (type_parameters == null) {
     472        47582 :                         type_parameters = new ArrayList<TypeParameter> ();
     473              :                 }
     474        50648 :                 type_parameters.add (p);
     475        50648 :                 scope.add (p.name, p);
     476              :         }
     477              : 
     478              :         /**
     479              :          * Returns the type parameter list.
     480              :          *
     481              :          * @return list of type parameters
     482              :          */
     483     15485013 :         public unowned List<TypeParameter> get_type_parameters () {
     484     15485013 :                 if (type_parameters != null) {
     485     15485013 :                         return type_parameters;
     486              :                 }
     487     15363882 :                 if (_empty_type_parameter_list == null) {
     488         1430 :                         _empty_type_parameter_list = new ArrayList<TypeParameter> ();
     489              :                 }
     490     15363882 :                 return _empty_type_parameter_list;
     491              :         }
     492              : 
     493         3129 :         public int get_type_parameter_index (string name) {
     494         3129 :                 if (type_parameters == null) {
     495            0 :                         return -1;
     496              :                 }
     497              : 
     498         3129 :                 int i = 0;
     499         3155 :                 foreach (TypeParameter parameter in type_parameters) {
     500         3142 :                         if (parameter.name == name) {
     501         3129 :                                 return i;
     502              :                         }
     503           13 :                         i++;
     504              :                 }
     505         3129 :                 return -1;
     506              :         }
     507              : 
     508       245825 :         public bool has_type_parameters () {
     509       245825 :                 return (type_parameters != null && type_parameters.size > 0);
     510              :         }
     511              : 
     512              :         /**
     513              :          * Adds a precondition to this method.
     514              :          *
     515              :          * @param precondition a boolean precondition expression
     516              :          */
     517           14 :         public void add_precondition (Expression precondition) {
     518           14 :                 if (preconditions == null) {
     519           14 :                         preconditions = new ArrayList<Expression> ();
     520              :                 }
     521           14 :                 preconditions.add (precondition);
     522           14 :                 precondition.parent_node = this;
     523              :         }
     524              : 
     525              :         /**
     526              :          * Returns the list of preconditions of this method.
     527              :          *
     528              :          * @return list of preconditions
     529              :          */
     530      7130946 :         public unowned List<Expression> get_preconditions () {
     531      7130946 :                 if (preconditions != null) {
     532      7130946 :                         return preconditions;
     533              :                 }
     534      7130907 :                 if (_empty_expression_list == null) {
     535            0 :                         _empty_expression_list = new ArrayList<Expression> ();
     536              :                 }
     537      7130907 :                 return _empty_expression_list;
     538              :         }
     539              : 
     540              :         /**
     541              :          * Adds a postcondition to this method.
     542              :          *
     543              :          * @param postcondition a boolean postcondition expression
     544              :          */
     545           23 :         public void add_postcondition (Expression postcondition) {
     546           23 :                 if (postconditions == null) {
     547           23 :                         postconditions = new ArrayList<Expression> ();
     548              :                 }
     549           23 :                 postconditions.add (postcondition);
     550           23 :                 postcondition.parent_node = this;
     551              :         }
     552              : 
     553              :         /**
     554              :          * Returns the list of postconditions of this method.
     555              :          *
     556              :          * @return list of postconditions
     557              :          */
     558     11462189 :         public unowned List<Expression> get_postconditions () {
     559     11462189 :                 if (postconditions != null) {
     560     11462189 :                         return postconditions;
     561              :                 }
     562     11462120 :                 if (_empty_expression_list == null) {
     563         1537 :                         _empty_expression_list = new ArrayList<Expression> ();
     564              :                 }
     565     11462120 :                 return _empty_expression_list;
     566              :         }
     567              : 
     568              :         /**
     569              :          * Adds an error type to the exceptions that can be
     570              :          * thrown by this method.
     571              :          */
     572       900436 :         public void add_error_type (DataType error_type) {
     573       900436 :                 if (error_types == null) {
     574       876018 :                         error_types = new ArrayList<DataType> ();
     575              :                 }
     576       900436 :                 error_types.add (error_type);
     577       900436 :                 error_type.parent_node = this;
     578              :         }
     579              : 
     580       877503 :         public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
     581       877503 :                 if (error_types != null) {
     582        73718 :                         foreach (var error_type in error_types) {
     583        41003 :                                 if (source_reference != null) {
     584        16307 :                                         var type = error_type.copy ();
     585        16307 :                                         type.source_reference = source_reference;
     586        16307 :                                         collection.add (type);
     587              :                                 } else {
     588         8389 :                                         collection.add (error_type);
     589              :                                 }
     590              :                         }
     591              :                 }
     592              :         }
     593              : 
     594            0 :         public override void replace_expression (Expression old_node, Expression new_node) {
     595            0 :                 if (preconditions != null) {
     596            0 :                         var index = preconditions.index_of (old_node);
     597            0 :                         if (index >= 0) {
     598            0 :                                 preconditions[index] = new_node;
     599            0 :                                 new_node.parent_node = this;
     600              :                         }
     601              :                 }
     602            0 :                 if (postconditions != null) {
     603            0 :                         var index = postconditions.index_of (old_node);
     604            0 :                         if (index >= 0) {
     605            0 :                                 postconditions[index] = new_node;
     606            0 :                                 new_node.parent_node = this;
     607              :                         }
     608              :                 }
     609              :         }
     610              : 
     611      4697552 :         public override void replace_type (DataType old_type, DataType new_type) {
     612      4697552 :                 if (base_interface_type == old_type) {
     613           12 :                         base_interface_type = new_type;
     614           12 :                         return;
     615              :                 }
     616      4697540 :                 if (return_type == old_type) {
     617      3861306 :                         return_type = new_type;
     618      3861306 :                         return;
     619              :                 }
     620       836234 :                 if (error_types != null) {
     621       858922 :                 for (int i = 0; i < error_types.size; i++) {
     622       858922 :                         if (error_types[i] == old_type) {
     623       836234 :                                 error_types[i] = new_type;
     624       836234 :                                 return;
     625              :                         }
     626              :                 }
     627              :         }
     628              :         }
     629              : 
     630     27371743 :         private void find_base_methods () {
     631     27371743 :                 if (base_methods_valid) {
     632              :                         return;
     633              :                 }
     634              : 
     635      6000406 :                 if (parent_symbol is Class) {
     636      3896240 :                         if (!(this is CreationMethod)) {
     637      3398115 :                                 find_base_interface_method ((Class) parent_symbol);
     638      3398115 :                                 if (is_virtual || is_abstract || overrides) {
     639       327828 :                                         find_base_class_method ((Class) parent_symbol);
     640              :                                 }
     641              :                         }
     642      2104166 :                 } else if (parent_symbol is Interface) {
     643       554004 :                         if (is_virtual || is_abstract) {
     644       380411 :                                 _base_interface_method = this;
     645              :                         }
     646              :                 }
     647              : 
     648      6000406 :                 base_methods_valid = true;
     649              :         }
     650              : 
     651       382493 :         private void find_base_class_method (Class cl) {
     652       355119 :                 var sym = cl.scope.lookup (name);
     653       355119 :                 if (sym is Signal) {
     654        79187 :                         unowned Signal sig = (Signal) sym;
     655       158374 :                         sym = sig.default_handler;
     656              :                 }
     657       355119 :                 if (sym is Method) {
     658       342511 :                         unowned Method base_method = (Method) sym;
     659       342511 :                         if (base_method.is_abstract || base_method.is_virtual) {
     660              :                                 string invalid_match;
     661       327745 :                                 if (!compatible (base_method, out invalid_match)) {
     662            3 :                                         error = true;
     663            3 :                                         var base_method_type = new MethodType (base_method);
     664            3 :                                         Report.error (source_reference, "overriding method `%s' is incompatible with base method `%s': %s.", get_full_name (), base_method_type.to_prototype_string (), invalid_match);
     665            3 :                                         return;
     666              :                                 }
     667              : 
     668       327742 :                                 _base_method = base_method;
     669       327742 :                                 copy_attribute_double (base_method, "CCode", "instance_pos");
     670       327742 :                                 copy_attribute_bool (base_method, "CCode", "returns_floating_reference");
     671       327742 :                                 return;
     672              :                         }
     673              :                 }
     674              : 
     675        27374 :                 if (cl.base_class != null) {
     676        27291 :                         find_base_class_method (cl.base_class);
     677              :                 }
     678              :         }
     679              : 
     680      6779348 :         private void find_base_interface_method (Class cl) {
     681      3398115 :                 Method? base_match = null;
     682              : 
     683      3398115 :                 string? invalid_error = null;
     684      3398115 :                 Method? invalid_base_match = null;
     685              : 
     686      8866187 :                 foreach (DataType type in cl.get_base_types ()) {
     687      3821874 :                         if (type.type_symbol is Interface) {
     688      1087841 :                                 if (base_interface_type != null && base_interface_type.type_symbol != type.type_symbol) {
     689            4 :                                         continue;
     690              :                                 }
     691              : 
     692      1087837 :                                 var sym = type.type_symbol.scope.lookup (name);
     693      1087837 :                                 if (sym is Signal) {
     694            1 :                                         unowned Signal sig = (Signal) sym;
     695            2 :                                         sym = sig.default_handler;
     696              :                                 }
     697      1087837 :                                 if (sym is Method) {
     698        31241 :                                         unowned Method base_method = (Method) sym;
     699        31246 :                                         if (base_method.is_abstract || base_method.is_virtual) {
     700        16886 :                                                 if (base_interface_type == null) {
     701              :                                                         // check for existing explicit implementation
     702        16875 :                                                         var has_explicit_implementation = false;
     703       311119 :                                                         foreach (var m in cl.get_methods ()) {
     704       147124 :                                                                 if (m.base_interface_type != null && base_method == m.base_interface_method) {
     705            2 :                                                                         has_explicit_implementation = true;
     706            2 :                                                                         break;
     707              :                                                                 }
     708              :                                                         }
     709            2 :                                                         if (has_explicit_implementation) {
     710            2 :                                                                 continue;
     711              :                                                         }
     712              :                                                 }
     713              : 
     714        16884 :                                                 string invalid_match = null;
     715        16884 :                                                 if (!compatible (base_method, out invalid_match)) {
     716           10 :                                                         invalid_error = invalid_match;
     717            5 :                                                         invalid_base_match = base_method;
     718              :                                                 } else {
     719        16879 :                                                         base_match = base_method;
     720        16879 :                                                         break;
     721              :                                                 }
     722              :                                         }
     723              :                                 }
     724              :                         }
     725              :                 }
     726              : 
     727      3398115 :                 if (base_match != null) {
     728        16879 :                         _base_interface_method = base_match;
     729        16879 :                         copy_attribute_double (base_match, "CCode", "instance_pos");
     730        16879 :                         copy_attribute_bool (base_match, "CCode", "returns_floating_reference");
     731        16879 :                         return;
     732      3381236 :                 } else if (!hides && invalid_base_match != null) {
     733            3 :                         error = true;
     734            3 :                         var base_method_type = new MethodType (invalid_base_match);
     735            3 :                         Report.error (source_reference, "overriding method `%s' is incompatible with base method `%s': %s.", get_full_name (), base_method_type.to_prototype_string (), invalid_error);
     736            3 :                         return;
     737              :                 }
     738              : 
     739      3381233 :                 if (base_interface_type != null) {
     740            1 :                         Report.error (source_reference, "`%s': no suitable interface method found to implement", get_full_name ());
     741              :                 }
     742              :         }
     743              : 
     744     23005658 :         public override bool check (CodeContext context) {
     745      5840406 :                 if (checked) {
     746       177972 :                         return !error;
     747              :                 }
     748              : 
     749      5662434 :                 checked = true;
     750              : 
     751      5662434 :                 if (this_parameter != null) {
     752      4216594 :                         this_parameter.check (context);
     753              :                 }
     754              : 
     755      5662434 :                 if (has_attribute ("DestroysInstance")) {
     756        26981 :                         this_parameter.variable_type.value_owned = true;
     757              :                 }
     758      5662434 :                 if (has_attribute ("NoThrow")) {
     759            0 :                         error_types = null;
     760              :                 }
     761              : 
     762      5662434 :                 if (parent_symbol is Class && (is_abstract || is_virtual)) {
     763       314459 :                         unowned Class cl = (Class) parent_symbol;
     764       314459 :                         if (cl.is_compact && cl.base_class != null) {
     765            1 :                                 error = true;
     766            1 :                                 Report.error (source_reference, "Abstract and virtual methods may not be declared in derived compact classes");
     767            1 :                                 return false;
     768              :                         }
     769       314458 :                         if (cl.is_opaque) {
     770            1 :                                 error = true;
     771            1 :                                 Report.error (source_reference, "Abstract and virtual methods may not be declared in opaque compact classes");
     772            1 :                                 return false;
     773              :                         }
     774              :                 }
     775              : 
     776      5662432 :                 if (is_variadic () && (is_abstract || is_virtual)) {
     777            2 :                         error = true;
     778            2 :                         Report.error (source_reference, "Abstract and virtual methods may not be variadic. Use a `va_list' parameter instead of `...' or params-array.");
     779            2 :                         return false;
     780              :                 }
     781              : 
     782      5662430 :                 if (has_attribute ("NoWrapper") && !(is_abstract || is_virtual)) {
     783            1 :                         error = true;
     784            1 :                         Report.error (source_reference, "[NoWrapper] methods must be declared abstract or virtual");
     785            1 :                         return false;
     786              :                 }
     787              : 
     788      5662429 :                 if (is_abstract) {
     789       300601 :                         if (parent_symbol is Class) {
     790         9037 :                                 unowned Class cl = (Class) parent_symbol;
     791         9037 :                                 if (!cl.is_abstract) {
     792            1 :                                         error = true;
     793            1 :                                         Report.error (source_reference, "Abstract methods may not be declared in non-abstract classes");
     794            1 :                                         return false;
     795              :                                 }
     796       291564 :                         } else if (!(parent_symbol is Interface)) {
     797            1 :                                 error = true;
     798            1 :                                 Report.error (source_reference, "Abstract methods may not be declared outside of classes and interfaces");
     799            1 :                                 return false;
     800              :                         }
     801      5361828 :                 } else if (is_virtual) {
     802       394255 :                         if (!(parent_symbol is Class) && !(parent_symbol is Interface)) {
     803            1 :                                 error = true;
     804            1 :                                 Report.error (source_reference, "Virtual methods may not be declared outside of classes and interfaces");
     805            1 :                                 return false;
     806              :                         }
     807      4967573 :                 } else if (overrides) {
     808        13291 :                         if (!(parent_symbol is Class)) {
     809            1 :                                 error = true;
     810            1 :                                 Report.error (source_reference, "Methods may not be overridden outside of classes");
     811            1 :                                 return false;
     812              :                         }
     813      4954282 :                 } else if (access == SymbolAccessibility.PROTECTED) {
     814          245 :                         if (!(parent_symbol is Class) && !(parent_symbol is Interface)) {
     815            1 :                                 error = true;
     816            1 :                                 Report.error (source_reference, "Protected methods may not be declared outside of classes and interfaces");
     817            1 :                                 return false;
     818              :                         }
     819              :                 }
     820              : 
     821      5662424 :                 if (is_abstract && body != null) {
     822            1 :                         error = true;
     823            1 :                         Report.error (source_reference, "Abstract methods cannot have bodies");
     824      5662423 :                 } else if ((is_abstract || is_virtual) && is_extern) {
     825            2 :                         error = true;
     826            2 :                         Report.error (source_reference, "Extern methods cannot be abstract or virtual");
     827      5662421 :                 } else if (is_extern && body != null) {
     828            1 :                         error = true;
     829            1 :                         Report.error (source_reference, "Extern methods cannot have bodies");
     830      5662420 :                 } else if (!is_abstract && !external && source_type == SourceFileType.SOURCE && body == null) {
     831            2 :                         error = true;
     832            2 :                         Report.error (source_reference, "Non-abstract, non-extern methods must have bodies");
     833              :                 }
     834              : 
     835              :                 // auto-convert main block to async if a yield expression is used
     836      5662424 :                 if (is_main_block && body != null) {
     837           41 :                         body.accept (new TraverseVisitor (node => {
     838           36 :                                 if (!(node is Statement || node is Expression || node is Variable || node is CatchClause)) {
     839            6 :                                         return TraverseStatus.STOP;
     840              :                                 }
     841           33 :                                 if (node is YieldStatement
     842           32 :                                     || (node is MethodCall && ((MethodCall) node).is_yield_expression)
     843           31 :                                     || (node is ObjectCreationExpression && ((ObjectCreationExpression) node).is_yield_expression)) {
     844            3 :                                         coroutine = true;
     845            3 :                                         return TraverseStatus.STOP;
     846              :                                 }
     847           36 :                                 return TraverseStatus.CONTINUE;
     848              :                         }));
     849              :                 }
     850              : 
     851      5662424 :                 if (coroutine && !external_package && !context.has_package ("gio-2.0")) {
     852            0 :                         error = true;
     853            0 :                         Report.error (source_reference, "gio-2.0 package required for async methods");
     854            0 :                         return false;
     855              :                 }
     856              : 
     857      5662424 :                 var old_source_file = context.analyzer.current_source_file;
     858      5662424 :                 var old_symbol = context.analyzer.current_symbol;
     859              : 
     860      5662424 :                 if (source_reference != null) {
     861      5662310 :                         context.analyzer.current_source_file = source_reference.file;
     862              :                 }
     863      5662424 :                 context.analyzer.current_symbol = this;
     864              : 
     865      5662424 :                 return_type.floating_reference = returns_floating_reference;
     866      5662424 :                 return_type.check (context);
     867      5662424 :                 if (!external_package) {
     868         5801 :                         context.analyzer.check_type (return_type);
     869         5801 :                         return_type.check_type_arguments (context, !(return_type is DelegateType));
     870              :                 }
     871              : 
     872      5662424 :                 if (return_type.type_symbol == context.analyzer.va_list_type.type_symbol) {
     873            1 :                         error = true;
     874            1 :                         Report.error (source_reference, "`%s' not supported as return type", return_type.type_symbol.get_full_name ());
     875            1 :                         return false;
     876              :                 }
     877              : 
     878      5662423 :                 if (has_attribute ("ModuleInit")) {
     879            1 :                         source_reference.file.context.module_init_method = this;
     880              :                 }
     881              : 
     882      5662423 :                 if (parameters.size == 1 && parameters[0].ellipsis && body != null && binding != MemberBinding.INSTANCE) {
     883              :                         // accept just `...' for external methods and instance methods
     884            1 :                         error = true;
     885            1 :                         Report.error (parameters[0].source_reference, "Named parameter required before `...'");
     886              :                 }
     887              : 
     888      5662423 :                 if (has_attribute ("Print") && (parameters.size != 1 || parameters[0].variable_type.type_symbol != context.analyzer.string_type.type_symbol)) {
     889            1 :                         error = true;
     890            1 :                         Report.error (source_reference, "[Print] methods must have exactly one parameter of type `string'");
     891              :                 }
     892              : 
     893              :                 // Collect generic type references
     894              :                 // TODO Can this be done in the SymbolResolver?
     895      5662423 :                 List<GenericType> referenced_generics = new ArrayList<GenericType> ();
     896     20223033 :                 var traverse = new TraverseVisitor (node => {
     897     14560610 :                         if (node is GenericType) {
     898       650408 :                                 referenced_generics.add ((GenericType) node);
     899       650408 :                                 return TraverseStatus.STOP;
     900              :                         }
     901     14560610 :                         return TraverseStatus.CONTINUE;
     902              :                 });
     903              : 
     904      5756417 :                 foreach (TypeParameter p in get_type_parameters ()) {
     905        46997 :                         if (!p.check (context)) {
     906            0 :                                 error = true;
     907              :                         }
     908              :                 }
     909              : 
     910      5662423 :                 return_type.accept (traverse);
     911              : 
     912      5662423 :                 var optional_param = false;
     913      5662423 :                 var params_array_param = false;
     914      5662423 :                 var ellipsis_param = false;
     915     19142310 :                 foreach (Parameter param in parameters) {
     916      7048115 :                         if (!param.check (context)) {
     917           10 :                                 error = true;
     918           10 :                                 continue;
     919              :                         }
     920      7048105 :                         if (coroutine && param.direction == ParameterDirection.REF) {
     921            1 :                                 error = true;
     922            1 :                                 Report.error (param.source_reference, "Reference parameters are not supported for async methods");
     923              :                         }
     924      7048105 :                         if (!external_package && coroutine && (param.ellipsis || param.params_array || param.variable_type.type_symbol == context.analyzer.va_list_type.type_symbol)) {
     925            3 :                                 error = true;
     926            3 :                                 Report.error (param.source_reference, "Variadic parameters are not supported for async methods");
     927            3 :                                 return false;
     928              :                         }
     929              : 
     930      7048102 :                         param.accept_children (traverse);
     931              : 
     932              :                         // TODO: begin and end parameters must be checked separately for coroutines
     933      7048102 :                         if (coroutine) {
     934       616326 :                                 continue;
     935              :                         }
     936      6431776 :                         if (optional_param && param.initializer == null && !param.ellipsis) {
     937            0 :                                 Report.warning (param.source_reference, "parameter without default follows parameter with default");
     938      6431776 :                         } else if (param.initializer != null) {
     939       643594 :                                 optional_param = true;
     940              :                         }
     941              : 
     942              :                         // Disallow parameter after params array or ellipsis
     943      6431776 :                         if (params_array_param) {
     944            2 :                                 Report.error (param.source_reference, "parameter follows params-array parameter");
     945      6431774 :                         } else if (param.params_array) {
     946         2890 :                                 params_array_param = true;
     947              :                         }
     948      6431776 :                         if (ellipsis_param) {
     949            1 :                                 Report.error (param.source_reference, "parameter follows ellipsis parameter");
     950      6431775 :                         } else if (param.ellipsis) {
     951       104312 :                                 ellipsis_param = true;
     952              :                         }
     953              : 
     954              :                         // Add local variable to provide access to params arrays which will be constructed out of the given va-args
     955      6431795 :                         if (param.params_array && body != null) {
     956           20 :                                 if (params_array_var != null) {
     957            1 :                                         error = true;
     958            1 :                                         Report.error (param.source_reference, "Only one params-array parameter is allowed");
     959            1 :                                         continue;
     960              :                                 }
     961           19 :                                 if (!context.experimental) {
     962           19 :                                         Report.warning (param.source_reference, "Support of params-arrays is experimental");
     963              :                                 }
     964           19 :                                 var type = (ArrayType) param.variable_type.copy ();
     965           19 :                                 type.element_type.value_owned = type.value_owned;
     966           19 :                                 type.value_owned = true;
     967           19 :                                 if (type.element_type.is_real_struct_type () && !type.element_type.nullable) {
     968            1 :                                         error = true;
     969            1 :                                         Report.error (param.source_reference, "Only nullable struct elements are supported in params-array");
     970              :                                 }
     971           19 :                                 if (type.length != null) {
     972            1 :                                         error = true;
     973            1 :                                         Report.error (param.source_reference, "Passing length to params-array is not supported yet");
     974              :                                 }
     975           19 :                                 params_array_var = new LocalVariable (type, param.name, null, param.source_reference);
     976           19 :                                 body.insert_statement (0, new DeclarationStatement (params_array_var, param.source_reference));
     977              :                         }
     978              :                 }
     979              : 
     980              :                 // Check if referenced type-parameters are present
     981              :                 // TODO Can this be done in the SymbolResolver?
     982      5746072 :                 if (binding == MemberBinding.STATIC && parent_symbol is Class && !((Class) parent_symbol).is_compact) {
     983        83652 :                         Iterator<GenericType> ref_generics_it = referenced_generics.iterator ();
     984        83660 :                         while (ref_generics_it.next ()) {
     985            4 :                                 var ref_generics = ref_generics_it.get ();
     986            4 :                                 foreach (var type_param in get_type_parameters ()) {
     987            0 :                                         if (ref_generics.type_parameter.name == type_param.name) {
     988            0 :                                                 ref_generics_it.remove ();
     989              :                                         }
     990              :                                 }
     991              :                         }
     992        83660 :                         foreach (var type in referenced_generics) {
     993            4 :                                 error = true;
     994            4 :                                 Report.error (type.source_reference, "The type name `%s' could not be found", type.type_parameter.name);
     995              :                         }
     996              :                 }
     997              : 
     998      5662420 :                 if (coroutine) {
     999              :                         // TODO: async methods with out-parameters before in-parameters are not supported
    1000       189758 :                         bool requires_pointer = false;
    1001      1422406 :                         for (int i = parameters.size - 1; i >= 0; i--) {
    1002       616324 :                                 var param = parameters[i];
    1003       616324 :                                 if (param.direction == ParameterDirection.IN) {
    1004              :                                         requires_pointer = true;
    1005        41899 :                                 } else if (requires_pointer) {
    1006            1 :                                         error = true;
    1007            1 :                                         Report.error (param.source_reference, "Synchronous out-parameters are not supported in async methods");
    1008              :                                 }
    1009              :                         }
    1010              :                 }
    1011              : 
    1012      5662420 :                 if (error_types != null) {
    1013      2306143 :                         foreach (DataType error_type in error_types) {
    1014       776246 :                                 if (!(error_type is ErrorType)) {
    1015            1 :                                         error = true;
    1016            1 :                                         Report.error (error_type.source_reference, "`%s' is not an error type", error_type.to_string ());
    1017              :                                 }
    1018       776246 :                                 error_type.check (context);
    1019              : 
    1020              :                                 // check whether error type is at least as accessible as the method
    1021       776246 :                                 if (!error_type.is_accessible (this)) {
    1022            1 :                                         error = true;
    1023            1 :                                         Report.error (source_reference, "error type `%s' is less accessible than method `%s'", error_type.to_string (), get_full_name ());
    1024            1 :                                         return false;
    1025              :                                 }
    1026              :                         }
    1027              :                 }
    1028              : 
    1029      5662419 :                 if (result_var != null) {
    1030           14 :                         result_var.check (context);
    1031              :                 }
    1032              : 
    1033      5662419 :                 if (preconditions != null) {
    1034           36 :                         foreach (Expression precondition in preconditions) {
    1035           12 :                                 precondition.check (context);
    1036              :                         }
    1037              :                 }
    1038              : 
    1039      5662419 :                 if (postconditions != null) {
    1040           63 :                         foreach (Expression postcondition in postconditions) {
    1041           21 :                                 postcondition.check (context);
    1042              :                         }
    1043              :                 }
    1044              : 
    1045      5662419 :                 if (body != null) {
    1046       124544 :                         body.check (context);
    1047              :                 }
    1048              : 
    1049      5662419 :                 if (overrides && base_method == null && base_interface_method != null && base_interface_method.is_abstract) {
    1050            1 :                         Report.warning (source_reference, "`override' not required to implement `abstract' interface method `%s'", base_interface_method.get_full_name ());
    1051            1 :                         overrides = false;
    1052      5662418 :                 } else if (!error && overrides && base_method == null && base_interface_method == null) {
    1053            0 :                         error = true;
    1054            0 :                         Report.error (source_reference, "`%s': no suitable method found to override", get_full_name ());
    1055      5662418 :                 } else if ((is_abstract || is_virtual || overrides) && access == SymbolAccessibility.PRIVATE) {
    1056            3 :                         error = true;
    1057            3 :                         Report.error (source_reference, "Private member `%s' cannot be marked as override, virtual, or abstract", get_full_name ());
    1058            3 :                         return false;
    1059              :                 }
    1060              : 
    1061      5662416 :                 if (base_interface_type != null && base_interface_method != null && parent_symbol is Class) {
    1062           10 :                         unowned Class cl = (Class) parent_symbol;
    1063           64 :                         foreach (var m in cl.get_methods ()) {
    1064           28 :                                 if (m != this && m.base_interface_method == base_interface_method) {
    1065            1 :                                         m.checked = true;
    1066            1 :                                         m.error = true;
    1067            1 :                                         error = true;
    1068            1 :                                         Report.error (source_reference, "`%s' already contains an implementation for `%s'", cl.get_full_name (), base_interface_method.get_full_name ());
    1069            1 :                                         Report.notice (m.source_reference, "previous implementation of `%s' was here", base_interface_method.get_full_name ());
    1070            1 :                                         return false;
    1071              :                                 }
    1072              :                         }
    1073              :                 }
    1074              : 
    1075      5662415 :                 context.analyzer.current_source_file = old_source_file;
    1076      5662415 :                 context.analyzer.current_symbol = old_symbol;
    1077              : 
    1078      5662415 :                 if (!external_package && !overrides && !hides && get_hidden_member () != null) {
    1079            7 :                         Report.warning (source_reference, "%s hides inherited method `%s'. Use the `new' keyword if hiding was intentional", get_full_name (), get_hidden_member ().get_full_name ());
    1080              :                 }
    1081              : 
    1082              :                 // check whether return type is at least as accessible as the method
    1083      5662415 :                 if (!return_type.is_accessible (this)) {
    1084            1 :                         error = true;
    1085            1 :                         Report.error (source_reference, "return type `%s' is less accessible than method `%s'", return_type.to_string (), get_full_name ());
    1086            1 :                         return false;
    1087              :                 }
    1088              : 
    1089      5662436 :                 foreach (Expression precondition in get_preconditions ()) {
    1090           12 :                         if (precondition.error) {
    1091              :                                 // if there was an error in the precondition, skip this check
    1092            0 :                                 error = true;
    1093            0 :                                 return false;
    1094              :                         }
    1095              : 
    1096           12 :                         if (!precondition.value_type.compatible (context.analyzer.bool_type)) {
    1097            1 :                                 error = true;
    1098            1 :                                 Report.error (precondition.source_reference, "Precondition must be boolean");
    1099            1 :                                 return false;
    1100              :                         }
    1101              :                 }
    1102              : 
    1103      5662453 :                 foreach (Expression postcondition in get_postconditions ()) {
    1104           21 :                         if (postcondition.error) {
    1105              :                                 // if there was an error in the postcondition, skip this check
    1106            0 :                                 error = true;
    1107            0 :                                 return false;
    1108              :                         }
    1109              : 
    1110           21 :                         if (!postcondition.value_type.compatible (context.analyzer.bool_type)) {
    1111            1 :                                 error = true;
    1112            1 :                                 Report.error (postcondition.source_reference, "Postcondition must be boolean");
    1113            1 :                                 return false;
    1114              :                         }
    1115              :                 }
    1116              : 
    1117              :                 // check that all errors that can be thrown in the method body are declared
    1118      5786714 :                 if (body != null && !body.error) {
    1119       124302 :                         var body_errors = new ArrayList<DataType> ();
    1120       124302 :                         body.get_error_types (body_errors);
    1121       125126 :                         foreach (DataType body_error_type in body_errors) {
    1122          412 :                                 bool can_propagate_error = false;
    1123          412 :                                 if (error_types != null) {
    1124          650 :                                         foreach (DataType method_error_type in error_types) {
    1125          217 :                                         if (body_error_type.compatible (method_error_type)) {
    1126          217 :                                                 can_propagate_error = true;
    1127              :                                         }
    1128              :                                 }
    1129              :                                 }
    1130          412 :                                 bool is_dynamic_error = body_error_type is ErrorType && ((ErrorType) body_error_type).dynamic_error;
    1131          412 :                                 if (!can_propagate_error && !is_dynamic_error) {
    1132          196 :                                         Report.warning (body_error_type.source_reference, "unhandled error `%s'", body_error_type.to_string());
    1133              :                                 }
    1134              :                         }
    1135              :                 }
    1136              : 
    1137              :                 // check that DBus methods at least throw "GLib.Error" or "GLib.DBusError, GLib.IOError"
    1138      9324772 :                 if (!(this is CreationMethod) && binding == MemberBinding.INSTANCE
    1139      4216282 :                     && !overrides && access == SymbolAccessibility.PUBLIC
    1140      4188845 :                     && parent_symbol is ObjectTypeSymbol && parent_symbol.has_attribute ("DBus")) {
    1141           96 :                         Attribute? dbus_attr = get_attribute ("DBus");
    1142          190 :                         if (dbus_attr == null || dbus_attr.get_bool ("visible", true)) {
    1143           94 :                                 bool throws_gerror = false;
    1144           94 :                                 bool throws_gioerror = false;
    1145           94 :                                 bool throws_gdbuserror = false;
    1146           94 :                                 var error_types = new ArrayList<DataType> ();
    1147           94 :                                 get_error_types (error_types);
    1148          228 :                                 foreach (DataType error_type in error_types) {
    1149           86 :                                         if (!(error_type is ErrorType)) {
    1150            0 :                                                 continue;
    1151              :                                         }
    1152           86 :                                         unowned ErrorDomain? error_domain = ((ErrorType) error_type).error_domain;
    1153           86 :                                         if (error_domain == null) {
    1154           19 :                                                 throws_gerror = true;
    1155           19 :                                                 break;
    1156              :                                         }
    1157           67 :                                         string? full_error_domain = error_domain.get_full_name ();
    1158           67 :                                         if (full_error_domain == "GLib.IOError") {
    1159              :                                                 throws_gioerror = true;
    1160           22 :                                         } else if (full_error_domain == "GLib.DBusError") {
    1161           20 :                                                 throws_gdbuserror = true;
    1162              :                                         }
    1163              :                                 }
    1164           94 :                                 if (!throws_gerror && !(throws_gioerror && throws_gdbuserror)) {
    1165           58 :                                         Report.warning (source_reference, "DBus methods are recommended to throw at least `GLib.Error' or `GLib.DBusError, GLib.IOError'");
    1166              :                                 }
    1167              :                         }
    1168              :                 }
    1169              : 
    1170      5662412 :                 if (is_possible_entry_point (context)) {
    1171         1342 :                         if (context.entry_point != null) {
    1172            1 :                                 error = true;
    1173            1 :                                 Report.error (source_reference, "program already has an entry point `%s'", context.entry_point.get_full_name ());
    1174            1 :                                 return false;
    1175              :                         }
    1176         1341 :                         entry_point = true;
    1177         1341 :                         context.entry_point = this;
    1178              : 
    1179         1341 :                         if (tree_can_fail) {
    1180            1 :                                 error = true;
    1181            1 :                                 Report.error (source_reference, "\"main\" method cannot throw errors");
    1182              :                         }
    1183              : 
    1184         1341 :                         if (is_inline) {
    1185            1 :                                 error = true;
    1186            1 :                                 Report.error (source_reference, "\"main\" method cannot be inline");
    1187              :                         }
    1188              :                 }
    1189              : 
    1190      5662411 :                 if (has_attribute ("GtkCallback")) {
    1191            5 :                         used = true;
    1192              :                 }
    1193              : 
    1194      5662411 :                 return !error;
    1195              :         }
    1196              : 
    1197      5662412 :         bool is_possible_entry_point (CodeContext context) {
    1198      5662412 :                 if (external_package) {
    1199      5661070 :                         return false;
    1200              :                 }
    1201              : 
    1202         5789 :                 if (context.entry_point_name == null) {
    1203         5789 :                         if (name == null || name != "main") {
    1204              :                                 // method must be called "main"
    1205         4447 :                                 return false;
    1206              :                         }
    1207              :                 } else {
    1208              :                         // custom entry point name
    1209            0 :                         if (get_full_name () != context.entry_point_name) {
    1210      5661070 :                                 return false;
    1211              :                         }
    1212              :                 }
    1213              : 
    1214         1342 :                 if (binding == MemberBinding.INSTANCE) {
    1215              :                         // method must be static
    1216      5661070 :                         return false;
    1217              :                 }
    1218              : 
    1219         1342 :                 if (return_type is VoidType) {
    1220           20 :                 } else if (return_type.type_symbol == context.analyzer.int_type.type_symbol) {
    1221              :                 } else {
    1222              :                         // return type must be void or int
    1223      5661070 :                         return false;
    1224              :                 }
    1225              : 
    1226         1342 :                 var params = get_parameters ();
    1227         1342 :                 if (params.size == 0) {
    1228              :                         // method may have no parameters
    1229         1248 :                         return true;
    1230              :                 }
    1231              : 
    1232           94 :                 if (params.size > 1) {
    1233              :                         // method must not have more than one parameter
    1234            0 :                         return false;
    1235              :                 }
    1236              : 
    1237           94 :                 Iterator<Parameter> params_it = params.iterator ();
    1238           94 :                 params_it.next ();
    1239           94 :                 var param = params_it.get ();
    1240              : 
    1241           94 :                 if (param.direction == ParameterDirection.OUT) {
    1242              :                         // parameter must not be an out parameter
    1243            0 :                         return false;
    1244              :                 }
    1245              : 
    1246           94 :                 if (!(param.variable_type is ArrayType)) {
    1247              :                         // parameter must be an array
    1248            0 :                         return false;
    1249              :                 }
    1250              : 
    1251           94 :                 unowned ArrayType array_type = (ArrayType) param.variable_type;
    1252           94 :                 if (array_type.element_type.type_symbol != context.analyzer.string_type.type_symbol) {
    1253              :                         // parameter must be an array of strings
    1254            0 :                         return false;
    1255              :                 }
    1256              : 
    1257           94 :                 return true;
    1258              :         }
    1259              : 
    1260          557 :         public int get_required_arguments () {
    1261          557 :                 int n = 0;
    1262          559 :                 foreach (var param in parameters) {
    1263          325 :                         if (param.initializer != null || param.ellipsis) {
    1264              :                                 // optional argument
    1265          324 :                                 break;
    1266              :                         }
    1267            1 :                         n++;
    1268              :                 }
    1269              :                 return n;
    1270              :         }
    1271              : 
    1272           22 :         public unowned Method get_end_method () {
    1273           22 :                 assert (this.coroutine);
    1274              : 
    1275           22 :                 if (end_method == null) {
    1276           21 :                         end_method = new Method ("end", return_type, source_reference);
    1277           21 :                         end_method.access = SymbolAccessibility.PUBLIC;
    1278           21 :                         end_method.external = true;
    1279           21 :                         end_method.owner = scope;
    1280           69 :                         foreach (var param in get_async_end_parameters ()) {
    1281           24 :                                 end_method.add_parameter (param.copy ());
    1282              :                         }
    1283           27 :                         foreach (var param in get_type_parameters ()) {
    1284            3 :                                 end_method.add_type_parameter (param);
    1285              :                         }
    1286           21 :                         end_method.copy_attribute_double (this, "CCode", "async_result_pos");
    1287              :                 }
    1288           22 :                 return end_method;
    1289              :         }
    1290              : 
    1291           61 :         public unowned Method get_callback_method () {
    1292           61 :                 assert (this.coroutine);
    1293              : 
    1294           84 :                 if (callback_method == null) {
    1295           23 :                         var bool_type = CodeContext.get ().analyzer.bool_type.copy ();
    1296           23 :                         bool_type.value_owned = true;
    1297           23 :                         callback_method = new Method ("callback", bool_type, source_reference);
    1298           23 :                         callback_method.access = SymbolAccessibility.PUBLIC;
    1299           23 :                         callback_method.external = true;
    1300           23 :                         callback_method.binding = MemberBinding.INSTANCE;
    1301           23 :                         callback_method.owner = scope;
    1302           23 :                         callback_method.is_async_callback = true;
    1303              :                 }
    1304           61 :                 return callback_method;
    1305              :         }
    1306              : 
    1307          209 :         public unowned List<Parameter> get_async_begin_parameters () {
    1308          209 :                 assert (this.coroutine);
    1309              : 
    1310          209 :                 if (async_begin_parameters != null) {
    1311          209 :                         return async_begin_parameters;
    1312              :                 }
    1313              : 
    1314           93 :                 async_begin_parameters = new ArrayList<Parameter> ();
    1315              : 
    1316           93 :                 var glib_ns = CodeContext.get ().root.scope.lookup ("GLib");
    1317              : 
    1318           93 :                 Parameter ellipsis = null;
    1319          265 :                 foreach (var param in parameters) {
    1320           86 :                         if (param.ellipsis) {
    1321            0 :                                 ellipsis = param;
    1322           86 :                         } else if (param.direction == ParameterDirection.IN) {
    1323           71 :                                 async_begin_parameters.add (param);
    1324              :                         }
    1325              :                 }
    1326              : 
    1327           93 :                 var callback_type = new DelegateType ((Delegate) glib_ns.scope.lookup ("AsyncReadyCallback"), source_reference);
    1328           93 :                 callback_type.nullable = true;
    1329           93 :                 callback_type.value_owned = true;
    1330           93 :                 callback_type.is_called_once = true;
    1331              : 
    1332           93 :                 var callback_param = new Parameter ("_callback_", callback_type, source_reference);
    1333           93 :                 callback_param.initializer = new NullLiteral (source_reference);
    1334           93 :                 callback_param.initializer.target_type = callback_type.copy ();
    1335           93 :                 callback_param.set_attribute_double ("CCode", "pos", -1);
    1336           93 :                 callback_param.set_attribute_double ("CCode", "delegate_target_pos", -0.9);
    1337           93 :                 scope.add (null, callback_param);
    1338           93 :                 async_begin_parameters.add (callback_param);
    1339              : 
    1340           93 :                 if (ellipsis != null) {
    1341            0 :                         async_begin_parameters.add (ellipsis);
    1342              :                 }
    1343              : 
    1344           93 :                 return async_begin_parameters;
    1345              :         }
    1346              : 
    1347          100 :         public unowned List<Parameter> get_async_end_parameters () {
    1348          100 :                 assert (this.coroutine);
    1349              : 
    1350          100 :                 if (async_end_parameters != null) {
    1351          100 :                         return async_end_parameters;
    1352              :                 }
    1353              : 
    1354           41 :                 async_end_parameters = new ArrayList<Parameter> ();
    1355              : 
    1356           41 :                 var glib_ns = CodeContext.get ().root.scope.lookup ("GLib");
    1357           41 :                 var result_type = new ObjectType ((ObjectTypeSymbol) glib_ns.scope.lookup ("AsyncResult"));
    1358              : 
    1359           41 :                 var result_param = new Parameter ("_res_", result_type, source_reference);
    1360           41 :                 result_param.set_attribute_double ("CCode", "pos", get_attribute_double ("CCode", "async_result_pos", 0.1));
    1361           41 :                 scope.add (null, result_param);
    1362           41 :                 async_end_parameters.add (result_param);
    1363              : 
    1364          131 :                 foreach (var param in parameters) {
    1365           45 :                         if (param.direction == ParameterDirection.OUT) {
    1366           15 :                                 async_end_parameters.add (param);
    1367              :                         }
    1368              :                 }
    1369              : 
    1370           41 :                 return async_end_parameters;
    1371              :         }
    1372              : 
    1373           91 :         public void add_captured_variable (LocalVariable local) {
    1374           91 :                 assert (this.closure);
    1375              : 
    1376           91 :                 if (captured_variables == null) {
    1377           72 :                         captured_variables = new ArrayList<LocalVariable> ();
    1378              :                 }
    1379           91 :                 captured_variables.add (local);
    1380              :         }
    1381              : 
    1382        15776 :         public void get_captured_variables (Collection<LocalVariable> variables) {
    1383        15776 :                 if (captured_variables != null) {
    1384          980 :                         foreach (var local in captured_variables) {
    1385          352 :                                 variables.add (local);
    1386              :                         }
    1387              :                 }
    1388              :         }
    1389              : 
    1390       263520 :         public override void get_defined_variables (Collection<Variable> collection) {
    1391       263520 :                 if (result_var != null) {
    1392           42 :                         collection.add (result_var);
    1393              :                 }
    1394       263520 :                 if (params_array_var != null) {
    1395           66 :                         collection.add (params_array_var);
    1396              :                 }
    1397              : 
    1398              :                 // capturing variables is only supported if they are initialized
    1399              :                 // therefore assume that captured variables are initialized
    1400       263520 :                 if (closure) {
    1401        11832 :                         get_captured_variables ((Collection<LocalVariable>) collection);
    1402              :                 }
    1403              :         }
    1404              : 
    1405        33148 :         public int get_format_arg_index () {
    1406        60044 :                 for (int i = 0; i < parameters.size; i++) {
    1407        26955 :                         if (parameters[i].format_arg) {
    1408           59 :                                 return i;
    1409              :                         }
    1410              :                 }
    1411        33148 :                 return -1;
    1412              :         }
    1413              : 
    1414        50017 :         public bool has_error_type_parameter () {
    1415        50017 :                 if (tree_can_fail) {
    1416              :                         return true;
    1417              :                 }
    1418        48821 :                 if (base_method != null && base_method != this && base_method.has_error_type_parameter ()) {
    1419              :                         return true;
    1420              :                 }
    1421        48812 :                 if (base_interface_method != null && base_interface_method != this && base_interface_method.has_error_type_parameter ()) {
    1422              :                         return true;
    1423              :                 }
    1424              :                 return false;
    1425              :         }
    1426              : }
    1427              : 
    1428              : // vim:sw=8 noet
        

Generated by: LCOV version 2.0-1