gtk+-3.0: Update to 3.0.5
[vala-lang.git] / vala / valamemberaccess.vala
blobdfb0eb6eeb31f9584849e2cd7ee65904c798f594
1 /* valamemberaccess.vala
3 * Copyright (C) 2006-2011 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 an access to a type member in the source code.
28 public class Vala.MemberAccess : Expression {
29 /**
30 * The parent of the member.
32 public Expression? inner {
33 get {
34 return _inner;
36 set {
37 _inner = value;
38 if (_inner != null) {
39 _inner.parent_node = this;
44 /**
45 * The name of the member.
47 public string member_name { get; set; }
49 /**
50 * Pointer member access.
52 public bool pointer_member_access { get; set; }
54 /**
55 * Represents access to an instance member without an actual instance,
56 * e.g. `MyClass.an_instance_method`.
58 public bool prototype_access { get; set; }
60 /**
61 * Specifies whether the member is used for object creation.
63 public bool creation_member { get; set; }
65 /**
66 * Qualified access to global symbol.
68 public bool qualified { get; set; }
70 private Expression? _inner;
71 private List<DataType> type_argument_list = new ArrayList<DataType> ();
73 /**
74 * Creates a new member access expression.
76 * @param inner parent of the member
77 * @param member_name member name
78 * @param source_reference reference to source code
79 * @return newly created member access expression
81 public MemberAccess (Expression? inner, string member_name, SourceReference? source_reference = null) {
82 this.inner = inner;
83 this.member_name = member_name;
84 this.source_reference = source_reference;
87 public MemberAccess.simple (string member_name, SourceReference? source_reference = null) {
88 this.member_name = member_name;
89 this.source_reference = source_reference;
92 public MemberAccess.pointer (Expression inner, string member_name, SourceReference? source_reference = null) {
93 this.inner = inner;
94 this.member_name = member_name;
95 this.source_reference = source_reference;
96 pointer_member_access = true;
99 /**
100 * Appends the specified type as generic type argument.
102 * @param arg a type reference
104 public void add_type_argument (DataType arg) {
105 type_argument_list.add (arg);
106 arg.parent_node = this;
110 * Returns a copy of the list of generic type arguments.
112 * @return type argument list
114 public List<DataType> get_type_arguments () {
115 return type_argument_list;
118 public override void accept (CodeVisitor visitor) {
119 visitor.visit_member_access (this);
121 visitor.visit_expression (this);
124 public override void accept_children (CodeVisitor visitor) {
125 if (inner != null) {
126 inner.accept (visitor);
129 foreach (DataType type_arg in type_argument_list) {
130 type_arg.accept (visitor);
134 public override string to_string () {
135 if (symbol_reference == null || symbol_reference.is_instance_member ()) {
136 if (inner == null) {
137 return member_name;
138 } else {
139 return "%s.%s".printf (inner.to_string (), member_name);
141 } else {
142 // ensure to always use fully-qualified name
143 // to refer to static members
144 return symbol_reference.get_full_name ();
148 public override void replace_expression (Expression old_node, Expression new_node) {
149 if (inner == old_node) {
150 inner = new_node;
154 public override bool is_pure () {
155 // accessing property could have side-effects
156 return (inner == null || inner.is_pure ()) && !(symbol_reference is Property);
159 public override void replace_type (DataType old_type, DataType new_type) {
160 for (int i = 0; i < type_argument_list.size; i++) {
161 if (type_argument_list[i] == old_type) {
162 type_argument_list[i] = new_type;
163 return;
168 public override bool is_constant () {
169 var method = symbol_reference as Method;
170 if (symbol_reference is Constant) {
171 return true;
172 } else if (method != null &&
173 (method.binding == MemberBinding.STATIC || prototype_access)) {
174 return true;
175 } else {
176 return false;
180 public override bool is_non_null () {
181 var c = symbol_reference as Constant;
182 if (c != null) {
183 return !c.type_reference.nullable;
184 } else {
185 return false;
189 public override bool check (CodeContext context) {
190 if (checked) {
191 return !error;
194 checked = true;
196 if (inner != null) {
197 inner.check (context);
200 foreach (DataType type_arg in type_argument_list) {
201 type_arg.check (context);
204 Symbol base_symbol = null;
205 Parameter this_parameter = null;
206 bool may_access_instance_members = false;
207 bool may_access_klass_members = false;
209 symbol_reference = null;
211 if (qualified) {
212 base_symbol = context.analyzer.root_symbol;
213 symbol_reference = context.analyzer.root_symbol.scope.lookup (member_name);
214 } else if (inner == null) {
215 if (member_name == "this") {
216 if (!context.analyzer.is_in_instance_method ()) {
217 error = true;
218 Report.error (source_reference, "This access invalid outside of instance methods");
219 return false;
223 base_symbol = context.analyzer.current_symbol;
225 // track whether method has been found to make sure that access
226 // to instance member is denied from within static lambda expressions
227 bool method_found = false;
229 var sym = context.analyzer.current_symbol;
230 while (sym != null && symbol_reference == null) {
231 if (!method_found) {
232 if (sym is CreationMethod) {
233 var cm = (CreationMethod) sym;
234 this_parameter = cm.this_parameter;
235 may_access_instance_members = true;
236 may_access_klass_members = true;
237 method_found = true;
238 } else if (sym is Property) {
239 var prop = (Property) sym;
240 this_parameter = prop.this_parameter;
241 may_access_instance_members = (prop.binding == MemberBinding.INSTANCE);
242 may_access_klass_members = (prop.binding != MemberBinding.STATIC);
243 method_found = true;
244 } else if (sym is Constructor) {
245 var c = (Constructor) sym;
246 this_parameter = c.this_parameter;
247 may_access_instance_members = (c.binding == MemberBinding.INSTANCE);
248 may_access_klass_members = true;
249 method_found = true;
250 } else if (sym is Destructor) {
251 var d = (Destructor) sym;
252 this_parameter = d.this_parameter;
253 may_access_instance_members = (d.binding == MemberBinding.INSTANCE);
254 may_access_klass_members = true;
255 method_found = true;
256 } else if (sym is Method) {
257 var m = (Method) sym;
258 this_parameter = m.this_parameter;
259 may_access_instance_members = (m.binding == MemberBinding.INSTANCE);
260 may_access_klass_members = (m.binding != MemberBinding.STATIC);
261 method_found = true;
265 symbol_reference = context.analyzer.symbol_lookup_inherited (sym, member_name);
267 if (symbol_reference == null) {
268 if (sym is TypeSymbol) {
269 // do not allow instance access to outer classes
270 this_parameter = null;
271 may_access_instance_members = false;
272 may_access_klass_members = false;
276 sym = sym.parent_symbol;
279 if (symbol_reference == null && source_reference != null) {
280 foreach (UsingDirective ns in source_reference.using_directives) {
281 var local_sym = ns.namespace_symbol.scope.lookup (member_name);
282 if (local_sym != null) {
283 if (symbol_reference != null && symbol_reference != local_sym) {
284 error = true;
285 Report.error (source_reference, "`%s' is an ambiguous reference between `%s' and `%s'".printf (member_name, symbol_reference.get_full_name (), local_sym.get_full_name ()));
286 return false;
288 symbol_reference = local_sym;
292 } else {
293 if (inner.error) {
294 /* if there was an error in the inner expression, skip this check */
295 error = true;
296 return false;
299 if (inner.value_type is PointerType) {
300 var pointer_type = inner.value_type as PointerType;
301 if (pointer_type != null && pointer_type.base_type is ValueType) {
302 // transform foo->bar to (*foo).bar
303 inner = new PointerIndirection (inner, source_reference);
304 inner.check (context);
305 pointer_member_access = false;
309 if (inner is MemberAccess) {
310 var ma = (MemberAccess) inner;
311 if (ma.prototype_access) {
312 error = true;
313 Report.error (source_reference, "Access to instance member `%s' denied".printf (inner.symbol_reference.get_full_name ()));
314 return false;
318 if (inner is MemberAccess || inner is BaseAccess) {
319 base_symbol = inner.symbol_reference;
321 if (symbol_reference == null && (base_symbol is Namespace || base_symbol is TypeSymbol)) {
322 symbol_reference = base_symbol.scope.lookup (member_name);
323 if (inner is BaseAccess) {
324 // inner expression is base access
325 // access to instance members of the base type possible
326 may_access_instance_members = true;
327 may_access_klass_members = true;
332 if (symbol_reference == null && inner.value_type != null) {
333 if (pointer_member_access) {
334 symbol_reference = inner.value_type.get_pointer_member (member_name);
335 } else {
336 if (inner.value_type.data_type != null) {
337 base_symbol = inner.value_type.data_type;
339 symbol_reference = inner.value_type.get_member (member_name);
341 if (symbol_reference != null) {
342 // inner expression is variable, field, or parameter
343 // access to instance members of the corresponding type possible
344 may_access_instance_members = true;
345 may_access_klass_members = true;
349 if (symbol_reference == null && inner.value_type != null && inner.value_type.is_dynamic) {
350 // allow late bound members for dynamic types
351 var dynamic_object_type = (ObjectType) inner.value_type;
352 if (parent_node is MethodCall) {
353 var invoc = (MethodCall) parent_node;
354 if (invoc.call == this) {
355 // dynamic method
356 DataType ret_type;
357 if (invoc.target_type != null) {
358 ret_type = invoc.target_type.copy ();
359 ret_type.value_owned = true;
360 } else if (invoc.parent_node is ExpressionStatement) {
361 ret_type = new VoidType ();
362 } else {
363 // expect dynamic object of the same type
364 ret_type = inner.value_type.copy ();
366 var m = new DynamicMethod (inner.value_type, member_name, ret_type, source_reference);
367 m.invocation = invoc;
368 var err = new ErrorType (null, null);
369 err.dynamic_error = true;
370 m.add_error_type (err);
371 m.access = SymbolAccessibility.PUBLIC;
372 m.add_parameter (new Parameter.with_ellipsis ());
373 dynamic_object_type.type_symbol.scope.add (null, m);
374 symbol_reference = m;
376 } else if (parent_node is Assignment) {
377 var a = (Assignment) parent_node;
378 if (a.left == this
379 && (a.operator == AssignmentOperator.ADD
380 || a.operator == AssignmentOperator.SUB)) {
381 // dynamic signal
382 var s = new DynamicSignal (inner.value_type, member_name, new VoidType (), source_reference);
383 s.handler = a.right;
384 s.access = SymbolAccessibility.PUBLIC;
385 dynamic_object_type.type_symbol.scope.add (null, s);
386 symbol_reference = s;
387 } else if (a.left == this) {
388 // dynamic property assignment
389 var prop = new DynamicProperty (inner.value_type, member_name, source_reference);
390 prop.access = SymbolAccessibility.PUBLIC;
391 prop.set_accessor = new PropertyAccessor (false, true, false, null, null, prop.source_reference);
392 prop.owner = inner.value_type.data_type.scope;
393 dynamic_object_type.type_symbol.scope.add (null, prop);
394 symbol_reference = prop;
396 } else if (parent_node is MemberAccess && inner is MemberAccess && parent_node.parent_node is MethodCall) {
397 var ma = (MemberAccess) parent_node;
398 if (ma.member_name == "connect" || ma.member_name == "connect_after") {
399 // dynamic signal
400 var s = new DynamicSignal (inner.value_type, member_name, new VoidType (), source_reference);
401 var mcall = (MethodCall) parent_node.parent_node;
402 // the first argument is the handler
403 if (mcall.get_argument_list().size > 0) {
404 s.handler = mcall.get_argument_list()[0];
406 s.access = SymbolAccessibility.PUBLIC;
407 dynamic_object_type.type_symbol.scope.add (null, s);
408 symbol_reference = s;
411 if (symbol_reference == null) {
412 // dynamic property read access
413 var prop = new DynamicProperty (inner.value_type, member_name, source_reference);
414 if (target_type != null) {
415 prop.property_type = target_type;
416 } else {
417 // expect dynamic object of the same type
418 prop.property_type = inner.value_type.copy ();
420 prop.access = SymbolAccessibility.PUBLIC;
421 prop.get_accessor = new PropertyAccessor (true, false, false, prop.property_type.copy (), null, prop.source_reference);
422 prop.owner = inner.value_type.data_type.scope;
423 dynamic_object_type.type_symbol.scope.add (null, prop);
424 symbol_reference = prop;
426 if (symbol_reference != null) {
427 may_access_instance_members = true;
428 may_access_klass_members = true;
433 if (symbol_reference == null) {
434 error = true;
436 string base_type_name = "(null)";
437 if (inner != null && inner.value_type != null) {
438 base_type_name = inner.value_type.to_string ();
439 } else if (base_symbol != null) {
440 base_type_name = base_symbol.get_full_name ();
443 Report.error (source_reference, "The name `%s' does not exist in the context of `%s'".printf (member_name, base_type_name));
444 return false;
447 var member = symbol_reference;
448 var access = SymbolAccessibility.PUBLIC;
449 bool instance = false;
450 bool klass = false;
451 bool generics = false;
453 if (!member.check (context)) {
454 return false;
457 if (member is LocalVariable) {
458 var local = (LocalVariable) member;
459 var block = local.parent_symbol as Block;
460 if (block != null && context.analyzer.find_parent_method_or_property_accessor (block) != context.analyzer.current_method_or_property_accessor) {
461 // mark all methods between current method and the captured
462 // block as closures (to support nested closures)
463 Symbol sym = context.analyzer.current_method_or_property_accessor;
464 while (sym != block) {
465 var method = sym as Method;
466 if (method != null) {
467 method.closure = true;
468 // consider captured variables as used
469 // as we require captured variables to be initialized
470 method.add_captured_variable (local);
472 sym = sym.parent_symbol;
475 local.captured = true;
476 block.captured = true;
478 } else if (member is Parameter) {
479 var param = (Parameter) member;
480 var m = param.parent_symbol as Method;
481 if (m != null && m != context.analyzer.current_method_or_property_accessor && param != m.this_parameter) {
482 // mark all methods between current method and the captured
483 // parameter as closures (to support nested closures)
484 Symbol sym = context.analyzer.current_method_or_property_accessor;
485 while (sym != m) {
486 var method = sym as Method;
487 if (method != null) {
488 method.closure = true;
490 sym = sym.parent_symbol;
493 param.captured = true;
494 m.body.captured = true;
496 if (param.direction != ParameterDirection.IN) {
497 error = true;
498 Report.error (source_reference, "Cannot capture reference or output parameter `%s'".printf (param.get_full_name ()));
500 } else {
501 var acc = param.parent_symbol.parent_symbol as PropertyAccessor;
502 if (acc != null && acc != context.analyzer.current_method_or_property_accessor && param != acc.prop.this_parameter) {
503 // mark all methods between current method and the captured
504 // parameter as closures (to support nested closures)
505 Symbol sym = context.analyzer.current_method_or_property_accessor;
506 while (sym != m) {
507 var method = sym as Method;
508 if (method != null) {
509 method.closure = true;
511 sym = sym.parent_symbol;
514 param.captured = true;
515 acc.body.captured = true;
518 } else if (member is Field) {
519 var f = (Field) member;
520 access = f.access;
521 instance = (f.binding == MemberBinding.INSTANCE);
522 klass = (f.binding == MemberBinding.CLASS);
524 // do not allow access to fields of generic types
525 // if instance type does not specify type arguments
526 if (f.variable_type is GenericType) {
527 generics = true;
529 } else if (member is Constant) {
530 var c = (Constant) member;
531 access = c.access;
532 } else if (member is Method) {
533 var m = (Method) member;
534 if (m.is_async_callback) {
535 // ensure to use right callback method for virtual/abstract async methods
536 // and also for lambda expressions within async methods
537 var async_method = context.analyzer.current_async_method;
539 if (async_method != context.analyzer.current_method) {
540 Symbol sym = context.analyzer.current_method;
541 while (sym != async_method) {
542 var method = sym as Method;
543 if (method != null) {
544 method.closure = true;
546 sym = sym.parent_symbol;
548 async_method.body.captured = true;
551 m = async_method.get_callback_method ();
552 symbol_reference = m;
553 member = symbol_reference;
554 } else if (m.base_method != null) {
555 // refer to base method to inherit default arguments
556 m = m.base_method;
558 if (m.signal_reference != null) {
559 // method is class/default handler for a signal
560 // let signal deal with member access
561 symbol_reference = m.signal_reference;
562 } else {
563 symbol_reference = m;
566 member = symbol_reference;
567 } else if (m.base_interface_method != null) {
568 // refer to base method to inherit default arguments
569 m = m.base_interface_method;
570 symbol_reference = m;
571 member = symbol_reference;
573 access = m.access;
574 if (!(m is CreationMethod)) {
575 instance = (m.binding == MemberBinding.INSTANCE);
577 klass = (m.binding == MemberBinding.CLASS);
579 // do not allow access to methods using generic type parameters
580 // if instance type does not specify type arguments
581 foreach (var param in m.get_parameters ()) {
582 var generic_type = param.variable_type as GenericType;
583 if (generic_type != null && generic_type.type_parameter.parent_symbol is TypeSymbol) {
584 generics = true;
585 break;
588 var generic_type = m.return_type as GenericType;
589 if (generic_type != null && generic_type.type_parameter.parent_symbol is TypeSymbol) {
590 generics = true;
592 } else if (member is Property) {
593 var prop = (Property) member;
594 if (!prop.check (context)) {
595 error = true;
596 return false;
598 if (prop.base_property != null) {
599 // refer to base property
600 prop = prop.base_property;
601 symbol_reference = prop;
602 member = symbol_reference;
603 } else if (prop.base_interface_property != null) {
604 // refer to base property
605 prop = prop.base_interface_property;
606 symbol_reference = prop;
607 member = symbol_reference;
609 access = prop.access;
610 if (lvalue) {
611 if (prop.set_accessor == null) {
612 error = true;
613 Report.error (source_reference, "Property `%s' is read-only".printf (prop.get_full_name ()));
614 return false;
616 if (prop.access == SymbolAccessibility.PUBLIC) {
617 access = prop.set_accessor.access;
618 } else if (prop.access == SymbolAccessibility.PROTECTED
619 && prop.set_accessor.access != SymbolAccessibility.PUBLIC) {
620 access = prop.set_accessor.access;
622 } else {
623 if (prop.get_accessor == null) {
624 error = true;
625 Report.error (source_reference, "Property `%s' is write-only".printf (prop.get_full_name ()));
626 return false;
628 if (prop.access == SymbolAccessibility.PUBLIC) {
629 access = prop.get_accessor.access;
630 } else if (prop.access == SymbolAccessibility.PROTECTED
631 && prop.get_accessor.access != SymbolAccessibility.PUBLIC) {
632 access = prop.get_accessor.access;
635 instance = (prop.binding == MemberBinding.INSTANCE);
637 // do not allow access to properties of generic types
638 // if instance type does not specify type arguments
639 if (prop.property_type is GenericType) {
640 generics = true;
642 } else if (member is Signal) {
643 instance = true;
644 access = member.access;
647 member.used = true;
648 member.check_deprecated (source_reference);
649 member.check_experimental (source_reference);
651 if (access == SymbolAccessibility.PROTECTED) {
652 var target_type = (TypeSymbol) member.parent_symbol;
654 bool in_subtype = false;
655 for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) {
656 if (this_symbol == target_type) {
657 // required for interfaces with non-abstract methods
658 // accessing protected interface members
659 in_subtype = true;
660 break;
663 var cl = this_symbol as Class;
664 if (cl != null && cl.is_subtype_of (target_type)) {
665 in_subtype = true;
666 break;
670 if (!in_subtype) {
671 error = true;
672 Report.error (source_reference, "Access to protected member `%s' denied".printf (member.get_full_name ()));
673 return false;
675 } else if (access == SymbolAccessibility.PRIVATE) {
676 var target_type = member.parent_symbol;
678 bool in_target_type = false;
679 for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) {
680 if (target_type == this_symbol) {
681 in_target_type = true;
682 break;
686 if (!in_target_type) {
687 error = true;
688 Report.error (source_reference, "Access to private member `%s' denied".printf (member.get_full_name ()));
689 return false;
693 if (generics && inner != null) {
694 var instance_type = inner.value_type;
695 var pointer_type = inner.value_type as PointerType;
696 if (pointer_type != null) {
697 instance_type = pointer_type.base_type;
700 // instance type might be a subtype of the parent symbol of the member
701 // that subtype might not be generic, so do not report an error in that case
702 var object_type = instance_type as ObjectType;
703 if (object_type != null && object_type.type_symbol.get_type_parameters ().size > 0 &&
704 instance_type.get_type_arguments ().size == 0) {
705 error = true;
706 Report.error (inner.source_reference, "missing generic type arguments");
707 return false;
711 if ((instance && !may_access_instance_members) ||
712 (klass && !may_access_klass_members)) {
713 prototype_access = true;
715 if (symbol_reference is Method) {
716 // also set static type for prototype access
717 // required when using instance methods as delegates in constants
718 // TODO replace by MethodPrototype
719 value_type = context.analyzer.get_value_type_for_symbol (symbol_reference, lvalue);
720 } else if (symbol_reference is Field) {
721 value_type = new FieldPrototype ((Field) symbol_reference);
722 } else {
723 value_type = new InvalidType ();
726 if (target_type != null) {
727 value_type.value_owned = target_type.value_owned;
729 } else {
730 // implicit this access
731 if (instance && inner == null) {
732 inner = new MemberAccess (null, "this", source_reference);
733 inner.value_type = this_parameter.variable_type.copy ();
734 inner.symbol_reference = this_parameter;
737 if (context.experimental_non_null && instance && inner.value_type.nullable &&
738 !(inner.value_type is PointerType) && !(inner.value_type is GenericType)) {
739 Report.error (source_reference, "Access to instance member `%s' from nullable reference denied".printf (symbol_reference.get_full_name ()));
742 formal_value_type = context.analyzer.get_value_type_for_symbol (symbol_reference, lvalue);
743 if (inner != null && formal_value_type != null) {
744 value_type = formal_value_type.get_actual_type (inner.value_type, null, this);
745 } else {
746 value_type = formal_value_type;
749 if (symbol_reference is Method) {
750 var m = (Method) symbol_reference;
752 if (target_type != null) {
753 value_type.value_owned = target_type.value_owned;
756 Method base_method;
757 if (m.base_method != null) {
758 base_method = m.base_method;
759 } else if (m.base_interface_method != null) {
760 base_method = m.base_interface_method;
761 } else {
762 base_method = m;
765 if (instance && base_method.parent_symbol is TypeSymbol) {
766 inner.target_type = context.analyzer.get_data_type_for_symbol ((TypeSymbol) base_method.parent_symbol);
768 } else if (symbol_reference is Property) {
769 var prop = (Property) symbol_reference;
771 Property base_property;
772 if (prop.base_property != null) {
773 base_property = prop.base_property;
774 } else if (prop.base_interface_property != null) {
775 base_property = prop.base_interface_property;
776 } else {
777 base_property = prop;
780 if (instance && base_property.parent_symbol != null) {
781 inner.target_type = context.analyzer.get_data_type_for_symbol ((TypeSymbol) base_property.parent_symbol);
783 } else if ((symbol_reference is Field
784 || symbol_reference is Signal)
785 && instance && symbol_reference.parent_symbol != null) {
786 inner.target_type = context.analyzer.get_data_type_for_symbol ((TypeSymbol) symbol_reference.parent_symbol);
790 return !error;
793 public override void emit (CodeGenerator codegen) {
794 if (inner != null) {
795 inner.emit (codegen);
798 codegen.visit_member_access (this);
800 codegen.visit_expression (this);
803 public override void get_defined_variables (Collection<LocalVariable> collection) {
804 if (inner != null) {
805 inner.get_defined_variables (collection);
809 public override void get_used_variables (Collection<LocalVariable> collection) {
810 if (inner != null) {
811 inner.get_used_variables (collection);
813 var local = symbol_reference as LocalVariable;
814 if (local != null) {
815 collection.add (local);