Line data Source code
1 : /* valaparameter.vala
2 : *
3 : * Copyright (C) 2006-2012 Jürg Billeter
4 : * Copyright (C) 2006-2008 Raffaele Sandrini
5 : *
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.
10 :
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.
15 :
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
19 : *
20 : * Author:
21 : * Jürg Billeter <j@bitron.ch>
22 : * Raffaele Sandrini <raffaele@sandrini.ch>
23 : */
24 :
25 : using GLib;
26 :
27 : /**
28 : * Represents a formal parameter in method and callback signatures.
29 : */
30 14950475 : public class Vala.Parameter : Variable {
31 11268044 : public ParameterDirection direction { get; set; default = ParameterDirection.IN; }
32 :
33 : /**
34 : * Specifies whether the methods accepts an indefinite number of
35 : * parameters.
36 : */
37 17146725 : public bool ellipsis { get; set; }
38 :
39 : /**
40 : * Specifies whether the methods accepts an indefinite number of
41 : * parameters.
42 : */
43 45336202 : public bool params_array { get; set; }
44 :
45 77087 : public bool captured { get; set; }
46 :
47 : public bool format_arg {
48 39252 : get {
49 39252 : return has_attribute ("FormatArg");
50 : }
51 : }
52 :
53 : /**
54 : * The base parameter of this parameter relative to the base method.
55 : */
56 28534532 : public Parameter base_parameter { get; set; }
57 :
58 : /**
59 : * Creates a new formal parameter.
60 : *
61 : * @param name parameter name
62 : * @param variable_type parameter type
63 : * @param source_reference reference to source code
64 : * @return newly created formal parameter
65 : */
66 44466732 : public Parameter (string name, DataType? variable_type, SourceReference? source_reference = null) {
67 14822244 : base (variable_type, name, null, source_reference);
68 :
69 14822244 : access = SymbolAccessibility.PUBLIC;
70 : }
71 :
72 : /**
73 : * Creates a new ellipsis parameter representing an indefinite number of
74 : * parameters.
75 : */
76 126695 : public Parameter.with_ellipsis (SourceReference? source_reference = null) {
77 126695 : base (null, null, null, source_reference);
78 126695 : ellipsis = true;
79 :
80 126695 : access = SymbolAccessibility.PUBLIC;
81 : }
82 :
83 14265070 : public override void accept (CodeVisitor visitor) {
84 14265070 : visitor.visit_formal_parameter (this);
85 : }
86 :
87 15424953 : public override void accept_children (CodeVisitor visitor) {
88 15424953 : if (!ellipsis) {
89 15201361 : variable_type.accept (visitor);
90 :
91 15201361 : if (initializer != null) {
92 1932012 : initializer.accept (visitor);
93 : }
94 : }
95 : }
96 :
97 7606324 : public override void replace_type (DataType old_type, DataType new_type) {
98 7606324 : if (variable_type == old_type) {
99 7606324 : variable_type = new_type;
100 : }
101 : }
102 :
103 0 : public override void replace_expression (Expression old_node, Expression new_node) {
104 0 : if (initializer == old_node) {
105 0 : initializer = new_node;
106 : }
107 : }
108 :
109 161 : public Parameter copy () {
110 161 : if (!ellipsis) {
111 161 : var result = new Parameter (name, variable_type.copy (), source_reference);
112 161 : result.params_array = params_array;
113 161 : result.direction = this.direction;
114 161 : result.initializer = this.initializer;
115 :
116 : // cannot use List.copy()
117 : // as it returns a list of unowned elements
118 221 : foreach (Attribute a in this.attributes) {
119 60 : result.attributes.append (a);
120 : }
121 :
122 161 : return result;
123 : } else {
124 0 : return new Parameter.with_ellipsis ();
125 : }
126 : }
127 :
128 14458829 : public override bool check (CodeContext context) {
129 14458829 : if (checked) {
130 948636 : return !error;
131 : }
132 :
133 13510193 : checked = true;
134 :
135 13510193 : var old_source_file = context.analyzer.current_source_file;
136 13510193 : var old_symbol = context.analyzer.current_symbol;
137 :
138 13510193 : if (source_reference != null) {
139 13510052 : context.analyzer.current_source_file = source_reference.file;
140 : }
141 13510193 : context.analyzer.current_symbol = parent_symbol;
142 :
143 13510193 : if (variable_type != null) {
144 13392848 : if (variable_type is VoidType) {
145 1 : error = true;
146 1 : Report.error (source_reference, "'void' not supported as parameter type");
147 1 : return false;
148 : }
149 13392847 : variable_type.check (context);
150 : }
151 :
152 13510192 : if (!ellipsis) {
153 13392823 : variable_type.check (context);
154 :
155 13392823 : if (params_array) {
156 2909 : if (!(variable_type is ArrayType)) {
157 1 : error = true;
158 1 : Report.error (source_reference, "parameter array expected");
159 1 : return false;
160 2908 : } else if (((ArrayType) variable_type).rank != 1) {
161 1 : error = true;
162 1 : Report.error (source_reference, "multi-dimensional parameter array not allowed");
163 1 : return false;
164 : }
165 : }
166 :
167 13402998 : if (has_attribute_argument ("CCode", "scope") && variable_type is DelegateType) {
168 10177 : var delegate_type = (DelegateType) variable_type;
169 10177 : delegate_type.is_called_once = get_attribute_string ("CCode", "scope") == "async";
170 : }
171 :
172 13392821 : if (initializer != null) {
173 1009561 : initializer.target_type = variable_type.copy ();
174 1009561 : initializer.check (context);
175 1009561 : if (initializer.value_type == null) {
176 1 : initializer.value_type = new InvalidType ();
177 : }
178 : }
179 :
180 13392821 : unowned ArrayType? variable_array_type = variable_type as ArrayType;
181 328538 : if (variable_array_type != null && variable_array_type.inline_allocated
182 50 : && !variable_array_type.fixed_length) {
183 2 : error = true;
184 2 : Report.error (source_reference, "Inline allocated array as parameter requires to have fixed length");
185 : }
186 : }
187 :
188 13510190 : if (initializer != null && !initializer.error) {
189 1009560 : if (initializer is NullLiteral
190 690734 : && !variable_type.nullable
191 114685 : && direction != ParameterDirection.OUT) {
192 1 : Report.warning (source_reference, "`null' incompatible with parameter type `%s'", variable_type.to_string ());
193 1009559 : } else if (!(initializer is NullLiteral) && direction == ParameterDirection.OUT) {
194 1 : error = true;
195 1 : Report.error (source_reference, "only `null' is allowed as default value for out parameters");
196 1009558 : } else if (direction == ParameterDirection.IN && !initializer.value_type.compatible (variable_type)) {
197 2 : error = true;
198 2 : Report.error (initializer.source_reference, "Cannot convert from `%s' to `%s'", initializer.value_type.to_string (), variable_type.to_string ());
199 1009556 : } else if (direction == ParameterDirection.REF) {
200 1 : error = true;
201 1 : Report.error (source_reference, "default value not allowed for ref parameter");
202 1009555 : } else if (!initializer.is_accessible (this)) {
203 1 : error = true;
204 1 : Report.error (initializer.source_reference, "default value is less accessible than method `%s'", parent_symbol.get_full_name ());
205 : }
206 : }
207 :
208 13510190 : if (!ellipsis) {
209 13392821 : if (!external_package) {
210 10422 : context.analyzer.check_type (variable_type);
211 10422 : variable_type.check_type_arguments (context, !(variable_type is DelegateType));
212 :
213 : // check symbol availability
214 10422 : if ((parent_symbol == null || !parent_symbol.external_package) && variable_type.type_symbol != null) {
215 10088 : variable_type.type_symbol.version.check (context, source_reference);
216 : }
217 : }
218 :
219 : // check whether parameter type is at least as accessible as the method
220 13392821 : if (!variable_type.is_accessible (this)) {
221 1 : error = true;
222 1 : Report.error (source_reference, "parameter type `%s' is less accessible than method `%s'", variable_type.to_string (), parent_symbol.get_full_name ());
223 : }
224 : }
225 :
226 13510190 : unowned Method? m = parent_symbol as Method;
227 12557706 : if (m != null) {
228 12557706 : unowned Method? base_method = null;
229 12557706 : if (m.base_method != null && m.base_method != m) {
230 27036 : base_method = m.base_method;
231 12530670 : } else if (m.base_interface_method != null && m.base_interface_method != m) {
232 29493 : base_method = m.base_interface_method;
233 : }
234 56529 : if (base_method != null) {
235 56529 : int index = m.get_parameters ().index_of (this);
236 56529 : if (index >= 0) {
237 26368 : base_parameter = base_method.get_parameters ().get (index);
238 : }
239 : }
240 : }
241 :
242 13510190 : context.analyzer.current_source_file = old_source_file;
243 13510190 : context.analyzer.current_symbol = old_symbol;
244 :
245 13510190 : return !error;
246 : }
247 : }
248 :
249 : public enum Vala.ParameterDirection {
250 : IN,
251 : OUT,
252 : REF
253 : }
254 :
|