Use strict non-null types with --enable-experimental-non-null
[vala-lang.git] / vala / valacreationmethod.vala
blob8469e1778240e5340861c250d1eba0a86a75a02d
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
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 the number of parameters this creation method sets.
39 public int n_construction_params { get; set; }
41 /**
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
45 * handling.
47 public string? custom_return_type_cname { get; set; }
49 /**
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; }
55 /**
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);
83 if (body != null) {
84 body.accept (visitor);
88 public override string get_default_cname () {
89 var parent = parent_symbol as TypeSymbol;
91 string infix = "new";
92 if (parent is Struct) {
93 infix = "init";
96 if (name == ".new") {
97 return "%s%s".printf (parent.get_lower_case_cprefix (), infix);
98 } else {
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) {
107 return get_cname ();
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);
119 } else {
120 return "%s%s_%s".printf (parent.get_lower_case_cprefix (), infix, name);
124 public override bool check (SemanticAnalyzer analyzer) {
125 if (checked) {
126 return !error;
129 checked = true;
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));
136 error = true;
137 return false;
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);
156 if (body != null) {
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)) {
164 int n_params = 0;
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) {
170 n_params++;
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");
191 } else {
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 ()));
211 return false;
214 // check that all errors that can be thrown in the method body are declared
215 if (body != null) {
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()));
229 return !error;