girparser: Guess virtual method wrapper variant when possible
[vala-lang.git] / vala / valafield.vala
blob6bf48686a9443fba218e0a8847037ed0993e789b
1 /* valafield.vala
3 * Copyright (C) 2006-2010 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
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
25 /**
26 * Represents a type or namespace field.
28 public class Vala.Field : Variable, Lockable {
29 /**
30 * Specifies whether this field may only be accessed with an instance of
31 * the contained type.
33 public MemberBinding binding { get; set; default = MemberBinding.INSTANCE; }
35 /**
36 * Specifies whether the field is volatile. Volatile fields are
37 * necessary to allow multi-threaded access.
39 public bool is_volatile { get; set; }
41 /**
42 * Specifies whether an array length field should implicitly be created
43 * if the field type is an array.
45 public bool no_array_length { get; set; }
47 /**
48 * Specifies whether a delegate target field should implicitly be created
49 * if the field type is a delegate.
51 public bool no_delegate_target { get; set; }
53 /**
54 * Specifies whether the array is null terminated.
56 public bool array_null_terminated { get; set; }
58 /**
59 * Specifies whether the array length field uses a custom name in C.
61 public bool has_array_length_cname {
62 get { return (array_length_cname != null); }
65 /**
66 * Specifies whether the array uses a custom C expression as length.
68 public bool has_array_length_cexpr {
69 get { return (array_length_cexpr != null); }
72 /**
73 * Specifies a custom type for the array length.
75 public string? array_length_type { get; set; default = null; }
77 private string? array_length_cname;
79 private string? array_length_cexpr;
81 private string cname;
83 private bool lock_used = false;
85 /**
86 * Creates a new field.
88 * @param name field name
89 * @param type field type
90 * @param init initializer expression
91 * @param source reference to source code
92 * @return newly created field
94 public Field (string name, DataType variable_type, Expression? initializer, SourceReference? source_reference = null, Comment? comment = null) {
95 base (variable_type, name, initializer, source_reference, comment);
98 public override void accept (CodeVisitor visitor) {
99 visitor.visit_field (this);
102 public override void accept_children (CodeVisitor visitor) {
103 variable_type.accept (visitor);
105 if (initializer != null) {
106 initializer.accept (visitor);
111 * Returns the name of this field as it is used in C code.
113 * @return the name to be used in C code
115 public string get_cname () {
116 if (cname == null) {
117 cname = get_default_cname ();
119 return cname;
123 * Sets the name of this field as it is used in C code.
125 * @param cname the name to be used in C code
127 public void set_cname (string cname) {
128 this.cname = cname;
132 * Returns the default name of this field as it is used in C code.
134 * @return the name to be used in C code by default
136 public string get_default_cname () {
137 if (binding == MemberBinding.STATIC) {
138 return parent_symbol.get_lower_case_cprefix () + name;
139 } else {
140 return name;
145 * Returns the name of the array length field as it is used in C code
147 * @return the name of the array length field to be used in C code
149 public string? get_array_length_cname () {
150 return this.array_length_cname;
154 * Sets the name of the array length field as it is used in C code
156 * @param array_length_cname the name of the array length field to be
157 * used in C code
159 public void set_array_length_cname (string? array_length_cname) {
160 this.array_length_cname = array_length_cname;
164 * Returns the array length expression as it is used in C code
166 * @return the array length expression to be used in C code
168 public string? get_array_length_cexpr () {
169 return this.array_length_cexpr;
174 * Sets the array length expression as it is used in C code
176 * @param array_length_cexpr the array length expression to be used in C
177 * code
179 public void set_array_length_cexpr (string? array_length_cexpr) {
180 this.array_length_cexpr = array_length_cexpr;
183 private void process_ccode_attribute (Attribute a) {
184 if (a.has_argument ("cname")) {
185 set_cname (a.get_string ("cname"));
187 if (a.has_argument ("cheader_filename")) {
188 var val = a.get_string ("cheader_filename");
189 foreach (string filename in val.split (",")) {
190 add_cheader_filename (filename);
193 if (a.has_argument ("array_length")) {
194 no_array_length = !a.get_bool ("array_length");
196 if (a.has_argument ("array_null_terminated")) {
197 array_null_terminated = a.get_bool ("array_null_terminated");
199 if (a.has_argument ("array_length_cname")) {
200 set_array_length_cname (a.get_string ("array_length_cname"));
202 if (a.has_argument ("array_length_cexpr")) {
203 set_array_length_cexpr (a.get_string ("array_length_cexpr"));
205 if (a.has_argument ("array_length_type")) {
206 array_length_type = a.get_string ("array_length_type");
208 if (a.has_argument ("delegate_target")) {
209 no_delegate_target = !a.get_bool ("delegate_target");
214 * Process all associated attributes.
216 public void process_attributes () {
217 foreach (Attribute a in attributes) {
218 if (a.name == "CCode") {
219 process_ccode_attribute (a);
220 } else if (a.name == "Deprecated") {
221 process_deprecated_attribute (a);
226 public bool get_lock_used () {
227 return lock_used;
230 public void set_lock_used (bool used) {
231 lock_used = used;
234 public override void replace_expression (Expression old_node, Expression new_node) {
235 if (initializer == old_node) {
236 initializer = new_node;
240 public override void replace_type (DataType old_type, DataType new_type) {
241 if (variable_type == old_type) {
242 variable_type = new_type;
246 public string? get_ctype () {
247 var attr = get_attribute ("CCode");
248 if (attr == null) {
249 return null;
251 return attr.get_string ("type");
254 public void set_ctype (string ctype) {
255 var attr = get_attribute ("CCode");
256 if (attr == null) {
257 attr = new Attribute ("CCode");
258 attributes.append (attr);
260 attr.add_argument ("type", "\"%s\"".printf (ctype));
263 public override bool check (CodeContext context) {
264 if (checked) {
265 return !error;
268 checked = true;
270 var old_source_file = context.analyzer.current_source_file;
271 var old_symbol = context.analyzer.current_symbol;
273 if (source_reference != null) {
274 context.analyzer.current_source_file = source_reference.file;
276 context.analyzer.current_symbol = this;
278 if (variable_type is VoidType) {
279 error = true;
280 Report.error (source_reference, "'void' not supported as field type");
281 return false;
284 variable_type.check (context);
286 // check whether field type is at least as accessible as the field
287 if (!context.analyzer.is_type_accessible (this, variable_type)) {
288 error = true;
289 Report.error (source_reference, "field type `%s` is less accessible than field `%s`".printf (variable_type.to_string (), get_full_name ()));
290 return false;
293 process_attributes ();
295 if (initializer != null) {
296 initializer.target_type = variable_type;
298 if (!initializer.check (context)) {
299 error = true;
300 return false;
303 if (initializer.value_type == null) {
304 error = true;
305 Report.error (source_reference, "expression type not allowed as initializer");
306 return false;
309 if (!initializer.value_type.compatible (variable_type)) {
310 error = true;
311 Report.error (source_reference, "Cannot convert from `%s' to `%s'".printf (initializer.value_type.to_string (), variable_type.to_string ()));
312 return false;
315 if (external) {
316 error = true;
317 Report.error (source_reference, "External fields cannot use initializers");
321 if (binding == MemberBinding.INSTANCE && parent_symbol is Interface) {
322 error = true;
323 Report.error (source_reference, "Interfaces may not have instance fields");
324 return false;
327 bool field_in_header = !is_internal_symbol ();
328 if (parent_symbol is Class) {
329 var cl = (Class) parent_symbol;
330 if (cl.is_compact && !cl.is_internal_symbol ()) {
331 // compact classes don't have priv structs
332 field_in_header = true;
336 if (!external_package && !hides && get_hidden_member () != null) {
337 Report.warning (source_reference, "%s hides inherited field `%s'. Use the `new' keyword if hiding was intentional".printf (get_full_name (), get_hidden_member ().get_full_name ()));
340 context.analyzer.current_source_file = old_source_file;
341 context.analyzer.current_symbol = old_symbol;
343 return !error;