3 * Copyright (C) 2006-2010 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
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.
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.
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
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
28 * Represents a type or namespace method.
30 public class Vala
.Method
: Subroutine
, Callable
{
31 List
<TypeParameter
> type_parameters
;
34 * The return type of this method.
36 public DataType return_type
{
37 get { return _return_type
; }
40 _return_type
.parent_node
= this
;
44 public override bool has_result
{
45 get { return !(return_type is VoidType
); }
49 * Specifies whether this method may only be called with an instance of
52 public MemberBinding binding
{ get; set; default = MemberBinding
.INSTANCE
; }
55 * Specifies whether this method is abstract. Abstract methods have no
56 * body, may only be specified within abstract classes, and must be
57 * overriden by derived non-abstract classes.
59 public bool is_abstract
{ get; set; }
62 * Specifies whether this method is virtual. Virtual methods may be
63 * overridden by derived classes.
65 public bool is_virtual
{ get; set; }
68 * Specifies whether this method overrides a virtual or abstract method
71 public bool overrides
{ get; set; }
74 * Specifies whether this method should be inlined.
76 public bool is_inline
{ get; set; }
78 public bool returns_floating_reference
{
80 return get_attribute_bool ("CCode", "returns_floating_reference");
83 set_attribute_bool ("CCode", "returns_floating_reference", value
);
88 * Specifies whether the C method returns a new instance pointer which
89 * may be different from the previous instance pointer. Only valid for
92 public bool returns_modified_pointer
{
94 return get_attribute ("ReturnsModifiedPointer") != null;
97 set_attribute ("ReturnsModifiedPointer", value
);
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.
106 public Method base_method
{
108 find_base_methods ();
114 * Specifies the abstract interface method this method implements.
116 public Method base_interface_method
{
118 find_base_methods ();
119 return _base_interface_method
;
124 * Specifies the explicit interface containing the method this method implements.
126 public DataType base_interface_type
{
127 get { return _base_interface_type
; }
129 _base_interface_type
= value
;
130 _base_interface_type
.parent_node
= this
;
134 public bool entry_point
{ get; private set; }
137 * Specifies the generated `this` parameter for instance methods.
139 public Parameter this_parameter
{ get; set; }
142 * Specifies whether this method expects printf-style format arguments.
144 public bool printf_format
{
146 return get_attribute ("PrintfFormat") != null;
149 set_attribute ("PrintfFormat", value
);
154 * Specifies whether this method expects scanf-style format arguments.
156 public bool scanf_format
{
158 return get_attribute ("ScanfFormat") != null;
161 set_attribute ("ScanfFormat", value
);
166 * Specifies whether a construct function with a GType parameter is
167 * available. This is only applicable to creation methods.
169 public bool has_construct_function
{
171 return get_attribute_bool ("CCode", "has_construct_function", true);
174 set_attribute_bool ("CCode", "has_construct_function", value
);
178 public weak Signal signal_reference
{ get; set; }
180 public bool closure
{ get; set; }
182 public bool coroutine
{ get; set; }
184 public bool is_async_callback
{ get; set; }
186 private List
<Parameter
> parameters
= new ArrayList
<Parameter
> ();
187 private List
<Expression
> preconditions
;
188 private List
<Expression
> postconditions
;
189 private DataType _return_type
;
191 private weak Method _base_method
;
192 private weak Method _base_interface_method
;
193 private DataType _base_interface_type
;
194 private bool base_methods_valid
;
196 Method? callback_method
;
199 // only valid for closures
200 List
<LocalVariable
> captured_variables
;
202 static List
<Expression
> _empty_expression_list
;
203 static List
<TypeParameter
> _empty_type_parameter_list
;
206 * Creates a new method.
208 * @param name method name
209 * @param return_type method return type
210 * @param source_reference reference to source code
211 * @return newly created method
213 public Method (string? name
, DataType return_type
, SourceReference? source_reference
= null, Comment? comment
= null) {
214 base (name
, source_reference
, comment
);
215 this
.return_type
= return_type
;
219 * Appends parameter to this method.
221 * @param param a formal parameter
223 public void add_parameter (Parameter param
) {
224 // default C parameter position
225 parameters
.add (param
);
226 scope
.add (param
.name
, param
);
229 public List
<Parameter
> get_parameters () {
234 * Remove all parameters from this method.
236 public void clear_parameters () {
237 foreach (Parameter param
in parameters
) {
238 if (!param
.ellipsis
) {
239 scope
.remove (param
.name
);
245 public bool is_variadic () {
246 foreach (Parameter param
in parameters
) {
247 if (param
.ellipsis
) {
254 public override void accept (CodeVisitor visitor
) {
255 visitor
.visit_method (this
);
258 public override void accept_children (CodeVisitor visitor
) {
259 foreach (TypeParameter p
in get_type_parameters ()) {
263 if (base_interface_type
!= null) {
264 base_interface_type
.accept (visitor
);
267 if (return_type
!= null) {
268 return_type
.accept (visitor
);
271 foreach (Parameter param
in parameters
) {
272 param
.accept (visitor
);
275 foreach (DataType error_type
in get_error_types ()) {
276 error_type
.accept (visitor
);
279 if (result_var
!= null) {
280 result_var
.accept (visitor
);
283 if (preconditions
!= null) {
284 foreach (Expression precondition
in preconditions
) {
285 precondition
.accept (visitor
);
289 if (postconditions
!= null) {
290 foreach (Expression postcondition
in postconditions
) {
291 postcondition
.accept (visitor
);
296 body
.accept (visitor
);
301 * Checks whether the parameters and return type of this method are
302 * compatible with the specified method
304 * @param base_method a method
305 * @param invalid_match error string about which check failed
306 * @return true if the specified method is compatible to this method
308 public bool compatible (Method base_method
, out string? invalid_match
) {
309 // method is always compatible to itself
310 if (this
== base_method
) {
311 invalid_match
= null;
315 if (binding
!= base_method
.binding
) {
316 invalid_match
= "incompatible binding";
320 ObjectType object_type
= null;
321 if (parent_symbol is ObjectTypeSymbol
) {
322 object_type
= new
ObjectType ((ObjectTypeSymbol
) parent_symbol
);
323 foreach (TypeParameter type_parameter
in object_type
.type_symbol
.get_type_parameters ()) {
324 var type_arg
= new
GenericType (type_parameter
);
325 type_arg
.value_owned
= true;
326 object_type
.add_type_argument (type_arg
);
330 if (this
.get_type_parameters ().size
< base_method
.get_type_parameters ().size
) {
331 invalid_match
= "too few type parameters";
333 } else if (this
.get_type_parameters ().size
> base_method
.get_type_parameters ().size
) {
334 invalid_match
= "too many type parameters";
338 List
<DataType
> method_type_args
= null;
339 if (this
.get_type_parameters ().size
> 0) {
340 method_type_args
= new ArrayList
<DataType
> ();
341 foreach (TypeParameter type_parameter
in this
.get_type_parameters ()) {
342 var type_arg
= new
GenericType (type_parameter
);
343 type_arg
.value_owned
= true;
344 method_type_args
.add (type_arg
);
348 var actual_base_type
= base_method
.return_type
.get_actual_type (object_type
, method_type_args
, this
);
349 if (!return_type
.equals (actual_base_type
)) {
350 invalid_match
= "Base method expected return type `%s', but `%s' was provided".printf (actual_base_type
.to_prototype_string (), return_type
.to_prototype_string ());
354 Iterator
<Parameter
> method_params_it
= parameters
.iterator ();
356 foreach (Parameter base_param
in base_method
.parameters
) {
357 /* this method may not expect less arguments */
358 if (!method_params_it
.next ()) {
359 invalid_match
= "too few parameters";
363 var param
= method_params_it
.get ();
364 if (base_param
.ellipsis
!= param
.ellipsis
) {
365 invalid_match
= "ellipsis parameter mismatch";
368 if (!base_param
.ellipsis
) {
369 if (base_param
.direction
!= param
.direction
) {
370 invalid_match
= "incompatible direction of parameter %d".printf (param_index
);
374 actual_base_type
= base_param
.variable_type
.get_actual_type (object_type
, method_type_args
, this
);
375 if (!actual_base_type
.equals (param
.variable_type
)) {
376 invalid_match
= "incompatible type of parameter %d".printf (param_index
);
383 /* this method may not expect more arguments */
384 if (method_params_it
.next ()) {
385 invalid_match
= "too many parameters";
389 /* this method may throw less but not more errors than the base method */
390 foreach (DataType method_error_type
in get_error_types ()) {
392 foreach (DataType base_method_error_type
in base_method
.get_error_types ()) {
393 if (method_error_type
.compatible (base_method_error_type
)) {
400 invalid_match
= "incompatible error type `%s'".printf (method_error_type
.to_string ());
404 if (base_method
.coroutine
!= this
.coroutine
) {
405 invalid_match
= "async mismatch";
409 invalid_match
= null;
414 * Appends the specified parameter to the list of type parameters.
416 * @param p a type parameter
418 public void add_type_parameter (TypeParameter p
) {
419 if (type_parameters
== null) {
420 type_parameters
= new ArrayList
<TypeParameter
> ();
422 type_parameters
.add (p
);
423 scope
.add (p
.name
, p
);
427 * Returns a copy of the type parameter list.
429 * @return list of type parameters
431 public List
<TypeParameter
> get_type_parameters () {
432 if (type_parameters
!= null) {
433 return type_parameters
;
435 if (_empty_type_parameter_list
== null) {
436 _empty_type_parameter_list
= new ArrayList
<TypeParameter
> ();
438 return _empty_type_parameter_list
;
441 public int get_type_parameter_index (string name
) {
442 if (type_parameters
== null) {
447 foreach (TypeParameter parameter
in type_parameters
) {
448 if (parameter
.name
== name
) {
457 * Adds a precondition to this method.
459 * @param precondition a boolean precondition expression
461 public void add_precondition (Expression precondition
) {
462 if (preconditions
== null) {
463 preconditions
= new ArrayList
<Expression
> ();
465 preconditions
.add (precondition
);
466 precondition
.parent_node
= this
;
470 * Returns a copy of the list of preconditions of this method.
472 * @return list of preconditions
474 public List
<Expression
> get_preconditions () {
475 if (preconditions
!= null) {
476 return preconditions
;
478 if (_empty_expression_list
== null) {
479 _empty_expression_list
= new ArrayList
<Expression
> ();
481 return _empty_expression_list
;
485 * Adds a postcondition to this method.
487 * @param postcondition a boolean postcondition expression
489 public void add_postcondition (Expression postcondition
) {
490 if (postconditions
== null) {
491 postconditions
= new ArrayList
<Expression
> ();
493 postconditions
.add (postcondition
);
494 postcondition
.parent_node
= this
;
498 * Returns a copy of the list of postconditions of this method.
500 * @return list of postconditions
502 public List
<Expression
> get_postconditions () {
503 if (postconditions
!= null) {
504 return postconditions
;
506 if (_empty_expression_list
== null) {
507 _empty_expression_list
= new ArrayList
<Expression
> ();
509 return _empty_expression_list
;
512 public override void replace_type (DataType old_type
, DataType new_type
) {
513 if (base_interface_type
== old_type
) {
514 base_interface_type
= new_type
;
517 if (return_type
== old_type
) {
518 return_type
= new_type
;
521 var error_types
= get_error_types ();
522 for (int i
= 0; i
< error_types
.size
; i
++) {
523 if (error_types
[i
] == old_type
) {
524 error_types
[i
] = new_type
;
530 private void find_base_methods () {
531 if (base_methods_valid
) {
535 if (parent_symbol is Class
) {
536 if (!(this is CreationMethod
)) {
537 find_base_interface_method ((Class
) parent_symbol
);
538 if (is_virtual
|| is_abstract
|| overrides
) {
539 find_base_class_method ((Class
) parent_symbol
);
542 } else if (parent_symbol is Interface
) {
543 if (is_virtual
|| is_abstract
) {
544 _base_interface_method
= this
;
548 base_methods_valid
= true;
551 private void find_base_class_method (Class cl
) {
552 var sym
= cl
.scope
.lookup (name
);
554 var sig
= (Signal
) sym
;
555 sym
= sig
.default_handler
;
558 var base_method
= (Method
) sym
;
559 if (base_method
.is_abstract
|| base_method
.is_virtual
) {
560 string invalid_match
;
561 if (!compatible (base_method
, out invalid_match
)) {
563 var base_method_type
= new
MethodType (base_method
);
564 Report
.error (source_reference
, "overriding method `%s' is incompatible with base method `%s': %s.".printf (get_full_name (), base_method_type
.to_prototype_string (), invalid_match
));
568 _base_method
= base_method
;
573 if (cl
.base_class
!= null) {
574 find_base_class_method (cl
.base_class
);
578 private void find_base_interface_method (Class cl
) {
579 foreach (DataType type
in cl
.get_base_types ()) {
580 if (type
.data_type is Interface
) {
581 if (base_interface_type
!= null && base_interface_type
.data_type
!= type
.data_type
) {
585 var sym
= type
.data_type
.scope
.lookup (name
);
587 var sig
= (Signal
) sym
;
588 sym
= sig
.default_handler
;
591 var base_method
= (Method
) sym
;
592 if (base_method
.is_abstract
|| base_method
.is_virtual
) {
593 if (base_interface_type
== null) {
594 // check for existing explicit implementation
595 var has_explicit_implementation
= false;
596 foreach (var m
in cl
.get_methods ()) {
597 if (m
.base_interface_type
!= null && base_method
== m
.base_interface_method
) {
598 has_explicit_implementation
= true;
602 if (has_explicit_implementation
) {
607 string invalid_match
= null;
608 if (!compatible (base_method
, out invalid_match
)) {
610 var base_method_type
= new
MethodType (base_method
);
611 Report
.error (source_reference
, "overriding method `%s' is incompatible with base method `%s': %s.".printf (get_full_name (), base_method_type
.to_prototype_string (), invalid_match
));
615 _base_interface_method
= base_method
;
622 if (base_interface_type
!= null) {
623 Report
.error (source_reference
, "`%s': no suitable interface method found to implement".printf (get_full_name ()));
627 public override bool check (CodeContext context
) {
634 if (get_attribute ("DestroysInstance") != null) {
635 this_parameter
.variable_type
.value_owned
= true;
637 if (get_attribute ("NoThrow") != null) {
638 get_error_types ().clear ();
641 if (parent_symbol is Class
&& (is_abstract
|| is_virtual
)) {
642 var cl
= (Class
) parent_symbol
;
643 if (cl
.is_compact
&& cl
.base_class
!= null) {
645 Report
.error (source_reference
, "Abstract and virtual methods may not be declared in derived compact classes");
651 if (parent_symbol is Class
) {
652 var cl
= (Class
) parent_symbol
;
653 if (!cl
.is_abstract
) {
655 Report
.error (source_reference
, "Abstract methods may not be declared in non-abstract classes");
658 } else if (!(parent_symbol is Interface
)) {
660 Report
.error (source_reference
, "Abstract methods may not be declared outside of classes and interfaces");
663 } else if (is_virtual
) {
664 if (!(parent_symbol is Class
) && !(parent_symbol is Interface
)) {
666 Report
.error (source_reference
, "Virtual methods may not be declared outside of classes and interfaces");
669 } else if (overrides
) {
670 if (!(parent_symbol is Class
)) {
672 Report
.error (source_reference
, "Methods may not be overridden outside of classes");
675 } else if (access
== SymbolAccessibility
.PROTECTED
) {
676 if (!(parent_symbol is Class
) && !(parent_symbol is Interface
)) {
678 Report
.error (source_reference
, "Protected methods may not be declared outside of classes and interfaces");
683 if (is_abstract
&& body
!= null) {
684 Report
.error (source_reference
, "Abstract methods cannot have bodies");
685 } else if ((is_abstract
|| is_virtual
) && external
&& !external_package
&& !parent_symbol
.external
) {
686 Report
.error (source_reference
, "Extern methods cannot be abstract or virtual");
687 } else if (external
&& body
!= null) {
688 Report
.error (source_reference
, "Extern methods cannot have bodies");
689 } else if (!is_abstract
&& !external
&& source_type
== SourceFileType
.SOURCE
&& body
== null) {
690 Report
.error (source_reference
, "Non-abstract, non-extern methods must have bodies");
693 if (coroutine
&& !external_package
&& !context
.has_package ("gio-2.0")) {
695 Report
.error (source_reference
, "gio-2.0 package required for async methods");
699 var old_source_file
= context
.analyzer
.current_source_file
;
700 var old_symbol
= context
.analyzer
.current_symbol
;
702 if (source_reference
!= null) {
703 context
.analyzer
.current_source_file
= source_reference
.file
;
705 context
.analyzer
.current_symbol
= this
;
707 return_type
.floating_reference
= returns_floating_reference
;
708 return_type
.check (context
);
710 var init_attr
= get_attribute ("ModuleInit");
711 if (init_attr
!= null) {
712 source_reference
.file
.context
.module_init_method
= this
;
715 if (return_type
!= null) {
716 return_type
.check (context
);
719 if (parameters
.size
== 1 && parameters
[0].ellipsis
&& body
!= null && binding
!= MemberBinding
.INSTANCE
) {
720 // accept just `...' for external methods and instance methods
722 Report
.error (parameters
[0].source_reference
, "Named parameter required before `...'");
725 var optional_param
= false;
726 foreach (Parameter param
in parameters
) {
727 param
.check (context
);
728 if (coroutine
&& param
.direction
== ParameterDirection
.REF
) {
730 Report
.error (param
.source_reference
, "Reference parameters are not supported for async methods");
732 // TODO: begin and end parameters must be checked separately for coroutines
736 if (optional_param
&& param
.initializer
== null && !param
.ellipsis
) {
737 Report
.warning (param
.source_reference
, "parameter without default follows parameter with default");
738 } else if (param
.initializer
!= null) {
739 optional_param
= true;
743 foreach (DataType error_type
in get_error_types ()) {
744 error_type
.check (context
);
746 // check whether error type is at least as accessible as the method
747 if (!context
.analyzer
.is_type_accessible (this
, error_type
)) {
749 Report
.error (source_reference
, "error type `%s` is less accessible than method `%s`".printf (error_type
.to_string (), get_full_name ()));
754 if (result_var
!= null) {
755 result_var
.check (context
);
758 if (preconditions
!= null) {
759 foreach (Expression precondition
in preconditions
) {
760 precondition
.check (context
);
764 if (postconditions
!= null) {
765 foreach (Expression postcondition
in postconditions
) {
766 postcondition
.check (context
);
771 body
.check (context
);
774 if (context
.analyzer
.current_struct
!= null) {
775 if (is_abstract
|| is_virtual
|| overrides
) {
777 Report
.error (source_reference
, "A struct member `%s' cannot be marked as override, virtual, or abstract".printf (get_full_name ()));
780 } else if (overrides
&& base_method
== null) {
781 Report
.error (source_reference
, "`%s': no suitable method found to override".printf (get_full_name ()));
782 } else if ((is_abstract
|| is_virtual
|| overrides
) && access
== SymbolAccessibility
.PRIVATE
) {
784 Report
.error (source_reference
, "Private member `%s' cannot be marked as override, virtual, or abstract".printf (get_full_name ()));
788 if (base_interface_type
!= null && base_interface_method
!= null && parent_symbol is Class
) {
789 var cl
= (Class
) parent_symbol
;
790 foreach (var m
in cl
.get_methods ()) {
791 if (m
!= this
&& m
.base_interface_method
== base_interface_method
) {
795 Report
.error (source_reference
, "`%s' already contains an implementation for `%s'".printf (cl
.get_full_name (), base_interface_method
.get_full_name ()));
796 Report
.notice (m
.source_reference
, "previous implementation of `%s' was here".printf (base_interface_method
.get_full_name ()));
802 context
.analyzer
.current_source_file
= old_source_file
;
803 context
.analyzer
.current_symbol
= old_symbol
;
805 if (!external_package
&& !overrides
&& !hides
&& get_hidden_member () != null) {
806 Report
.warning (source_reference
, "%s hides inherited method `%s'. Use the `new' keyword if hiding was intentional".printf (get_full_name (), get_hidden_member ().get_full_name ()));
809 // check whether return type is at least as accessible as the method
810 if (!context
.analyzer
.is_type_accessible (this
, return_type
)) {
812 Report
.error (source_reference
, "return type `%s` is less accessible than method `%s`".printf (return_type
.to_string (), get_full_name ()));
816 foreach (Expression precondition
in get_preconditions ()) {
817 if (precondition
.error
) {
818 // if there was an error in the precondition, skip this check
823 if (!precondition
.value_type
.compatible (context
.analyzer
.bool_type
)) {
825 Report
.error (precondition
.source_reference
, "Precondition must be boolean");
830 foreach (Expression postcondition
in get_postconditions ()) {
831 if (postcondition
.error
) {
832 // if there was an error in the postcondition, skip this check
837 if (!postcondition
.value_type
.compatible (context
.analyzer
.bool_type
)) {
839 Report
.error (postcondition
.source_reference
, "Postcondition must be boolean");
844 // check that all errors that can be thrown in the method body are declared
846 foreach (DataType body_error_type
in body
.get_error_types ()) {
847 bool can_propagate_error
= false;
848 foreach (DataType method_error_type
in get_error_types ()) {
849 if (body_error_type
.compatible (method_error_type
)) {
850 can_propagate_error
= true;
853 bool is_dynamic_error
= body_error_type is ErrorType
&& ((ErrorType
) body_error_type
).dynamic_error
;
854 if (!can_propagate_error
&& !is_dynamic_error
) {
855 Report
.warning (body_error_type
.source_reference
, "unhandled error `%s'".printf (body_error_type
.to_string()));
860 // check that DBus methods at least throw "GLib.Error" or "GLib.DBusError, GLib.IOError"
861 if (!(this is CreationMethod
) && binding
== MemberBinding
.INSTANCE
862 && !overrides
&& access
== SymbolAccessibility
.PUBLIC
863 && parent_symbol is ObjectTypeSymbol
&& parent_symbol
.get_attribute ("DBus") != null) {
864 Attribute? dbus_attr
= get_attribute ("DBus");
865 if (dbus_attr
== null || dbus_attr
.get_bool ("visible", true)) {
866 bool throws_gerror
= false;
867 bool throws_gioerror
= false;
868 bool throws_gdbuserror
= false;
869 foreach (DataType error_type
in get_error_types ()) {
870 if (!(error_type is ErrorType
)) {
873 unowned ErrorDomain? error_domain
= ((ErrorType
) error_type
).error_domain
;
874 if (error_domain
== null) {
875 throws_gerror
= true;
878 string? full_error_domain
= error_domain
.get_full_name ();
879 if (full_error_domain
== "GLib.IOError") {
880 throws_gioerror
= true;
881 } else if (full_error_domain
== "GLib.DBusError") {
882 throws_gdbuserror
= true;
885 if (!throws_gerror
&& !(throws_gioerror
&& throws_gdbuserror
)) {
886 Report
.warning (source_reference
, "DBus methods are recommended to throw at least `GLib.Error' or `GLib.DBusError, GLib.IOError'");
891 if (is_possible_entry_point (context
)) {
892 if (context
.entry_point
!= null) {
894 Report
.error (source_reference
, "program already has an entry point `%s'".printf (context
.entry_point
.get_full_name ()));
898 context
.entry_point
= this
;
901 Report
.error (source_reference
, "\"main\" method cannot throw errors");
905 Report
.error (source_reference
, "\"main\" method cannot be inline");
909 Report
.error (source_reference
, "\"main\" method cannot be async");
913 if (get_attribute ("GtkCallback") != null) {
920 bool is_possible_entry_point (CodeContext context
) {
921 if (external_package
) {
925 if (context
.entry_point_name
== null) {
926 if (name
== null || name
!= "main") {
927 // method must be called "main"
931 // custom entry point name
932 if (get_full_name () != context
.entry_point_name
) {
937 if (binding
== MemberBinding
.INSTANCE
) {
938 // method must be static
942 if (return_type is VoidType
) {
943 } else if (return_type
.data_type
== context
.analyzer
.int_type
.data_type
) {
945 // return type must be void or int
949 var params
= get_parameters ();
950 if (params
.size
== 0) {
951 // method may have no parameters
955 if (params
.size
> 1) {
956 // method must not have more than one parameter
960 Iterator
<Parameter
> params_it
= params
.iterator ();
962 var param
= params_it
.get ();
964 if (param
.direction
== ParameterDirection
.OUT
) {
965 // parameter must not be an out parameter
969 if (!(param
.variable_type is ArrayType
)) {
970 // parameter must be an array
974 var array_type
= (ArrayType
) param
.variable_type
;
975 if (array_type
.element_type
.data_type
!= context
.analyzer
.string_type
.data_type
) {
976 // parameter must be an array of strings
983 public int get_required_arguments () {
985 foreach (var param
in parameters
) {
986 if (param
.initializer
!= null || param
.ellipsis
) {
995 public Method
get_end_method () {
996 assert (this
.coroutine
);
998 if (end_method
== null) {
999 end_method
= new
Method ("end", return_type
, source_reference
);
1000 end_method
.access
= SymbolAccessibility
.PUBLIC
;
1001 end_method
.external
= true;
1002 end_method
.owner
= scope
;
1003 foreach (var param
in get_async_end_parameters ()) {
1004 end_method
.add_parameter (param
.copy ());
1006 foreach (var param
in get_type_parameters ()) {
1007 end_method
.add_type_parameter (param
);
1013 public Method
get_callback_method () {
1014 assert (this
.coroutine
);
1016 if (callback_method
== null) {
1017 var bool_type
= new
BooleanType ((Struct
) CodeContext
.get ().root
.scope
.lookup ("bool"));
1018 bool_type
.value_owned
= true;
1019 callback_method
= new
Method ("callback", bool_type
, source_reference
);
1020 callback_method
.access
= SymbolAccessibility
.PUBLIC
;
1021 callback_method
.external
= true;
1022 callback_method
.binding
= MemberBinding
.INSTANCE
;
1023 callback_method
.owner
= scope
;
1024 callback_method
.is_async_callback
= true;
1026 return callback_method
;
1029 public List
<Parameter
> get_async_begin_parameters () {
1030 assert (this
.coroutine
);
1032 var glib_ns
= CodeContext
.get ().root
.scope
.lookup ("GLib");
1034 var params
= new ArrayList
<Parameter
> ();
1035 Parameter ellipsis
= null;
1036 foreach (var param
in parameters
) {
1037 if (param
.ellipsis
) {
1039 } else if (param
.direction
== ParameterDirection
.IN
) {
1044 var callback_type
= new
DelegateType ((Delegate
) glib_ns
.scope
.lookup ("AsyncReadyCallback"));
1045 callback_type
.nullable
= true;
1046 callback_type
.value_owned
= true;
1047 callback_type
.is_called_once
= true;
1049 var callback_param
= new
Parameter ("_callback_", callback_type
);
1050 callback_param
.initializer
= new
NullLiteral (source_reference
);
1051 callback_param
.initializer
.target_type
= callback_type
.copy ();
1052 callback_param
.set_attribute_double ("CCode", "pos", -1);
1053 callback_param
.set_attribute_double ("CCode", "delegate_target_pos", -0.9);
1055 params
.add (callback_param
);
1057 if (ellipsis
!= null) {
1058 params
.add (ellipsis
);
1064 public List
<Parameter
> get_async_end_parameters () {
1065 assert (this
.coroutine
);
1067 var params
= new ArrayList
<Parameter
> ();
1069 var glib_ns
= CodeContext
.get ().root
.scope
.lookup ("GLib");
1070 var result_type
= new
ObjectType ((ObjectTypeSymbol
) glib_ns
.scope
.lookup ("AsyncResult"));
1072 var result_param
= new
Parameter ("_res_", result_type
);
1073 result_param
.set_attribute_double ("CCode", "pos", 0.1);
1074 params
.add (result_param
);
1076 foreach (var param
in parameters
) {
1077 if (param
.direction
== ParameterDirection
.OUT
) {
1085 public void add_captured_variable (LocalVariable local
) {
1086 assert (this
.closure
);
1088 if (captured_variables
== null) {
1089 captured_variables
= new ArrayList
<LocalVariable
> ();
1091 captured_variables
.add (local
);
1094 public void get_captured_variables (Collection
<LocalVariable
> variables
) {
1095 if (captured_variables
!= null) {
1096 foreach (var local
in captured_variables
) {
1097 variables
.add (local
);
1102 public override void get_defined_variables (Collection
<Variable
> collection
) {
1103 // capturing variables is only supported if they are initialized
1104 // therefore assume that captured variables are initialized
1106 get_captured_variables ((Collection
<LocalVariable
>) collection
);
1110 public int get_format_arg_index () {
1111 for (int i
= 0; i
< parameters
.size
; i
++) {
1112 if (parameters
[i
].format_arg
) {
1119 public bool has_error_type_parameter () {
1120 if (get_error_types ().size
> 0) {
1123 if (base_method
!= null && base_method
!= this
&& base_method
.has_error_type_parameter ()) {
1126 if (base_interface_method
!= null && base_interface_method
!= this
&& base_interface_method
.has_error_type_parameter ()) {