Line data Source code
1 : /* valapropertyaccessor.vala
2 : *
3 : * Copyright (C) 2006-2010 Jürg Billeter
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Lesser General Public
7 : * License as published by the Free Software Foundation; either
8 : * version 2.1 of the License, or (at your option) any later version.
9 :
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Lesser General Public License for more details.
14 :
15 : * You should have received a copy of the GNU Lesser General Public
16 : * License along with this library; if not, write to the Free Software
17 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 : *
19 : * Author:
20 : * Jürg Billeter <j@bitron.ch>
21 : */
22 :
23 : using GLib;
24 :
25 : /**
26 : * Represents a get or set accessor of a property in the source code.
27 : */
28 758341 : public class Vala.PropertyAccessor : Subroutine {
29 : /**
30 : * The corresponding property.
31 : */
32 : public Property prop {
33 5125838 : get { return parent_symbol as Property; }
34 : }
35 :
36 : /**
37 : * The property type.
38 : */
39 : public DataType? value_type {
40 3588561 : get { return _value_type; }
41 1434193 : private set {
42 2451190 : _value_type = value;
43 1434193 : if (value != null) {
44 1434189 : _value_type.parent_node = this;
45 : }
46 : }
47 : }
48 :
49 : /**
50 : * Specifies whether this accessor may be used to get the property.
51 : */
52 801225 : public bool readable { get; private set; }
53 :
54 : /**
55 : * Specifies whether this accessor may be used to set the property.
56 : */
57 767852 : public bool writable { get; private set; }
58 :
59 : /**
60 : * Specifies whether this accessor may be used to construct the
61 : * property.
62 : */
63 1073781 : public bool construction { get; private set; }
64 :
65 : /**
66 : * True if the body was automatically generated
67 : */
68 13546 : public bool automatic_body { get; private set; }
69 :
70 : public override bool has_result {
71 477 : get { return readable; }
72 : }
73 :
74 : /**
75 : * Represents the generated value parameter in a set accessor.
76 : */
77 1383615 : public Parameter value_parameter { get; private set; }
78 :
79 756803 : private DataType _value_type;
80 :
81 : /**
82 : * Creates a new property accessor.
83 : *
84 : * @param readable true if get accessor, false otherwise
85 : * @param writable true if set accessor, false otherwise
86 : * @param construction true if construct accessor, false otherwise
87 : * @param body accessor body
88 : * @param source_reference reference to source code
89 : * @return newly created property accessor
90 : */
91 756803 : public PropertyAccessor (bool readable, bool writable, bool construction, DataType? value_type, Block? body, SourceReference? source_reference = null, Comment? comment = null) {
92 756803 : base (null, source_reference, comment);
93 756803 : this.readable = readable;
94 756803 : this.writable = writable;
95 756803 : this.construction = construction;
96 756803 : this.value_type = value_type;
97 756803 : this.body = body;
98 756803 : this.access = SymbolAccessibility.PUBLIC;
99 : }
100 :
101 1199588 : public override void accept (CodeVisitor visitor) {
102 1199588 : visitor.visit_property_accessor (this);
103 : }
104 :
105 712337 : public override void accept_children (CodeVisitor visitor) {
106 712337 : value_type.accept (visitor);
107 :
108 712337 : if (result_var != null) {
109 0 : result_var.accept (visitor);
110 : }
111 :
112 712337 : if (body != null) {
113 10841 : body.accept (visitor);
114 : }
115 : }
116 :
117 : /**
118 : * Get the method representing this property accessor
119 : * @return null if the accessor is neither readable nor writable
120 : */
121 215 : public Method? get_method () {
122 215 : Method? m = null;
123 215 : if (readable) {
124 178 : m = new Method ("get_%s".printf (prop.name), value_type, source_reference, comment);
125 :
126 : // Inherit important attributes
127 178 : m.copy_attribute_bool (prop, "CCode", "array_length");
128 178 : m.copy_attribute_string (prop, "CCode", "array_length_type");
129 178 : m.copy_attribute_bool (prop, "CCode", "array_null_terminated");
130 178 : m.copy_attribute_bool (prop, "CCode", "delegate_target");
131 37 : } else if (writable || construction) {
132 37 : m = new Method ("set_%s".printf (prop.name), new VoidType(), source_reference, comment);
133 37 : m.add_parameter (value_parameter.copy ());
134 : }
135 :
136 215 : if (m != null) {
137 215 : m.owner = prop.owner;
138 215 : m.access = access;
139 215 : m.binding = prop.binding;
140 215 : m.is_abstract = prop.is_abstract;
141 215 : m.is_virtual = prop.is_virtual;
142 215 : m.this_parameter = prop.this_parameter;
143 :
144 : // Inherit important attributes
145 215 : m.copy_attribute_bool (prop, "GIR", "visible");
146 : }
147 :
148 : return m;
149 : }
150 :
151 704633 : public override bool check (CodeContext context) {
152 704633 : if (checked) {
153 0 : return !error;
154 : }
155 :
156 704633 : checked = true;
157 :
158 704633 : if (!value_type.check (context)) {
159 4 : error = true;
160 4 : return false;
161 : }
162 :
163 704629 : var old_symbol = context.analyzer.current_symbol;
164 :
165 704629 : context.analyzer.current_symbol = this;
166 :
167 704629 : if (writable || construction) {
168 312368 : value_parameter = new Parameter ("value", value_type, source_reference);
169 : // Inherit important attributes
170 312368 : value_parameter.copy_attribute_bool (prop, "CCode", "array_length");
171 312368 : value_parameter.copy_attribute_string (prop, "CCode", "array_length_type");
172 312368 : value_parameter.copy_attribute_bool (prop, "CCode", "array_null_terminated");
173 312368 : value_parameter.copy_attribute_bool (prop, "CCode", "delegate_target");
174 : }
175 :
176 1096882 : if (context.profile == Profile.GOBJECT
177 704621 : && readable && ((TypeSymbol) prop.parent_symbol).is_subtype_of (context.analyzer.object_type)) {
178 : //FIXME Code duplication with CCodeMemberAccessModule.visit_member_access()
179 375158 : if (prop.has_attribute ("NoAccessorMethod")) {
180 120916 : if (value_type.is_real_struct_type ()) {
181 388 : if (source_reference == null || source_reference.file == null) {
182 : // Hopefully good as is
183 380 : } else if (!value_type.value_owned && source_reference.file.file_type == SourceFileType.SOURCE) {
184 1 : error = true;
185 1 : Report.error (source_reference, "unowned return value for getter of property `%s' not supported without accessor", prop.get_full_name ());
186 : }
187 120528 : } else if (value_type.value_owned && (source_reference == null || source_reference.file == null)) {
188 785 : if (value_type is DelegateType || value_type is PointerType || (value_type is ValueType && !value_type.nullable)) {
189 592 : value_type.value_owned = false;
190 : }
191 : }
192 : }
193 : }
194 :
195 704629 : if (prop.source_type == SourceFileType.SOURCE) {
196 2213 : if (body == null && !prop.interface_only && !prop.is_abstract) {
197 : /* no accessor body specified, insert default body */
198 :
199 958 : automatic_body = true;
200 958 : body = new Block (source_reference);
201 958 : var ma = new MemberAccess.simple ("_%s".printf (prop.name), source_reference);
202 1437 : if (readable) {
203 479 : body.add_statement (new ReturnStatement (ma, source_reference));
204 : } else {
205 479 : Expression value = new MemberAccess.simple ("value", source_reference);
206 479 : if (value_type.value_owned) {
207 11 : value = new ReferenceTransferExpression (value, source_reference);
208 : }
209 479 : var assignment = new Assignment (ma, value, AssignmentOperator.SIMPLE, source_reference);
210 479 : body.add_statement (new ExpressionStatement (assignment));
211 : }
212 : }
213 : }
214 :
215 704629 : if ((prop.is_abstract || prop.is_virtual || prop.overrides) && access == SymbolAccessibility.PRIVATE) {
216 2 : error = true;
217 2 : Report.error (source_reference, "Property `%s' with private accessor cannot be marked as abstract, virtual or override", prop.get_full_name ());
218 2 : return false;
219 : }
220 :
221 704627 : if (value_type.value_owned && value_type.is_non_null_simple_type ()) {
222 2 : error = true;
223 2 : Report.error (source_reference, "`owned' accessor not allowed for specified property type");
224 2 : return false;
225 : }
226 :
227 704625 : if (context.profile == Profile.POSIX && construction) {
228 0 : error = true;
229 0 : Report.error (source_reference, "`construct' is not supported in POSIX profile");
230 0 : return false;
231 704625 : } else if (construction && !((TypeSymbol) prop.parent_symbol).is_subtype_of (context.analyzer.object_type)) {
232 2 : error = true;
233 2 : Report.error (source_reference, "construct properties require `GLib.Object'");
234 2 : return false;
235 704623 : } else if (construction && !context.analyzer.is_gobject_property (prop)) {
236 : //TODO Report an error for external property too
237 2 : if (external_package) {
238 0 : Report.warning (source_reference, "construct properties not supported for specified property type");
239 : } else {
240 2 : error = true;
241 2 : Report.error (source_reference, "construct properties not supported for specified property type");
242 2 : return false;
243 : }
244 : }
245 :
246 704621 : if (body != null && prop.is_abstract) {
247 1 : error = true;
248 1 : Report.error (source_reference, "Accessor of abstract property `%s' cannot have body", prop.get_full_name ());
249 1 : return false;
250 : }
251 :
252 704620 : if (body != null) {
253 6821 : if (writable || construction) {
254 510 : body.scope.add (value_parameter.name, value_parameter);
255 : }
256 :
257 6821 : body.check (context);
258 : }
259 :
260 711437 : if (body != null && !body.error) {
261 6817 : var error_types = new ArrayList<DataType> ();
262 6817 : body.get_error_types (error_types);
263 6821 : foreach (DataType body_error_type in error_types) {
264 2 : if (!((ErrorType) body_error_type).dynamic_error) {
265 2 : Report.warning (body_error_type.source_reference, "unhandled error `%s'", body_error_type.to_string ());
266 : }
267 : }
268 : }
269 :
270 704620 : context.analyzer.current_symbol = old_symbol;
271 :
272 704620 : return !error;
273 : }
274 :
275 677390 : public override void replace_type (DataType old_type, DataType new_type) {
276 677390 : if (value_type == old_type) {
277 677390 : value_type = new_type;
278 : }
279 : }
280 : }
|