vala: Add consts/methods to retrieve and check library version
[vala-gnome.git] / vala / valamemberaccess.vala
blob64263ba3e3b7b5cfcf4475dc0bf181dfa16b6366
1 /* valamemberaccess.vala
3 * Copyright (C) 2006-2012 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 bool is_accessible (Symbol sym) {
160 return (inner == null || inner.is_accessible (sym)) && symbol_reference.is_accessible (sym);
163 public override void replace_type (DataType old_type, DataType new_type) {
164 for (int i = 0; i < type_argument_list.size; i++) {
165 if (type_argument_list[i] == old_type) {
166 type_argument_list[i] = new_type;
167 return;
172 public override bool is_constant () {
173 var method = symbol_reference as Method;
174 if (symbol_reference is Constant) {
175 return true;
176 } else if (symbol_reference is ArrayLengthField && inner != null && inner.symbol_reference is Constant) {
177 // length of constant array
178 return true;
179 } else if (method != null &&
180 (method.binding == MemberBinding.STATIC || prototype_access)) {
181 return true;
182 } else {
183 return false;
187 public override bool is_non_null () {
188 var c = symbol_reference as Constant;
189 if (c != null) {
190 return (c is EnumValue || !c.type_reference.nullable);
191 } else {
192 return false;
196 public override bool check (CodeContext context) {
197 if (checked) {
198 return !error;
201 checked = true;
203 if (inner != null) {
204 inner.check (context);
207 foreach (DataType type_arg in type_argument_list) {
208 type_arg.check (context);
211 Symbol base_symbol = null;
212 Parameter this_parameter = null;
213 bool may_access_instance_members = false;
214 bool may_access_klass_members = false;
216 symbol_reference = null;
218 if (qualified) {
219 base_symbol = context.root;
220 symbol_reference = base_symbol.scope.lookup (member_name);
221 } else if (inner == null) {
222 if (member_name == "this") {
223 if (!context.analyzer.is_in_instance_method ()) {
224 error = true;
225 Report.error (source_reference, "This access invalid outside of instance methods");
226 return false;
230 base_symbol = context.analyzer.current_symbol;
232 // track whether method has been found to make sure that access
233 // to instance member is denied from within static lambda expressions
234 bool method_found = false;
236 var sym = context.analyzer.current_symbol;
237 while (sym != null && symbol_reference == null) {
238 if (!method_found) {
239 if (sym is CreationMethod) {
240 var cm = (CreationMethod) sym;
241 this_parameter = cm.this_parameter;
242 may_access_instance_members = true;
243 may_access_klass_members = true;
244 method_found = true;
245 } else if (sym is Property) {
246 var prop = (Property) sym;
247 this_parameter = prop.this_parameter;
248 may_access_instance_members = (prop.binding == MemberBinding.INSTANCE);
249 may_access_klass_members = (prop.binding != MemberBinding.STATIC);
250 method_found = true;
251 } else if (sym is Constructor) {
252 var c = (Constructor) sym;
253 this_parameter = c.this_parameter;
254 may_access_instance_members = (c.binding == MemberBinding.INSTANCE);
255 may_access_klass_members = true;
256 method_found = true;
257 } else if (sym is Destructor) {
258 var d = (Destructor) sym;
259 this_parameter = d.this_parameter;
260 may_access_instance_members = (d.binding == MemberBinding.INSTANCE);
261 may_access_klass_members = true;
262 method_found = true;
263 } else if (sym is Method) {
264 var m = (Method) sym;
265 this_parameter = m.this_parameter;
266 may_access_instance_members = (m.binding == MemberBinding.INSTANCE);
267 may_access_klass_members = (m.binding != MemberBinding.STATIC);
268 method_found = true;
272 symbol_reference = SemanticAnalyzer.symbol_lookup_inherited (sym, member_name);
274 if (symbol_reference == null && sym is TypeSymbol && may_access_instance_members) {
275 // used for generated to_string methods in enums
276 symbol_reference = this_parameter.variable_type.get_member (member_name);
278 if (symbol_reference != null && is_instance_symbol (symbol_reference)) {
279 // implicit this
280 inner = new MemberAccess (null, "this", source_reference);
281 inner.value_type = this_parameter.variable_type.copy ();
282 inner.value_type.value_owned = false;
283 inner.symbol_reference = this_parameter;
285 symbol_reference = inner.value_type.get_member (member_name);
289 if (symbol_reference == null) {
290 if (sym is TypeSymbol) {
291 // do not allow instance access to outer classes
292 this_parameter = null;
293 may_access_instance_members = false;
294 may_access_klass_members = false;
298 sym = sym.parent_symbol;
301 if (symbol_reference == null && source_reference != null) {
302 foreach (UsingDirective ns in source_reference.using_directives) {
303 var local_sym = ns.namespace_symbol.scope.lookup (member_name);
304 if (local_sym != null) {
305 if (symbol_reference != null && symbol_reference != local_sym) {
306 error = true;
307 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 ()));
308 return false;
310 symbol_reference = local_sym;
314 } else {
315 if (inner.error) {
316 /* if there was an error in the inner expression, skip this check */
317 error = true;
318 return false;
321 if (inner.value_type is PointerType) {
322 var pointer_type = inner.value_type as PointerType;
323 if (pointer_type != null && pointer_type.base_type is ValueType) {
324 // transform foo->bar to (*foo).bar
325 inner = new PointerIndirection (inner, source_reference);
326 inner.check (context);
327 pointer_member_access = false;
331 if (inner is MemberAccess) {
332 var ma = (MemberAccess) inner;
333 if (ma.prototype_access) {
334 error = true;
335 Report.error (source_reference, "Access to instance member `%s' denied".printf (inner.symbol_reference.get_full_name ()));
336 return false;
340 if (inner is MemberAccess || inner is BaseAccess) {
341 base_symbol = inner.symbol_reference;
343 if (symbol_reference == null && (base_symbol is Namespace || base_symbol is TypeSymbol)) {
344 symbol_reference = base_symbol.scope.lookup (member_name);
345 if (inner is BaseAccess) {
346 // inner expression is base access
347 // access to instance members of the base type possible
348 may_access_instance_members = true;
349 may_access_klass_members = true;
354 if (symbol_reference == null && inner.value_type != null) {
355 if (pointer_member_access) {
356 symbol_reference = inner.value_type.get_pointer_member (member_name);
357 } else {
358 if (inner.value_type.data_type != null) {
359 base_symbol = inner.value_type.data_type;
361 symbol_reference = inner.value_type.get_member (member_name);
363 if (symbol_reference != null) {
364 // inner expression is variable, field, or parameter
365 // access to instance members of the corresponding type possible
366 may_access_instance_members = true;
367 may_access_klass_members = true;
371 if (symbol_reference == null && inner.value_type != null && inner.value_type.is_dynamic) {
372 // allow late bound members for dynamic types
373 var dynamic_object_type = (ObjectType) inner.value_type;
374 if (parent_node is MethodCall) {
375 var invoc = (MethodCall) parent_node;
376 if (invoc.call == this) {
377 // dynamic method
378 DataType ret_type;
379 if (invoc.target_type != null) {
380 ret_type = invoc.target_type.copy ();
381 ret_type.value_owned = true;
382 } else if (invoc.parent_node is ExpressionStatement) {
383 ret_type = new VoidType ();
384 } else {
385 // expect dynamic object of the same type
386 ret_type = inner.value_type.copy ();
388 var m = new DynamicMethod (inner.value_type, member_name, ret_type, source_reference);
389 m.invocation = invoc;
390 var err = new ErrorType (null, null);
391 err.dynamic_error = true;
392 m.add_error_type (err);
393 m.access = SymbolAccessibility.PUBLIC;
394 m.add_parameter (new Parameter.with_ellipsis ());
395 dynamic_object_type.type_symbol.scope.add (null, m);
396 symbol_reference = m;
398 } else if (parent_node is Assignment) {
399 var a = (Assignment) parent_node;
400 if (a.left == this
401 && (a.operator == AssignmentOperator.ADD
402 || a.operator == AssignmentOperator.SUB)) {
403 // dynamic signal
404 var s = new DynamicSignal (inner.value_type, member_name, new VoidType (), source_reference);
405 s.handler = a.right;
406 s.access = SymbolAccessibility.PUBLIC;
407 dynamic_object_type.type_symbol.scope.add (null, s);
408 symbol_reference = s;
409 } else if (a.left == this) {
410 // dynamic property assignment
411 var prop = new DynamicProperty (inner.value_type, member_name, source_reference);
412 prop.access = SymbolAccessibility.PUBLIC;
413 prop.set_accessor = new PropertyAccessor (false, true, false, null, null, prop.source_reference);
414 prop.owner = inner.value_type.data_type.scope;
415 dynamic_object_type.type_symbol.scope.add (null, prop);
416 symbol_reference = prop;
418 } else if (parent_node is MemberAccess && inner is MemberAccess && parent_node.parent_node is MethodCall) {
419 var ma = (MemberAccess) parent_node;
420 if (ma.member_name == "connect" || ma.member_name == "connect_after") {
421 // dynamic signal
422 var s = new DynamicSignal (inner.value_type, member_name, new VoidType (), source_reference);
423 var mcall = (MethodCall) parent_node.parent_node;
424 // the first argument is the handler
425 if (mcall.get_argument_list().size > 0) {
426 s.handler = mcall.get_argument_list()[0];
428 s.access = SymbolAccessibility.PUBLIC;
429 dynamic_object_type.type_symbol.scope.add (null, s);
430 symbol_reference = s;
433 if (symbol_reference == null) {
434 // dynamic property read access
435 var prop = new DynamicProperty (inner.value_type, member_name, source_reference);
436 if (target_type != null) {
437 prop.property_type = target_type;
438 } else {
439 // expect dynamic object of the same type
440 prop.property_type = inner.value_type.copy ();
442 prop.access = SymbolAccessibility.PUBLIC;
443 prop.get_accessor = new PropertyAccessor (true, false, false, prop.property_type.copy (), null, prop.source_reference);
444 prop.owner = inner.value_type.data_type.scope;
445 dynamic_object_type.type_symbol.scope.add (null, prop);
446 symbol_reference = prop;
448 if (symbol_reference != null) {
449 may_access_instance_members = true;
450 may_access_klass_members = true;
455 // enum-type inference
456 if (symbol_reference == null && target_type != null && target_type.data_type is Enum) {
457 var enum_type = (Enum) target_type.data_type;
458 foreach (var val in enum_type.get_values ()) {
459 if (member_name == val.name) {
460 symbol_reference = val;
461 break;
466 if (symbol_reference == null) {
467 error = true;
469 string base_type_name = "(null)";
470 if (inner != null && inner.value_type != null) {
471 base_type_name = inner.value_type.to_string ();
472 } else if (base_symbol != null) {
473 base_type_name = base_symbol.get_full_name ();
476 Report.error (source_reference, "The name `%s' does not exist in the context of `%s'".printf (member_name, base_type_name));
477 return false;
480 var member = symbol_reference;
481 var access = SymbolAccessibility.PUBLIC;
482 bool instance = false;
483 bool klass = false;
484 bool generics = false;
486 if (!member.check (context)) {
487 return false;
490 if (member is LocalVariable) {
491 var local = (LocalVariable) member;
492 var block = local.parent_symbol as Block;
493 if (block != null && context.analyzer.find_parent_method_or_property_accessor (block) != context.analyzer.current_method_or_property_accessor) {
494 // mark all methods between current method and the captured
495 // block as closures (to support nested closures)
496 Symbol sym = context.analyzer.current_method_or_property_accessor;
497 while (sym != block) {
498 var method = sym as Method;
499 if (method != null) {
500 method.closure = true;
501 // consider captured variables as used
502 // as we require captured variables to be initialized
503 method.add_captured_variable (local);
505 sym = sym.parent_symbol;
508 local.captured = true;
509 block.captured = true;
511 } else if (member is Parameter) {
512 var param = (Parameter) member;
513 var m = param.parent_symbol as Method;
514 if (m != null && m != context.analyzer.current_method_or_property_accessor && param != m.this_parameter) {
515 // mark all methods between current method and the captured
516 // parameter as closures (to support nested closures)
517 Symbol sym = context.analyzer.current_method_or_property_accessor;
518 while (sym != m) {
519 var method = sym as Method;
520 if (method != null) {
521 method.closure = true;
523 sym = sym.parent_symbol;
526 param.captured = true;
527 m.body.captured = true;
529 if (param.direction != ParameterDirection.IN) {
530 error = true;
531 Report.error (source_reference, "Cannot capture reference or output parameter `%s'".printf (param.get_full_name ()));
533 } else {
534 var acc = param.parent_symbol.parent_symbol as PropertyAccessor;
535 if (acc != null && acc != context.analyzer.current_method_or_property_accessor && param != acc.prop.this_parameter) {
536 // mark all methods between current method and the captured
537 // parameter as closures (to support nested closures)
538 Symbol sym = context.analyzer.current_method_or_property_accessor;
539 while (sym != m) {
540 var method = sym as Method;
541 if (method != null) {
542 method.closure = true;
544 sym = sym.parent_symbol;
547 param.captured = true;
548 acc.body.captured = true;
551 } else if (member is Field) {
552 var f = (Field) member;
553 access = f.access;
554 instance = (f.binding == MemberBinding.INSTANCE);
555 klass = (f.binding == MemberBinding.CLASS);
557 // do not allow access to fields of generic types
558 // if instance type does not specify type arguments
559 if (f.variable_type is GenericType) {
560 generics = true;
562 } else if (member is Constant) {
563 var c = (Constant) member;
564 access = c.access;
566 var block = c.parent_symbol as Block;
567 if (block != null && context.analyzer.find_parent_method_or_property_accessor (block) != context.analyzer.current_method_or_property_accessor) {
568 error = true;
569 Report.error (source_reference, "internal error: accessing local constants of outer methods is not supported yet");
570 return false;
572 } else if (member is Method) {
573 var m = (Method) member;
574 if (m.is_async_callback) {
575 // ensure to use right callback method for virtual/abstract async methods
576 // and also for lambda expressions within async methods
577 var async_method = context.analyzer.current_async_method;
579 bool is_valid_access = false;
580 if (async_method != null) {
581 if (m == async_method.get_callback_method ()) {
582 is_valid_access = true;
583 } else if (async_method.base_method != null && m == async_method.base_method.get_callback_method ()) {
584 is_valid_access = true;
585 } else if (async_method.base_interface_method != null && m == async_method.base_interface_method.get_callback_method ()) {
586 is_valid_access = true;
589 if (!is_valid_access) {
590 error = true;
591 Report.error (source_reference, "Access to async callback `%s' not allowed in this context".printf (m.get_full_name ()));
592 return false;
595 if (async_method != context.analyzer.current_method) {
596 Symbol sym = context.analyzer.current_method;
597 while (sym != async_method) {
598 var method = sym as Method;
599 if (method != null) {
600 method.closure = true;
602 sym = sym.parent_symbol;
604 async_method.body.captured = true;
607 m = async_method.get_callback_method ();
608 symbol_reference = m;
609 member = symbol_reference;
610 } else if (m.base_method != null) {
611 // refer to base method to inherit default arguments
612 m = m.base_method;
614 if (m.signal_reference != null) {
615 // method is class/default handler for a signal
616 // let signal deal with member access
617 symbol_reference = m.signal_reference;
618 } else {
619 symbol_reference = m;
622 member = symbol_reference;
623 } else if (m.base_interface_method != null) {
624 // refer to base method to inherit default arguments
625 m = m.base_interface_method;
627 if (m.signal_reference != null) {
628 // method is class/default handler for a signal
629 // let signal deal with member access
630 symbol_reference = m.signal_reference;
631 } else {
632 symbol_reference = m;
635 member = symbol_reference;
637 access = m.access;
638 if (!(m is CreationMethod)) {
639 instance = (m.binding == MemberBinding.INSTANCE);
641 klass = (m.binding == MemberBinding.CLASS);
643 // do not allow access to methods using generic type parameters
644 // if instance type does not specify type arguments
645 foreach (var param in m.get_parameters ()) {
646 var generic_type = param.variable_type as GenericType;
647 if (generic_type != null && generic_type.type_parameter.parent_symbol is TypeSymbol) {
648 generics = true;
649 break;
652 var generic_type = m.return_type as GenericType;
653 if (generic_type != null && generic_type.type_parameter.parent_symbol is TypeSymbol) {
654 generics = true;
656 } else if (member is Property) {
657 var prop = (Property) member;
658 if (!prop.check (context)) {
659 error = true;
660 return false;
662 if (prop.base_property != null) {
663 // refer to base property
664 prop = prop.base_property;
665 symbol_reference = prop;
666 member = symbol_reference;
667 } else if (prop.base_interface_property != null) {
668 // refer to base property
669 prop = prop.base_interface_property;
670 symbol_reference = prop;
671 member = symbol_reference;
673 access = prop.access;
674 if (lvalue) {
675 if (prop.set_accessor == null) {
676 error = true;
677 Report.error (source_reference, "Property `%s' is read-only".printf (prop.get_full_name ()));
678 return false;
680 if (prop.access == SymbolAccessibility.PUBLIC) {
681 access = prop.set_accessor.access;
682 } else if (prop.access == SymbolAccessibility.PROTECTED
683 && prop.set_accessor.access != SymbolAccessibility.PUBLIC) {
684 access = prop.set_accessor.access;
686 } else {
687 if (prop.get_accessor == null) {
688 error = true;
689 Report.error (source_reference, "Property `%s' is write-only".printf (prop.get_full_name ()));
690 return false;
692 if (prop.access == SymbolAccessibility.PUBLIC) {
693 access = prop.get_accessor.access;
694 } else if (prop.access == SymbolAccessibility.PROTECTED
695 && prop.get_accessor.access != SymbolAccessibility.PUBLIC) {
696 access = prop.get_accessor.access;
699 instance = (prop.binding == MemberBinding.INSTANCE);
701 // do not allow access to properties of generic types
702 // if instance type does not specify type arguments
703 if (prop.property_type is GenericType) {
704 generics = true;
706 } else if (member is Signal) {
707 instance = true;
708 access = member.access;
711 member.used = true;
712 member.version.check (source_reference);
714 if (access == SymbolAccessibility.PROTECTED) {
715 var target_type = (TypeSymbol) member.parent_symbol;
717 bool in_subtype = false;
718 for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) {
719 if (this_symbol == target_type) {
720 // required for interfaces with non-abstract methods
721 // accessing protected interface members
722 in_subtype = true;
723 break;
726 var cl = this_symbol as Class;
727 if (cl != null && cl.is_subtype_of (target_type)) {
728 in_subtype = true;
729 break;
733 if (!in_subtype) {
734 error = true;
735 Report.error (source_reference, "Access to protected member `%s' denied".printf (member.get_full_name ()));
736 return false;
738 } else if (access == SymbolAccessibility.PRIVATE) {
739 var target_type = member.parent_symbol;
741 bool in_target_type = false;
742 for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) {
743 if (target_type == this_symbol) {
744 in_target_type = true;
745 break;
749 if (!in_target_type) {
750 error = true;
751 Report.error (source_reference, "Access to private member `%s' denied".printf (member.get_full_name ()));
752 return false;
756 if (generics && inner != null) {
757 var instance_type = inner.value_type;
758 var pointer_type = inner.value_type as PointerType;
759 if (pointer_type != null) {
760 instance_type = pointer_type.base_type;
763 // instance type might be a subtype of the parent symbol of the member
764 // that subtype might not be generic, so do not report an error in that case
765 var object_type = instance_type as ObjectType;
766 if (object_type != null && object_type.type_symbol.get_type_parameters ().size > 0 &&
767 instance_type.get_type_arguments ().size == 0) {
768 error = true;
769 Report.error (inner.source_reference, "missing generic type arguments");
770 return false;
774 if ((instance && !may_access_instance_members) ||
775 (klass && !may_access_klass_members)) {
776 prototype_access = true;
778 if (symbol_reference is Method) {
779 // also set static type for prototype access
780 // required when using instance methods as delegates in constants
781 // TODO replace by MethodPrototype
782 value_type = context.analyzer.get_value_type_for_symbol (symbol_reference, lvalue);
783 } else if (symbol_reference is Field) {
784 value_type = new FieldPrototype ((Field) symbol_reference);
785 } else {
786 value_type = new InvalidType ();
789 if (target_type != null) {
790 value_type.value_owned = target_type.value_owned;
792 } else {
793 // implicit this access
794 if (instance && inner == null) {
795 inner = new MemberAccess (null, "this", source_reference);
796 inner.value_type = this_parameter.variable_type.copy ();
797 inner.value_type.value_owned = false;
798 inner.symbol_reference = this_parameter;
799 } else {
800 check_lvalue_access ();
803 if (!instance && !klass && !(symbol_reference is CreationMethod) && may_access_instance_members && inner != null) {
804 if (inner.symbol_reference is Method) {
805 // do not warn when calling .begin or .end on static async method
806 } else {
807 Report.warning (source_reference, "Access to static member `%s' with an instance reference".printf (symbol_reference.get_full_name ()));
811 if (context.experimental_non_null && instance && inner.value_type.nullable &&
812 !(inner.value_type is PointerType) && !(inner.value_type is GenericType) &&
813 !(inner.value_type is ArrayType)) {
814 Report.error (source_reference, "Access to instance member `%s' from nullable reference denied".printf (symbol_reference.get_full_name ()));
817 var m = symbol_reference as Method;
818 var inner_ma = inner as MemberAccess;
819 if (m != null && m.binding == MemberBinding.STATIC && m.parent_symbol is ObjectTypeSymbol &&
820 inner != null && inner.value_type == null && inner_ma.type_argument_list.size > 0) {
821 // support static methods in generic classes
822 inner.value_type = new ObjectType ((ObjectTypeSymbol) m.parent_symbol);
824 foreach (var type_argument in inner_ma.type_argument_list) {
825 inner.value_type.add_type_argument (type_argument);
829 formal_value_type = context.analyzer.get_value_type_for_symbol (symbol_reference, lvalue);
830 if (inner != null && formal_value_type != null) {
831 value_type = formal_value_type.get_actual_type (inner.value_type, null, this);
832 } else {
833 value_type = formal_value_type;
836 if (symbol_reference is Method) {
837 var method = (Method) symbol_reference;
838 if (target_type != null) {
839 value_type.value_owned = target_type.value_owned;
841 if (instance && method.parent_symbol is TypeSymbol) {
842 inner.target_type = SemanticAnalyzer.get_data_type_for_symbol (method.parent_symbol);
843 inner.target_type.value_owned = method.this_parameter.variable_type.value_owned;
845 } else if (symbol_reference is Property) {
846 var prop = (Property) symbol_reference;
847 if (instance && prop.parent_symbol != null) {
848 inner.target_type = SemanticAnalyzer.get_data_type_for_symbol (prop.parent_symbol);
850 } else if ((symbol_reference is Field
851 || symbol_reference is Signal)
852 && instance && symbol_reference.parent_symbol != null) {
853 var parent_type = SemanticAnalyzer.get_data_type_for_symbol (symbol_reference.parent_symbol);
854 inner.target_type = parent_type.get_actual_type (inner.value_type, null, this);
858 return !error;
861 static bool is_instance_symbol (Symbol symbol) {
862 if (symbol is Field && ((Field) symbol).binding == MemberBinding.INSTANCE) {
863 return true;
864 } else if (symbol is Method && !(symbol is CreationMethod) && ((Method) symbol).binding == MemberBinding.INSTANCE) {
865 return true;
866 } else if (symbol is Property && ((Property) symbol).binding == MemberBinding.INSTANCE) {
867 return true;
868 } else if (symbol is Signal) {
869 return true;
870 } else {
871 return false;
875 public void check_lvalue_access () {
876 if (inner == null) {
877 return;
879 var instance = symbol_reference is Field && ((Field) symbol_reference).binding == MemberBinding.INSTANCE;
880 if (!instance) {
881 instance = symbol_reference is Method && ((Method) symbol_reference).binding == MemberBinding.INSTANCE;
883 if (!instance) {
884 instance = symbol_reference is Property && ((Property) symbol_reference).binding == MemberBinding.INSTANCE;
887 var this_access = inner.symbol_reference is Parameter && inner.symbol_reference.name == "this";
888 var struct_or_array = (inner.value_type is StructValueType && !inner.value_type.nullable) || (CodeContext.get ().profile == Profile.GOBJECT && inner.value_type is ArrayType);
890 var ma = inner as MemberAccess;
891 if (ma == null && struct_or_array && inner is PointerIndirection) {
892 // (*struct)->method()
893 ma = ((PointerIndirection) inner).inner as MemberAccess;
896 if (instance && struct_or_array && (symbol_reference is Method || lvalue) && ((ma != null && ma.symbol_reference is Variable) || inner is ElementAccess) && !this_access) {
897 inner.lvalue = true;
898 if (ma != null) {
899 ma.lvalue = true;
900 ma.check_lvalue_access ();
905 public override void emit (CodeGenerator codegen) {
906 if (inner != null) {
907 inner.emit (codegen);
910 codegen.visit_member_access (this);
912 codegen.visit_expression (this);
915 public override void get_defined_variables (Collection<Variable> collection) {
916 if (inner != null) {
917 inner.get_defined_variables (collection);
921 public override void get_used_variables (Collection<Variable> collection) {
922 if (inner != null) {
923 inner.get_used_variables (collection);
925 var local = symbol_reference as LocalVariable;
926 var param = symbol_reference as Parameter;
927 if (local != null) {
928 collection.add (local);
929 } else if (param != null && param.direction == ParameterDirection.OUT) {
930 collection.add (param);