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
20 * Jürg Billeter <j@bitron.ch>
26 * Represents an access to a type member in the source code.
28 public class Vala
.MemberAccess
: Expression
{
30 * The parent of the member.
32 public Expression? inner
{
39 _inner
.parent_node
= this
;
45 * The name of the member.
47 public string member_name
{ get; set; }
50 * Pointer member access.
52 public bool pointer_member_access
{ get; set; }
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; }
61 * Specifies whether the member is used for object creation.
63 public bool creation_member
{ get; set; }
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
> ();
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) {
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) {
94 this
.member_name
= member_name
;
95 this
.source_reference
= source_reference
;
96 pointer_member_access
= true;
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
) {
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 ()) {
139 return "%s.%s".printf (inner
.to_string (), member_name
);
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
) {
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
;
172 public override bool is_constant () {
173 var method
= symbol_reference as Method
;
174 if (symbol_reference is Constant
) {
176 } else if (symbol_reference is ArrayLengthField
&& inner
!= null && inner
.symbol_reference is Constant
) {
177 // length of constant array
179 } else if (method
!= null &&
180 (method
.binding
== MemberBinding
.STATIC
|| prototype_access
)) {
187 public override bool is_non_null () {
188 var c
= symbol_reference as Constant
;
190 return (c is EnumValue
|| !c
.type_reference
.nullable
);
196 public override bool check (CodeContext context
) {
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;
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 ()) {
225 Report
.error (source_reference
, "This access invalid outside of instance methods");
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) {
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;
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
);
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;
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;
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
);
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
)) {
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
) {
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 ()));
310 symbol_reference
= local_sym
;
316 /* if there was an error in the inner expression, skip this check */
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
) {
335 Report
.error (source_reference
, "Access to instance member `%s' denied".printf (inner
.symbol_reference
.get_full_name ()));
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
);
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
) {
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 ();
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
;
401 && (a
.operator
== AssignmentOperator
.ADD
402 || a
.operator
== AssignmentOperator
.SUB
)) {
404 var s
= new
DynamicSignal (inner
.value_type
, member_name
, new
VoidType (), source_reference
);
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") {
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
;
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
;
466 if (symbol_reference
== null) {
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
));
480 var member
= symbol_reference
;
481 var access
= SymbolAccessibility
.PUBLIC
;
482 bool instance
= false;
484 bool generics
= false;
486 if (!member
.check (context
)) {
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
;
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
) {
531 Report
.error (source_reference
, "Cannot capture reference or output parameter `%s'".printf (param
.get_full_name ()));
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
;
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
;
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
) {
562 } else if (member is Constant
) {
563 var c
= (Constant
) member
;
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
) {
569 Report
.error (source_reference
, "internal error: accessing local constants of outer methods is not supported yet");
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
) {
591 Report
.error (source_reference
, "Access to async callback `%s' not allowed in this context".printf (m
.get_full_name ()));
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
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
;
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
;
632 symbol_reference
= m
;
635 member
= symbol_reference
;
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
) {
652 var generic_type
= m
.return_type as GenericType
;
653 if (generic_type
!= null && generic_type
.type_parameter
.parent_symbol is TypeSymbol
) {
656 } else if (member is Property
) {
657 var prop
= (Property
) member
;
658 if (!prop
.check (context
)) {
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
;
675 if (prop
.set_accessor
== null) {
677 Report
.error (source_reference
, "Property `%s' is read-only".printf (prop
.get_full_name ()));
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
;
687 if (prop
.get_accessor
== null) {
689 Report
.error (source_reference
, "Property `%s' is write-only".printf (prop
.get_full_name ()));
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
) {
706 } else if (member is Signal
) {
708 access
= member
.access
;
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
726 var cl
= this_symbol as Class
;
727 if (cl
!= null && cl
.is_subtype_of (target_type
)) {
735 Report
.error (source_reference
, "Access to protected member `%s' denied".printf (member
.get_full_name ()));
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;
749 if (!in_target_type
) {
751 Report
.error (source_reference
, "Access to private member `%s' denied".printf (member
.get_full_name ()));
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) {
769 Report
.error (inner
.source_reference
, "missing generic type arguments");
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
);
786 value_type
= new
InvalidType ();
789 if (target_type
!= null) {
790 value_type
.value_owned
= target_type
.value_owned
;
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
;
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
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
);
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
);
861 static bool is_instance_symbol (Symbol symbol
) {
862 if (symbol is Field
&& ((Field
) symbol
).binding
== MemberBinding
.INSTANCE
) {
864 } else if (symbol is Method
&& !(symbol is CreationMethod
) && ((Method
) symbol
).binding
== MemberBinding
.INSTANCE
) {
866 } else if (symbol is Property
&& ((Property
) symbol
).binding
== MemberBinding
.INSTANCE
) {
868 } else if (symbol is Signal
) {
875 public void check_lvalue_access () {
879 var instance
= symbol_reference is Field
&& ((Field
) symbol_reference
).binding
== MemberBinding
.INSTANCE
;
881 instance
= symbol_reference is Method
&& ((Method
) symbol_reference
).binding
== MemberBinding
.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
) {
900 ma
.check_lvalue_access ();
905 public override void emit (CodeGenerator codegen
) {
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
) {
917 inner
.get_defined_variables (collection
);
921 public override void get_used_variables (Collection
<Variable
> collection
) {
923 inner
.get_used_variables (collection
);
925 var local
= symbol_reference as LocalVariable
;
926 var param
= symbol_reference as Parameter
;
928 collection
.add (local
);
929 } else if (param
!= null && param
.direction
== ParameterDirection
.OUT
) {
930 collection
.add (param
);