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
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
29 * Code visitor resolving symbol names.
31 public class Vala
.SymbolResolver
: CodeVisitor
{
34 Gee
.List
<UsingDirective
> current_using_directives
;
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) {
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 ()));
69 cl
.base_class
= (Class
) type
.data_type
;
70 if (cl
.base_class
.is_subtype_of (cl
)) {
72 Report
.error (type
.source_reference
, "Base class cycle (`%s' and `%s')".printf (cl
.get_full_name (), cl
.base_class
.get_full_name ()));
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 current_scope
= current_scope
.parent_scope
;
89 public override void visit_interface (Interface iface
) {
90 current_scope
= iface
.scope
;
92 iface
.accept_children (this
);
94 foreach (DataType type
in iface
.get_prerequisites ()) {
95 if (type
.data_type
!= null && type
.data_type
.is_subtype_of (iface
)) {
97 Report
.error (type
.source_reference
, "Prerequisite cycle (`%s' and `%s')".printf (iface
.get_full_name (), type
.data_type
.get_full_name ()));
102 current_scope
= current_scope
.parent_scope
;
105 public override void visit_enum (Enum en
) {
106 current_scope
= en
.scope
;
108 en
.accept_children (this
);
110 current_scope
= current_scope
.parent_scope
;
113 public override void visit_error_domain (ErrorDomain ed
) {
114 current_scope
= ed
.scope
;
116 ed
.accept_children (this
);
118 current_scope
= current_scope
.parent_scope
;
121 public override void visit_delegate (Delegate cb
) {
122 current_scope
= cb
.scope
;
124 cb
.accept_children (this
);
126 current_scope
= current_scope
.parent_scope
;
129 public override void visit_constant (Constant c
) {
130 current_scope
= c
.scope
;
132 c
.accept_children (this
);
135 public override void visit_field (Field f
) {
136 current_scope
= f
.scope
;
138 f
.accept_children (this
);
140 current_scope
= current_scope
.parent_scope
;
143 public override void visit_method (Method m
) {
144 current_scope
= m
.scope
;
146 m
.accept_children (this
);
148 current_scope
= current_scope
.parent_scope
;
151 public override void visit_creation_method (CreationMethod m
) {
152 m
.accept_children (this
);
155 public override void visit_formal_parameter (FormalParameter p
) {
156 p
.accept_children (this
);
159 public override void visit_property (Property prop
) {
160 prop
.accept_children (this
);
163 public override void visit_property_accessor (PropertyAccessor acc
) {
164 acc
.accept_children (this
);
167 public override void visit_signal (Signal sig
) {
168 sig
.accept_children (this
);
171 public override void visit_constructor (Constructor c
) {
172 c
.accept_children (this
);
175 public override void visit_destructor (Destructor d
) {
176 d
.accept_children (this
);
179 public override void visit_block (Block b
) {
180 b
.accept_children (this
);
183 public override void visit_using_directive (UsingDirective ns
) {
184 var unresolved_symbol
= ns
.namespace_symbol as UnresolvedSymbol
;
185 if (unresolved_symbol
!= null) {
186 ns
.namespace_symbol
= resolve_symbol (unresolved_symbol
);
187 if (ns
.namespace_symbol
== null) {
189 Report
.error (ns
.source_reference
, "The namespace name `%s' could not be found".printf (unresolved_symbol
.to_string ()));
195 private Symbol?
resolve_symbol (UnresolvedSymbol unresolved_symbol
) {
196 if (unresolved_symbol
.qualified
) {
197 // qualified access to global symbol
198 return root_symbol
.scope
.lookup (unresolved_symbol
.name
);
199 } else if (unresolved_symbol
.inner
== null) {
201 Scope scope
= current_scope
;
202 while (sym
== null && scope
!= null) {
203 sym
= scope
.lookup (unresolved_symbol
.name
);
205 // only look for types and type containers
206 if (!(sym is Namespace
|| sym is TypeSymbol
|| sym is TypeParameter
)) {
210 scope
= scope
.parent_scope
;
213 foreach (UsingDirective ns
in current_using_directives
) {
214 if (ns
.error
|| ns
.namespace_symbol is UnresolvedSymbol
) {
218 var local_sym
= ns
.namespace_symbol
.scope
.lookup (unresolved_symbol
.name
);
220 // only look for types and type containers
221 if (!(local_sym is Namespace
|| local_sym is TypeSymbol
|| sym is TypeParameter
)) {
225 if (local_sym
!= null) {
227 unresolved_symbol
.error
= true;
228 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 ()));
237 var parent_symbol
= resolve_symbol (unresolved_symbol
.inner
);
238 if (parent_symbol
== null) {
239 unresolved_symbol
.error
= true;
240 Report
.error (unresolved_symbol
.inner
.source_reference
, "The symbol `%s' could not be found".printf (unresolved_symbol
.inner
.name
));
244 return parent_symbol
.scope
.lookup (unresolved_symbol
.name
);
248 private DataType
resolve_type (UnresolvedType unresolved_type
) {
249 DataType type
= null;
251 // still required for vapigen
252 if (unresolved_type
.unresolved_symbol
.name
== "void") {
253 return new
VoidType ();
256 var sym
= resolve_symbol (unresolved_type
.unresolved_symbol
);
258 // don't report same error twice
259 if (!unresolved_type
.unresolved_symbol
.error
) {
260 Report
.error (unresolved_type
.source_reference
, "The type name `%s' could not be found".printf (unresolved_type
.unresolved_symbol
.to_string ()));
262 return new
InvalidType ();
265 if (sym is TypeParameter
) {
266 type
= new
GenericType ((TypeParameter
) sym
);
267 } else if (sym is TypeSymbol
) {
268 if (sym is Delegate
) {
269 type
= new
DelegateType ((Delegate
) sym
);
270 } else if (sym is Class
) {
271 var cl
= (Class
) sym
;
272 if (cl
.is_error_base
) {
273 type
= new
ErrorType (null, null, unresolved_type
.source_reference
);
275 type
= new
ObjectType (cl
);
277 } else if (sym is Interface
) {
278 type
= new
ObjectType ((Interface
) sym
);
279 } else if (sym is Struct
) {
280 var st
= (Struct
) sym
;
281 if (st
.is_boolean_type ()) {
282 type
= new
BooleanType (st
);
283 } else if (st
.is_integer_type ()) {
284 type
= new
IntegerType (st
);
285 } else if (st
.is_floating_type ()) {
286 type
= new
FloatingType (st
);
288 type
= new
StructValueType (st
);
290 } else if (sym is Enum
) {
291 type
= new
EnumValueType ((Enum
) sym
);
292 } else if (sym is ErrorDomain
) {
293 type
= new
ErrorType ((ErrorDomain
) sym
, null, unresolved_type
.source_reference
);
294 } else if (sym is ErrorCode
) {
295 type
= new
ErrorType ((ErrorDomain
) sym
.parent_symbol
, (ErrorCode
) sym
, unresolved_type
.source_reference
);
297 Report
.error (unresolved_type
.source_reference
, "internal error: `%s' is not a supported type".printf (sym
.get_full_name ()));
298 return new
InvalidType ();
301 Report
.error (unresolved_type
.source_reference
, "`%s' is not a type".printf (sym
.get_full_name ()));
302 return new
InvalidType ();
305 type
.source_reference
= unresolved_type
.source_reference
;
306 type
.value_owned
= unresolved_type
.value_owned
;
308 if (type is GenericType
) {
309 // type parameters are always considered nullable
310 // actual type argument may or may not be nullable
311 type
.nullable
= true;
313 type
.nullable
= unresolved_type
.nullable
;
316 type
.is_dynamic
= unresolved_type
.is_dynamic
;
317 foreach (DataType type_arg
in unresolved_type
.get_type_arguments ()) {
318 type
.add_type_argument (type_arg
);
324 public override void visit_data_type (DataType data_type
) {
325 data_type
.accept_children (this
);
327 if (!(data_type is UnresolvedType
)) {
331 var unresolved_type
= (UnresolvedType
) data_type
;
333 unresolved_type
.parent_node
.replace_type (unresolved_type
, resolve_type (unresolved_type
));
336 public override void visit_declaration_statement (DeclarationStatement stmt
) {
337 stmt
.accept_children (this
);
340 public override void visit_local_variable (LocalVariable local
) {
341 local
.accept_children (this
);
342 if (local
.variable_type is ReferenceType
) {
343 local
.variable_type
.nullable
= true;
347 public override void visit_initializer_list (InitializerList list
) {
348 list
.accept_children (this
);
351 public override void visit_expression_statement (ExpressionStatement stmt
) {
352 stmt
.accept_children (this
);
355 public override void visit_if_statement (IfStatement stmt
) {
356 stmt
.accept_children (this
);
359 public override void visit_switch_statement (SwitchStatement stmt
) {
360 stmt
.accept_children (this
);
363 public override void visit_switch_section (SwitchSection section
) {
364 section
.accept_children (this
);
367 public override void visit_switch_label (SwitchLabel label
) {
368 label
.accept_children (this
);
371 public override void visit_while_statement (WhileStatement stmt
) {
372 stmt
.accept_children (this
);
375 public override void visit_do_statement (DoStatement stmt
) {
376 stmt
.accept_children (this
);
379 public override void visit_for_statement (ForStatement stmt
) {
380 stmt
.accept_children (this
);
383 public override void visit_foreach_statement (ForeachStatement stmt
) {
384 stmt
.accept_children (this
);
387 public override void visit_return_statement (ReturnStatement stmt
) {
388 stmt
.accept_children (this
);
391 public override void visit_yield_statement (YieldStatement stmt
) {
392 stmt
.accept_children (this
);
395 public override void visit_throw_statement (ThrowStatement stmt
) {
396 stmt
.accept_children (this
);
399 public override void visit_try_statement (TryStatement stmt
) {
400 stmt
.accept_children (this
);
403 public override void visit_catch_clause (CatchClause clause
) {
404 clause
.accept_children (this
);
407 public override void visit_array_creation_expression (ArrayCreationExpression e
) {
408 e
.accept_children (this
);
411 public override void visit_parenthesized_expression (ParenthesizedExpression expr
) {
412 expr
.accept_children (this
);
415 public override void visit_member_access (MemberAccess expr
) {
416 expr
.accept_children (this
);
419 public override void visit_method_call (MethodCall expr
) {
420 expr
.accept_children (this
);
423 public override void visit_element_access (ElementAccess expr
) {
424 expr
.accept_children (this
);
427 public override void visit_object_creation_expression (ObjectCreationExpression expr
) {
428 expr
.accept_children (this
);
431 public override void visit_unary_expression (UnaryExpression expr
) {
432 expr
.accept_children (this
);
435 public override void visit_reference_transfer_expression (ReferenceTransferExpression expr
) {
436 expr
.accept_children (this
);
439 public override void visit_binary_expression (BinaryExpression expr
) {
440 expr
.accept_children (this
);
443 public override void visit_lambda_expression (LambdaExpression l
) {
444 l
.accept_children (this
);
447 public override void visit_assignment (Assignment a
) {
448 a
.accept_children (this
);