girparser: Provide default constructor for classes.
[vala-lang.git] / vala / valacreationmethod.vala
blob7958ec65b9f564c2af2c00dc3560c640411e1d7b
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
20 * Author:
21 * Raffaele Sandrini <raffaele@sandrini.ch>
22 * Jürg Billeter <j@bitron.ch>
25 using GLib;
27 /**
28 * Represents a type creation method.
30 public class Vala.CreationMethod : Method {
31 /**
32 * Specifies the name of the type this creation method belongs to.
34 public string class_name { get; set; }
36 /**
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
40 * handling.
42 public string? custom_return_type_cname { get; set; }
44 /**
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; }
50 /**
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);
86 if (body != null) {
87 body.accept (visitor);
91 public override string get_default_cname () {
92 var parent = parent_symbol as TypeSymbol;
94 string infix = "new";
95 var st = parent as Struct;
96 if (st != null) {
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 ();
102 } else {
103 return "%s%s".printf (parent.get_lower_case_cprefix (), name);
107 infix = "init";
110 if (name == ".new") {
111 return "%s%s".printf (parent.get_lower_case_cprefix (), infix);
112 } else {
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) {
130 return get_cname ();
133 string infix = "construct";
135 if (CodeContext.get ().profile == Profile.DOVA) {
136 infix = "init";
139 if (name == ".new") {
140 return "%s%s".printf (parent.get_lower_case_cprefix (), infix);
141 } else {
142 return "%s%s_%s".printf (parent.get_lower_case_cprefix (), infix, name);
146 public override bool check (CodeContext context) {
147 if (checked) {
148 return !error;
151 checked = true;
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));
158 error = true;
159 return false;
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);
186 if (body != null) {
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");
212 } else {
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 ()));
232 return false;
235 // check that all errors that can be thrown in the method body are declared
236 if (body != null) {
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()));
250 return !error;