vapigen: Support owned_get metadata attribute for properties
[vala-lang.git] / vala / valasymbolresolver.vala
blob24612f1642f9e6c1ad32553a30eac5d91612217a
1 /* valasymbolresolver.vala
3 * Copyright (C) 2006-2009 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
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.
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.
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
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 using GLib;
26 using Gee;
28 /**
29 * Code visitor resolving symbol names.
31 public class Vala.SymbolResolver : CodeVisitor {
32 Symbol root_symbol;
33 Scope current_scope;
34 Gee.List<UsingDirective> current_using_directives;
36 /**
37 * Resolve symbol names in the specified code context.
39 * @param context a code context
41 public void resolve (CodeContext context) {
42 root_symbol = context.root;
43 current_scope = root_symbol.scope;
45 context.accept (this);
48 public override void visit_source_file (SourceFile file) {
49 current_using_directives = file.get_using_directives ();
50 current_scope = root_symbol.scope;
52 file.accept_children (this);
54 current_using_directives = null;
57 public override void visit_class (Class cl) {
58 current_scope = cl.scope;
60 cl.accept_children (this);
62 foreach (DataType type in cl.get_base_types ()) {
63 if (type.data_type is Class) {
64 if (cl.base_class != null) {
65 cl.error = true;
66 Report.error (type.source_reference, "%s: Classes cannot have multiple base classes (`%s' and `%s')".printf (cl.get_full_name (), cl.base_class.get_full_name (), type.data_type.get_full_name ()));
67 return;
69 cl.base_class = (Class) type.data_type;
70 if (cl.base_class.is_subtype_of (cl)) {
71 cl.error = true;
72 Report.error (type.source_reference, "Base class cycle (`%s' and `%s')".printf (cl.get_full_name (), cl.base_class.get_full_name ()));
73 return;
78 current_scope = current_scope.parent_scope;
81 public override void visit_struct (Struct st) {
82 current_scope = st.scope;
84 st.accept_children (this);
86 if (st.base_type != null) {
87 var base_type = st.base_struct;
88 if (base_type != null) {
89 if (base_type.is_subtype_of (st)) {
90 st.error = true;
91 Report.error (base_type.source_reference, "Base struct cycle (`%s' and `%s')".printf (st.get_full_name (), base_type.get_full_name ()));
92 return;
97 current_scope = current_scope.parent_scope;
100 public override void visit_interface (Interface iface) {
101 current_scope = iface.scope;
103 iface.accept_children (this);
105 foreach (DataType type in iface.get_prerequisites ()) {
106 if (type.data_type != null && type.data_type.is_subtype_of (iface)) {
107 iface.error = true;
108 Report.error (type.source_reference, "Prerequisite cycle (`%s' and `%s')".printf (iface.get_full_name (), type.data_type.get_full_name ()));
109 return;
113 current_scope = current_scope.parent_scope;
116 public override void visit_enum (Enum en) {
117 current_scope = en.scope;
119 en.accept_children (this);
121 current_scope = current_scope.parent_scope;
124 public override void visit_error_domain (ErrorDomain ed) {
125 current_scope = ed.scope;
127 ed.accept_children (this);
129 current_scope = current_scope.parent_scope;
132 public override void visit_delegate (Delegate cb) {
133 current_scope = cb.scope;
135 cb.accept_children (this);
137 current_scope = current_scope.parent_scope;
140 public override void visit_constant (Constant c) {
141 current_scope = c.scope;
143 c.accept_children (this);
146 public override void visit_field (Field f) {
147 current_scope = f.scope;
149 f.accept_children (this);
151 current_scope = current_scope.parent_scope;
154 public override void visit_method (Method m) {
155 current_scope = m.scope;
157 m.accept_children (this);
159 current_scope = current_scope.parent_scope;
162 public override void visit_creation_method (CreationMethod m) {
163 m.accept_children (this);
166 public override void visit_formal_parameter (FormalParameter p) {
167 p.accept_children (this);
170 public override void visit_property (Property prop) {
171 prop.accept_children (this);
174 public override void visit_property_accessor (PropertyAccessor acc) {
175 acc.accept_children (this);
178 public override void visit_signal (Signal sig) {
179 sig.accept_children (this);
182 public override void visit_constructor (Constructor c) {
183 c.accept_children (this);
186 public override void visit_destructor (Destructor d) {
187 d.accept_children (this);
190 public override void visit_block (Block b) {
191 b.accept_children (this);
194 public override void visit_using_directive (UsingDirective ns) {
195 var unresolved_symbol = ns.namespace_symbol as UnresolvedSymbol;
196 if (unresolved_symbol != null) {
197 ns.namespace_symbol = resolve_symbol (unresolved_symbol);
198 if (ns.namespace_symbol == null) {
199 ns.error = true;
200 Report.error (ns.source_reference, "The namespace name `%s' could not be found".printf (unresolved_symbol.to_string ()));
201 return;
206 private Symbol? resolve_symbol (UnresolvedSymbol unresolved_symbol) {
207 if (unresolved_symbol.qualified) {
208 // qualified access to global symbol
209 return root_symbol.scope.lookup (unresolved_symbol.name);
210 } else if (unresolved_symbol.inner == null) {
211 Symbol sym = null;
212 Scope scope = current_scope;
213 while (sym == null && scope != null) {
214 sym = scope.lookup (unresolved_symbol.name);
216 // only look for types and type containers
217 if (!(sym is Namespace || sym is TypeSymbol || sym is TypeParameter)) {
218 sym = null;
221 scope = scope.parent_scope;
223 if (sym == null) {
224 foreach (UsingDirective ns in current_using_directives) {
225 if (ns.error || ns.namespace_symbol is UnresolvedSymbol) {
226 continue;
229 var local_sym = ns.namespace_symbol.scope.lookup (unresolved_symbol.name);
231 // only look for types and type containers
232 if (!(local_sym is Namespace || local_sym is TypeSymbol || sym is TypeParameter)) {
233 local_sym = null;
236 if (local_sym != null) {
237 if (sym != null) {
238 unresolved_symbol.error = true;
239 Report.error (unresolved_symbol.source_reference, "`%s' is an ambiguous reference between `%s' and `%s'".printf (unresolved_symbol.name, sym.get_full_name (), local_sym.get_full_name ()));
240 return null;
242 sym = local_sym;
246 return sym;
247 } else {
248 var parent_symbol = resolve_symbol (unresolved_symbol.inner);
249 if (parent_symbol == null) {
250 unresolved_symbol.error = true;
251 Report.error (unresolved_symbol.inner.source_reference, "The symbol `%s' could not be found".printf (unresolved_symbol.inner.name));
252 return null;
255 return parent_symbol.scope.lookup (unresolved_symbol.name);
259 private DataType resolve_type (UnresolvedType unresolved_type) {
260 DataType type = null;
262 // still required for vapigen
263 if (unresolved_type.unresolved_symbol.name == "void") {
264 return new VoidType ();
267 var sym = resolve_symbol (unresolved_type.unresolved_symbol);
268 if (sym == null) {
269 // don't report same error twice
270 if (!unresolved_type.unresolved_symbol.error) {
271 Report.error (unresolved_type.source_reference, "The type name `%s' could not be found".printf (unresolved_type.unresolved_symbol.to_string ()));
273 return new InvalidType ();
276 if (sym is TypeParameter) {
277 type = new GenericType ((TypeParameter) sym);
278 } else if (sym is TypeSymbol) {
279 if (sym is Delegate) {
280 type = new DelegateType ((Delegate) sym);
281 } else if (sym is Class) {
282 var cl = (Class) sym;
283 if (cl.is_error_base) {
284 type = new ErrorType (null, null, unresolved_type.source_reference);
285 } else {
286 type = new ObjectType (cl);
288 } else if (sym is Interface) {
289 type = new ObjectType ((Interface) sym);
290 } else if (sym is Struct) {
291 var st = (Struct) sym;
292 // attributes are not processed yet, access them directly
293 if (st.get_attribute ("BooleanType") != null) {
294 type = new BooleanType (st);
295 } else if (st.get_attribute ("IntegerType") != null) {
296 type = new IntegerType (st);
297 } else if (st.get_attribute ("FloatingType") != null) {
298 type = new FloatingType (st);
299 } else {
300 type = new StructValueType (st);
302 } else if (sym is Enum) {
303 type = new EnumValueType ((Enum) sym);
304 } else if (sym is ErrorDomain) {
305 type = new ErrorType ((ErrorDomain) sym, null, unresolved_type.source_reference);
306 } else if (sym is ErrorCode) {
307 type = new ErrorType ((ErrorDomain) sym.parent_symbol, (ErrorCode) sym, unresolved_type.source_reference);
308 } else {
309 Report.error (unresolved_type.source_reference, "internal error: `%s' is not a supported type".printf (sym.get_full_name ()));
310 return new InvalidType ();
312 } else {
313 Report.error (unresolved_type.source_reference, "`%s' is not a type".printf (sym.get_full_name ()));
314 return new InvalidType ();
317 type.source_reference = unresolved_type.source_reference;
318 type.value_owned = unresolved_type.value_owned;
320 if (type is GenericType) {
321 // type parameters are always considered nullable
322 // actual type argument may or may not be nullable
323 type.nullable = true;
324 } else {
325 type.nullable = unresolved_type.nullable;
328 type.is_dynamic = unresolved_type.is_dynamic;
329 foreach (DataType type_arg in unresolved_type.get_type_arguments ()) {
330 type.add_type_argument (type_arg);
333 return type;
336 public override void visit_data_type (DataType data_type) {
337 data_type.accept_children (this);
339 if (!(data_type is UnresolvedType)) {
340 return;
343 var unresolved_type = (UnresolvedType) data_type;
345 unresolved_type.parent_node.replace_type (unresolved_type, resolve_type (unresolved_type));
348 public override void visit_declaration_statement (DeclarationStatement stmt) {
349 stmt.accept_children (this);
352 public override void visit_local_variable (LocalVariable local) {
353 local.accept_children (this);
354 if (local.variable_type is ReferenceType) {
355 local.variable_type.nullable = true;
359 public override void visit_initializer_list (InitializerList list) {
360 list.accept_children (this);
363 public override void visit_expression_statement (ExpressionStatement stmt) {
364 stmt.accept_children (this);
367 public override void visit_if_statement (IfStatement stmt) {
368 stmt.accept_children (this);
371 public override void visit_switch_statement (SwitchStatement stmt) {
372 stmt.accept_children (this);
375 public override void visit_switch_section (SwitchSection section) {
376 section.accept_children (this);
379 public override void visit_switch_label (SwitchLabel label) {
380 label.accept_children (this);
383 public override void visit_loop (Loop stmt) {
384 stmt.accept_children (this);
387 public override void visit_while_statement (WhileStatement stmt) {
388 stmt.accept_children (this);
391 public override void visit_do_statement (DoStatement stmt) {
392 stmt.accept_children (this);
395 public override void visit_for_statement (ForStatement stmt) {
396 stmt.accept_children (this);
399 public override void visit_foreach_statement (ForeachStatement stmt) {
400 stmt.accept_children (this);
403 public override void visit_return_statement (ReturnStatement stmt) {
404 stmt.accept_children (this);
407 public override void visit_yield_statement (YieldStatement stmt) {
408 stmt.accept_children (this);
411 public override void visit_throw_statement (ThrowStatement stmt) {
412 stmt.accept_children (this);
415 public override void visit_try_statement (TryStatement stmt) {
416 stmt.accept_children (this);
419 public override void visit_catch_clause (CatchClause clause) {
420 clause.accept_children (this);
423 public override void visit_array_creation_expression (ArrayCreationExpression e) {
424 e.accept_children (this);
427 public override void visit_member_access (MemberAccess expr) {
428 expr.accept_children (this);
431 public override void visit_method_call (MethodCall expr) {
432 expr.accept_children (this);
435 public override void visit_element_access (ElementAccess expr) {
436 expr.accept_children (this);
439 public override void visit_object_creation_expression (ObjectCreationExpression expr) {
440 expr.accept_children (this);
443 public override void visit_unary_expression (UnaryExpression expr) {
444 expr.accept_children (this);
447 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr) {
448 expr.accept_children (this);
451 public override void visit_binary_expression (BinaryExpression expr) {
452 expr.accept_children (this);
455 public override void visit_lambda_expression (LambdaExpression l) {
456 l.accept_children (this);
459 public override void visit_assignment (Assignment a) {
460 a.accept_children (this);