1 /* valacreationmethod.vala
3 * Copyright (C) 2007-2009 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 the number of parameters this creation method sets.
39 public int n_construction_params
{ get; set; }
42 * Specifies a custom C return type for that creation method.
43 * Only the idl parser and the interface writer should use this.
44 * FIXME: remove this as soon the compiler has a decent attribute
47 public string? custom_return_type_cname
{ get; set; }
50 * Specifies whether this constructor chains up to a base
51 * constructor or a different constructor of the same class.
53 public bool chain_up
{ get; set; }
56 * Creates a new method.
58 * @param name method name
59 * @param source_reference reference to source code
60 * @return newly created method
62 public CreationMethod (string? class_name
, string? name
, SourceReference? source_reference
= null, Comment? comment
= null) {
63 base (name
, new
VoidType (), source_reference
, comment
);
64 this
.class_name
= class_name
;
66 carray_length_parameter_position
= -3;
67 cdelegate_target_parameter_position
= -3;
70 public override void accept (CodeVisitor visitor
) {
71 visitor
.visit_creation_method (this
);
74 public override void accept_children (CodeVisitor visitor
) {
75 foreach (FormalParameter param
in get_parameters()) {
76 param
.accept (visitor
);
79 foreach (DataType error_type
in get_error_types ()) {
80 error_type
.accept (visitor
);
84 body
.accept (visitor
);
88 public override string get_default_cname () {
89 var parent
= parent_symbol as TypeSymbol
;
92 if (parent is Struct
) {
97 return "%s%s".printf (parent
.get_lower_case_cprefix (), infix
);
99 return "%s%s_%s".printf (parent
.get_lower_case_cprefix (), infix
, name
);
103 public override string get_real_cname () {
104 var parent
= parent_symbol as Class
;
106 if (parent
== null || parent
.is_compact
) {
110 var ccode_attribute
= get_attribute ("CCode");
111 if (ccode_attribute
!= null && ccode_attribute
.has_argument ("construct_function")) {
112 return ccode_attribute
.get_string ("construct_function");
115 string infix
= "construct";
117 if (name
== ".new") {
118 return "%s%s".printf (parent
.get_lower_case_cprefix (), infix
);
120 return "%s%s_%s".printf (parent
.get_lower_case_cprefix (), infix
, name
);
124 public override bool check (SemanticAnalyzer analyzer
) {
131 process_attributes ();
133 if (class_name
!= null && class_name
!= parent_symbol
.name
) {
134 // class_name is null for constructors generated by GIdlParser
135 Report
.error (source_reference
, "missing return type in method `%s.%s´".printf (analyzer
.current_symbol
.get_full_name (), class_name
));
140 var old_source_file
= analyzer
.current_source_file
;
141 var old_symbol
= analyzer
.current_symbol
;
143 if (source_reference
!= null) {
144 analyzer
.current_source_file
= source_reference
.file
;
146 analyzer
.current_symbol
= this
;
148 foreach (FormalParameter param
in get_parameters()) {
149 param
.check (analyzer
);
152 foreach (DataType error_type
in get_error_types ()) {
153 error_type
.check (analyzer
);
157 body
.check (analyzer
);
159 var cl
= parent_symbol as Class
;
161 // count construction property assignments
162 if (analyzer
.context
.profile
== Profile
.GOBJECT
&& cl
!= null
163 && cl
.is_subtype_of (analyzer
.object_type
)) {
165 foreach (Statement stmt
in body
.get_statements ()) {
166 var expr_stmt
= stmt as ExpressionStatement
;
167 if (expr_stmt
!= null) {
168 Property prop
= expr_stmt
.assigned_property ();
169 if (prop
!= null && prop
.set_accessor
.construction
) {
174 n_construction_params
= n_params
;
177 // ensure we chain up to base constructor
178 if (!chain_up
&& cl
!= null && cl
.base_class
!= null) {
179 if (cl
.base_class
.default_construction_method
!= null
180 && !cl
.base_class
.default_construction_method
.has_construct_function
) {
181 // chain up impossible
182 } else if (analyzer
.context
.profile
== Profile
.GOBJECT
183 && cl
.is_subtype_of (analyzer
.object_type
)
184 && (n_construction_params
> 0 || cl
.constructor
!= null)) {
185 // no chain up when using GObject construct properties or constructor
186 } else if (cl
.base_class
.default_construction_method
== null
187 || cl
.base_class
.default_construction_method
.access
== SymbolAccessibility
.PRIVATE
) {
188 Report
.warning (source_reference
, "unable to chain up to private base constructor");
189 } else if (cl
.base_class
.default_construction_method
.get_required_arguments () > 0) {
190 Report
.warning (source_reference
, "unable to chain up to base constructor requiring arguments");
192 var old_insert_block
= analyzer
.insert_block
;
193 analyzer
.current_symbol
= body
;
194 analyzer
.insert_block
= body
;
196 var stmt
= new
ExpressionStatement (new
MethodCall (new
BaseAccess (source_reference
), source_reference
), source_reference
);
197 body
.insert_statement (0, stmt
);
198 stmt
.check (analyzer
);
200 analyzer
.current_symbol
= this
;
201 analyzer
.insert_block
= old_insert_block
;
206 analyzer
.current_source_file
= old_source_file
;
207 analyzer
.current_symbol
= old_symbol
;
209 if (is_abstract
|| is_virtual
|| overrides
) {
210 Report
.error (source_reference
, "The creation method `%s' cannot be marked as override, virtual, or abstract".printf (get_full_name ()));
214 // check that all errors that can be thrown in the method body are declared
216 foreach (DataType body_error_type
in body
.get_error_types ()) {
217 bool can_propagate_error
= false;
218 foreach (DataType method_error_type
in get_error_types ()) {
219 if (body_error_type
.compatible (method_error_type
)) {
220 can_propagate_error
= true;
223 if (!can_propagate_error
&& !((ErrorType
) body_error_type
).dynamic_error
) {
224 Report
.warning (body_error_type
.source_reference
, "unhandled error `%s'".printf (body_error_type
.to_string()));