Fix crash when using out parameters in delegates, fixes bug 563705
[vala-lang.git] / vala / valafield.vala
blob56ec66b2d17c4dbdedcc4549b6589873ba706cf1
1 /* valafield.vala
3 * Copyright (C) 2006-2008 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;
24 using Gee;
26 /**
27 * Represents a type or namespace field.
29 public class Vala.Field : Member, Lockable {
30 /**
31 * The data type of this field.
33 public DataType field_type {
34 get { return _data_type; }
35 set {
36 _data_type = value;
37 _data_type.parent_node = this;
41 /**
42 * Specifies the expression to be used to initialize this field.
44 public Expression? initializer {
45 get { return _initializer; }
46 set {
47 _initializer = value;
48 if (_initializer != null) {
49 _initializer.parent_node = this;
54 /**
55 * Specifies whether this field may only be accessed with an instance of
56 * the contained type.
58 public MemberBinding binding { get; set; default = MemberBinding.INSTANCE; }
60 /**
61 * Specifies whether the field is volatile. Volatile fields are
62 * necessary to allow multi-threaded access.
64 public bool is_volatile { get; set; }
66 /**
67 * Specifies whether an array length field should implicitly be created
68 * if the field type is an array.
70 public bool no_array_length { get; set; }
72 private string cname;
74 private bool lock_used = false;
76 private Expression _initializer;
78 private DataType _data_type;
80 /**
81 * Creates a new field.
83 * @param name field name
84 * @param type field type
85 * @param init initializer expression
86 * @param source reference to source code
87 * @return newly created field
89 public Field (string name, DataType field_type, Expression? initializer, SourceReference? source_reference = null) {
90 base (name, source_reference);
91 this.field_type = field_type;
92 this.initializer = initializer;
95 public override void accept (CodeVisitor visitor) {
96 visitor.visit_member (this);
98 visitor.visit_field (this);
101 public override void accept_children (CodeVisitor visitor) {
102 field_type.accept (visitor);
104 if (initializer != null) {
105 initializer.accept (visitor);
110 * Returns the name of this field as it is used in C code.
112 * @return the name to be used in C code
114 public string get_cname () {
115 if (cname == null) {
116 cname = get_default_cname ();
118 return cname;
122 * Sets the name of this field as it is used in C code.
124 * @param cname the name to be used in C code
126 public void set_cname (string cname) {
127 this.cname = cname;
131 * Returns the default name of this field as it is used in C code.
133 * @return the name to be used in C code by default
135 public string get_default_cname () {
136 if (binding == MemberBinding.STATIC) {
137 return parent_symbol.get_lower_case_cprefix () + name;
138 } else {
139 return name;
143 private void process_ccode_attribute (Attribute a) {
144 if (a.has_argument ("cname")) {
145 set_cname (a.get_string ("cname"));
147 if (a.has_argument ("cheader_filename")) {
148 var val = a.get_string ("cheader_filename");
149 foreach (string filename in val.split (",")) {
150 add_cheader_filename (filename);
156 * Process all associated attributes.
158 public void process_attributes () {
159 foreach (Attribute a in attributes) {
160 if (a.name == "CCode") {
161 process_ccode_attribute (a);
162 } else if (a.name == "NoArrayLength") {
163 no_array_length = true;
168 public bool get_lock_used () {
169 return lock_used;
172 public void set_lock_used (bool used) {
173 lock_used = used;
176 public override void replace_type (DataType old_type, DataType new_type) {
177 if (field_type == old_type) {
178 field_type = new_type;
182 public string? get_ctype () {
183 var attr = get_attribute ("CCode");
184 if (attr == null) {
185 return null;
187 return attr.get_string ("type");
190 public void set_ctype (string ctype) {
191 var attr = get_attribute ("CCode");
192 if (attr == null) {
193 attr = new Attribute ("CCode");
194 attributes.append (attr);
196 attr.add_argument ("type", new StringLiteral ("\"%s\"".printf (ctype)));
199 public override bool check (SemanticAnalyzer analyzer) {
200 if (checked) {
201 return !error;
204 checked = true;
206 var old_source_file = analyzer.current_source_file;
208 if (source_reference != null) {
209 analyzer.current_source_file = source_reference.file;
212 field_type.check (analyzer);
214 process_attributes ();
216 if (initializer != null) {
217 initializer.target_type = field_type;
220 field_type.check (analyzer);
222 if (initializer != null) {
223 initializer.check (analyzer);
226 if (binding == MemberBinding.INSTANCE && parent_symbol is Interface) {
227 error = true;
228 Report.error (source_reference, "Interfaces may not have instance fields");
229 return false;
232 bool field_in_header = !is_internal_symbol ();
233 if (parent_symbol is Class) {
234 var cl = (Class) parent_symbol;
235 if (cl.is_compact && !cl.is_internal_symbol ()) {
236 // compact classes don't have priv structs
237 field_in_header = true;
241 if (field_in_header) {
242 if (field_type is ValueType) {
243 analyzer.current_source_file.add_type_dependency (field_type, SourceFileDependencyType.HEADER_FULL);
244 } else {
245 analyzer.current_source_file.add_type_dependency (field_type, SourceFileDependencyType.HEADER_SHALLOW);
247 } else {
248 if (parent_symbol is Namespace) {
249 error = true;
250 Report.error (source_reference, "Namespaces may not have private members");
251 return false;
254 analyzer.current_source_file.add_type_dependency (field_type, SourceFileDependencyType.SOURCE);
257 analyzer.current_source_file = old_source_file;
259 return !error;