3 * Copyright (C) 2006-2009 Jürg Billeter
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.
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.
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
20 * Jürg Billeter <j@bitron.ch>
21 * Raffaele Sandrini <raffaele@sandrini.ch>
27 * Represents a property declaration in the source code.
29 public class Vala
.Property
: Member
, Lockable
{
33 public DataType? property_type
{
34 get { return _data_type
; }
38 _data_type
.parent_node
= this
;
44 * The get accessor of this property if available.
46 public PropertyAccessor? get_accessor
{
47 get { return _get_accessor
; }
49 _get_accessor
= value
;
57 * The set/construct accessor of this property if available.
59 public PropertyAccessor? set_accessor
{
60 get { return _set_accessor
; }
62 _set_accessor
= value
;
70 * Represents the generated `this` parameter in this property.
72 public FormalParameter this_parameter
{ get; set; }
75 * Specifies whether a `notify` signal should be emitted on property
78 public bool notify
{ get; set; default = true; }
81 * Specifies whether the implementation of this property does not
82 * provide getter/setter methods.
84 public bool no_accessor_method
{ get; set; }
87 * Specifies whether automatic accessor code generation should be
90 public bool interface_only
{ get; set; }
93 * Specifies whether this property is abstract. Abstract properties have
94 * no accessor bodies, may only be specified within abstract classes and
95 * interfaces, and must be overriden by derived non-abstract classes.
97 public bool is_abstract
{ get; set; }
100 * Specifies whether this property is virtual. Virtual properties may be
101 * overridden by derived classes.
103 public bool is_virtual
{ get; set; }
106 * Specifies whether this property overrides a virtual or abstract
107 * property of a base type.
109 public bool overrides
{ get; set; }
112 * Reference the the Field that holds this property
114 public Field field
{ get; set; }
117 * Specifies whether this field may only be accessed with an instance of
118 * the contained type.
120 public MemberBinding binding
{ get; set; default = MemberBinding
.INSTANCE
; }
123 * Specifies the virtual or abstract property this property overrides.
124 * Reference must be weak as virtual properties set base_property to
127 public Property base_property
{
129 find_base_properties ();
130 return _base_property
;
135 * Specifies the abstract interface property this property implements.
137 public Property base_interface_property
{
139 find_base_properties ();
140 return _base_interface_property
;
145 * Specifies the default value of this property.
147 public Expression default_expression
{ get; set; }
149 public bool no_array_length
{ get; set; }
151 public bool array_null_terminated
{ get; set; }
154 * Nickname of this property.
159 _nick
= get_canonical_name ();
163 set { _nick
= value
; }
167 * The long description of this property.
169 public string blurb
{
171 if (_blurb
== null) {
172 _blurb
= get_canonical_name ();
176 set { _blurb
= value
; }
179 private bool lock_used
= false;
181 private DataType _data_type
;
183 private string? _nick
;
184 private string? _blurb
;
186 private weak Property _base_property
;
187 private Property _base_interface_property
;
188 private bool base_properties_valid
;
189 PropertyAccessor? _get_accessor
;
190 PropertyAccessor? _set_accessor
;
193 * Creates a new property.
195 * @param name property name
196 * @param type property type
197 * @param get_accessor get accessor
198 * @param set_accessor set/construct accessor
199 * @param source reference to source code
200 * @return newly created property
202 public Property (string name
, DataType? property_type
, PropertyAccessor? get_accessor
, PropertyAccessor? set_accessor
, SourceReference? source_reference
= null, Comment? comment
= null) {
203 base (name
, source_reference
, comment
);
204 this
.property_type
= property_type
;
205 this
.get_accessor
= get_accessor
;
206 this
.set_accessor
= set_accessor
;
209 public override void accept (CodeVisitor visitor
) {
210 visitor
.visit_member (this
);
212 visitor
.visit_property (this
);
215 public override void accept_children (CodeVisitor visitor
) {
216 property_type
.accept (visitor
);
218 if (get_accessor
!= null) {
219 get_accessor
.accept (visitor
);
221 if (set_accessor
!= null) {
222 set_accessor
.accept (visitor
);
225 if (default_expression
!= null) {
226 default_expression
.accept (visitor
);
231 * Returns the C name of this property in upper case. Words are
232 * separated by underscores. The upper case C name of the class is
233 * prefix of the result.
235 * @return the upper case name to be used in C code
237 public string get_upper_case_cname () {
238 return "%s_%s".printf (parent_symbol
.get_lower_case_cname (null), camel_case_to_lower_case (name
)).up ();
242 * Returns the string literal of this property to be used in C code.
244 * @return string literal to be used in C code
246 public CCodeConstant
get_canonical_cconstant () {
247 return new
CCodeConstant ("\"%s\"".printf (get_canonical_name ()));
250 public string get_canonical_name () {
251 var str
= new
StringBuilder ();
255 while (i
.len () > 0) {
256 unichar c
= i
.get_char ();
260 str
.append_unichar (c
);
269 void process_ccode_attribute (Attribute a
) {
270 if (a
.has_argument ("notify")) {
271 notify
= a
.get_bool ("notify");
273 if (a
.has_argument ("array_length")) {
274 no_array_length
= !a
.get_bool ("array_length");
276 if (a
.has_argument ("array_null_terminated")) {
277 array_null_terminated
= a
.get_bool ("array_null_terminated");
282 * Process all associated attributes.
284 public void process_attributes () {
285 foreach (Attribute a
in attributes
) {
286 if (a
.name
== "CCode") {
287 process_ccode_attribute (a
);
288 } else if (a
.name
== "NoAccessorMethod") {
289 no_accessor_method
= true;
290 } else if (a
.name
== "Description") {
291 if (a
.has_argument ("nick")) {
292 nick
= a
.get_string ("nick");
294 if (a
.has_argument ("blurb")) {
295 blurb
= a
.get_string ("blurb");
301 public bool get_lock_used () {
305 public void set_lock_used (bool used
) {
310 * Checks whether the accessors and type of the specified property
311 * matches this property.
313 * @param prop a property
314 * @return true if the specified property is compatible to this
317 public bool equals (Property prop2
) {
318 if ((get_accessor
== null && prop2
.get_accessor
!= null) ||
319 (get_accessor
!= null && prop2
.get_accessor
== null)) {
323 if ((set_accessor
== null && prop2
.set_accessor
!= null) ||
324 (set_accessor
!= null && prop2
.set_accessor
== null)) {
328 if (get_accessor
!= null) {
329 // check accessor value_type instead of property_type
330 // due to possible ownership differences
331 if (!prop2
.get_accessor
.value_type
.equals (get_accessor
.value_type
)) {
336 if (set_accessor
!= null) {
337 // check accessor value_type instead of property_type
338 // due to possible ownership differences
339 if (!prop2
.set_accessor
.value_type
.equals (set_accessor
.value_type
)) {
343 if (set_accessor
.writable
!= prop2
.set_accessor
.writable
) {
346 if (set_accessor
.construction
!= prop2
.set_accessor
.construction
) {
354 public override void replace_type (DataType old_type
, DataType new_type
) {
355 if (property_type
== old_type
) {
356 property_type
= new_type
;
360 private void find_base_properties () {
361 if (base_properties_valid
) {
365 if (parent_symbol is Class
) {
366 find_base_interface_property ((Class
) parent_symbol
);
367 if (is_virtual
|| overrides
) {
368 find_base_class_property ((Class
) parent_symbol
);
370 } else if (parent_symbol is Interface
) {
371 if (is_virtual
|| is_abstract
) {
372 _base_interface_property
= this
;
376 base_properties_valid
= true;
379 private void find_base_class_property (Class cl
) {
380 var sym
= cl
.scope
.lookup (name
);
381 if (sym is Property
) {
382 var base_property
= (Property
) sym
;
383 if (base_property
.is_abstract
|| base_property
.is_virtual
) {
384 if (!equals (base_property
)) {
386 Report
.error (source_reference
, "Type and/or accessors of overriding property `%s' do not match overridden property `%s'.".printf (get_full_name (), base_property
.get_full_name ()));
390 _base_property
= base_property
;
395 if (cl
.base_class
!= null) {
396 find_base_class_property (cl
.base_class
);
400 private void find_base_interface_property (Class cl
) {
401 // FIXME report error if multiple possible base properties are found
402 foreach (DataType type
in cl
.get_base_types ()) {
403 if (type
.data_type is Interface
) {
404 var sym
= type
.data_type
.scope
.lookup (name
);
405 if (sym is Property
) {
406 var base_property
= (Property
) sym
;
407 if (base_property
.is_abstract
) {
408 if (!equals (base_property
)) {
410 Report
.error (source_reference
, "Type and/or accessors of overriding property `%s' do not match overridden property `%s'.".printf (get_full_name (), base_property
.get_full_name ()));
414 _base_interface_property
= base_property
;
422 public override bool check (SemanticAnalyzer analyzer
) {
429 process_attributes ();
431 var old_source_file
= analyzer
.current_source_file
;
432 var old_symbol
= analyzer
.current_symbol
;
434 if (source_reference
!= null) {
435 analyzer
.current_source_file
= source_reference
.file
;
437 analyzer
.current_symbol
= this
;
439 property_type
.check (analyzer
);
441 if (get_accessor
!= null) {
442 get_accessor
.check (analyzer
);
444 if (set_accessor
!= null) {
445 set_accessor
.check (analyzer
);
448 if (default_expression
!= null) {
449 default_expression
.check (analyzer
);
452 // check whether property type is at least as accessible as the property
453 if (!analyzer
.is_type_accessible (this
, property_type
)) {
455 Report
.error (source_reference
, "property type `%s` is less accessible than property `%s`".printf (property_type
.to_string (), get_full_name ()));
458 if (overrides
&& base_property
== null) {
459 Report
.error (source_reference
, "%s: no suitable property found to override".printf (get_full_name ()));
462 if (!external_package
&& !overrides
&& !hides
&& get_hidden_member () != null) {
463 Report
.warning (source_reference
, "%s hides inherited property `%s'. Use the `new' keyword if hiding was intentional".printf (get_full_name (), get_hidden_member ().get_full_name ()));
466 /* construct properties must be public */
467 if (set_accessor
!= null && set_accessor
.construction
) {
468 if (access
!= SymbolAccessibility
.PUBLIC
) {
470 Report
.error (source_reference
, "%s: construct properties must be public".printf (get_full_name ()));
474 if (default_expression
!= null && !default_expression
.error
&& !(default_expression
.value_type
.compatible (property_type
))) {
476 Report
.error (default_expression
.source_reference
, "Expected initializer of type `%s' but got `%s'".printf (property_type
.to_string (), default_expression
.value_type
.to_string ()));
479 analyzer
.current_source_file
= old_source_file
;
480 analyzer
.current_symbol
= old_symbol
;