1 /* valacreationmethod.vala
3 * Copyright (C) 2007-2010 Jürg Billeter
4 * Copyright (C) 2007-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 * Raffaele Sandrini <raffaele@sandrini.ch>
22 * Jürg Billeter <j@bitron.ch>
28 * Represents a type creation method.
30 public class Vala
.CreationMethod
: Method
{
32 * Specifies the name of the type this creation method belongs to.
34 public string class_name
{ get; set; }
37 * Specifies a custom C return type for that creation method.
38 * Only the idl parser and the interface writer should use this.
39 * FIXME: remove this as soon the compiler has a decent attribute
42 public string? custom_return_type_cname
{ get; set; }
45 * Specifies whether this constructor chains up to a base
46 * constructor or a different constructor of the same class.
48 public bool chain_up
{ get; set; }
51 * Creates a new method.
53 * @param name method name
54 * @param source_reference reference to source code
55 * @return newly created method
57 public CreationMethod (string? class_name
, string? name
, SourceReference? source_reference
= null, Comment? comment
= null) {
58 base (name
, new
VoidType (), source_reference
, comment
);
59 this
.class_name
= class_name
;
61 carray_length_parameter_position
= -3;
62 cdelegate_target_parameter_position
= -3;
65 public override void accept (CodeVisitor visitor
) {
66 visitor
.visit_creation_method (this
);
69 public override void accept_children (CodeVisitor visitor
) {
70 foreach (Parameter param
in get_parameters()) {
71 param
.accept (visitor
);
74 foreach (DataType error_type
in get_error_types ()) {
75 error_type
.accept (visitor
);
78 foreach (Expression precondition
in get_preconditions ()) {
79 precondition
.accept (visitor
);
82 foreach (Expression postcondition
in get_postconditions ()) {
83 postcondition
.accept (visitor
);
87 body
.accept (visitor
);
91 public override string get_default_cname () {
92 var parent
= parent_symbol as TypeSymbol
;
95 var st
= parent as Struct
;
97 if (CodeContext
.get ().profile
== Profile
.DOVA
) {
98 if (st
.is_boolean_type () || st
.is_integer_type () || st
.is_floating_type ()) {
99 // don't use any infix for basic types
100 if (name
== ".new") {
101 return parent
.get_lower_case_cname ();
103 return "%s%s".printf (parent
.get_lower_case_cprefix (), name
);
110 if (name
== ".new") {
111 return "%s%s".printf (parent
.get_lower_case_cprefix (), infix
);
113 return "%s%s_%s".printf (parent
.get_lower_case_cprefix (), infix
, name
);
117 public override string get_real_cname () {
118 var ccode_attribute
= get_attribute ("CCode");
119 if (ccode_attribute
!= null && ccode_attribute
.has_argument ("construct_function")) {
120 return ccode_attribute
.get_string ("construct_function");
123 return get_default_construct_function ();
126 public string get_default_construct_function () {
127 var parent
= parent_symbol as Class
;
129 if (parent
== null || parent
.is_compact
) {
133 string infix
= "construct";
135 if (CodeContext
.get ().profile
== Profile
.DOVA
) {
139 if (name
== ".new") {
140 return "%s%s".printf (parent
.get_lower_case_cprefix (), infix
);
142 return "%s%s_%s".printf (parent
.get_lower_case_cprefix (), infix
, name
);
146 public override bool check (CodeContext context
) {
153 process_attributes ();
155 if (class_name
!= null && class_name
!= parent_symbol
.name
) {
156 // class_name is null for constructors generated by GIdlParser
157 Report
.error (source_reference
, "missing return type in method `%s.%s´".printf (context
.analyzer
.current_symbol
.get_full_name (), class_name
));
162 var old_source_file
= context
.analyzer
.current_source_file
;
163 var old_symbol
= context
.analyzer
.current_symbol
;
165 if (source_reference
!= null) {
166 context
.analyzer
.current_source_file
= source_reference
.file
;
168 context
.analyzer
.current_symbol
= this
;
170 foreach (Parameter param
in get_parameters()) {
171 param
.check (context
);
174 foreach (DataType error_type
in get_error_types ()) {
175 error_type
.check (context
);
178 foreach (Expression precondition
in get_preconditions ()) {
179 precondition
.check (context
);
182 foreach (Expression postcondition
in get_postconditions ()) {
183 postcondition
.check (context
);
187 body
.check (context
);
189 var cl
= parent_symbol as Class
;
191 // ensure we chain up to base constructor
192 if (!chain_up
&& cl
!= null && cl
.base_class
!= null) {
193 if (context
.profile
== Profile
.GOBJECT
194 && cl
.base_class
.default_construction_method
!= null
195 && !cl
.base_class
.default_construction_method
.has_construct_function
) {
196 // directly chain up to Object
197 var old_insert_block
= context
.analyzer
.insert_block
;
198 context
.analyzer
.current_symbol
= body
;
199 context
.analyzer
.insert_block
= body
;
201 var stmt
= new
ExpressionStatement (new
MethodCall (new
MemberAccess (new MemberAccess
.simple ("GLib", source_reference
), "Object", source_reference
), source_reference
), source_reference
);
202 body
.insert_statement (0, stmt
);
203 stmt
.check (context
);
205 context
.analyzer
.current_symbol
= this
;
206 context
.analyzer
.insert_block
= old_insert_block
;
207 } else if (cl
.base_class
.default_construction_method
== null
208 || cl
.base_class
.default_construction_method
.access
== SymbolAccessibility
.PRIVATE
) {
209 Report
.error (source_reference
, "unable to chain up to private base constructor");
210 } else if (cl
.base_class
.default_construction_method
.get_required_arguments () > 0) {
211 Report
.error (source_reference
, "unable to chain up to base constructor requiring arguments");
213 var old_insert_block
= context
.analyzer
.insert_block
;
214 context
.analyzer
.current_symbol
= body
;
215 context
.analyzer
.insert_block
= body
;
217 var stmt
= new
ExpressionStatement (new
MethodCall (new
BaseAccess (source_reference
), source_reference
), source_reference
);
218 body
.insert_statement (0, stmt
);
219 stmt
.check (context
);
221 context
.analyzer
.current_symbol
= this
;
222 context
.analyzer
.insert_block
= old_insert_block
;
227 context
.analyzer
.current_source_file
= old_source_file
;
228 context
.analyzer
.current_symbol
= old_symbol
;
230 if (is_abstract
|| is_virtual
|| overrides
) {
231 Report
.error (source_reference
, "The creation method `%s' cannot be marked as override, virtual, or abstract".printf (get_full_name ()));
235 // check that all errors that can be thrown in the method body are declared
237 foreach (DataType body_error_type
in body
.get_error_types ()) {
238 bool can_propagate_error
= false;
239 foreach (DataType method_error_type
in get_error_types ()) {
240 if (body_error_type
.compatible (method_error_type
)) {
241 can_propagate_error
= true;
244 if (!can_propagate_error
&& !((ErrorType
) body_error_type
).dynamic_error
) {
245 Report
.warning (body_error_type
.source_reference
, "unhandled error `%s'".printf (body_error_type
.to_string()));