LCOV - code coverage report
Current view: top level - vala - valamemberaccess.vala (source / functions) Coverage Total Hit
Test: vala 0.57.0.298-a8cae1 Lines: 96.6 % 765 739
Test Date: 2024-04-25 11:34:36 Functions: - 0 0

            Line data    Source code
       1              : /* valamemberaccess.vala
       2              :  *
       3              :  * Copyright (C) 2006-2012  Jürg Billeter
       4              :  *
       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.
       9              : 
      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.
      14              : 
      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
      18              :  *
      19              :  * Author:
      20              :  *      Jürg Billeter <j@bitron.ch>
      21              :  */
      22              : 
      23              : using GLib;
      24              : 
      25              : /**
      26              :  * Represents an access to a type member in the source code.
      27              :  */
      28      3896696 : public class Vala.MemberAccess : Expression {
      29              :         /**
      30              :          * The parent of the member.
      31              :          */
      32              :         public Expression? inner {
      33     38560437 :                 get {
      34     38560437 :                         return _inner;
      35              :                 }
      36      2008747 :                 set {
      37      2241149 :                         _inner = value;
      38      2008747 :                         if (_inner != null) {
      39       499258 :                                 _inner.parent_node = this;
      40              :                         }
      41              :                 }
      42              :         }
      43              : 
      44              :         /**
      45              :          * The name of the member.
      46              :          */
      47      6283445 :         public string member_name { get; set; }
      48              : 
      49              :         /**
      50              :          * Pointer member access.
      51              :          */
      52         2967 :         public bool pointer_member_access { get; set; }
      53              : 
      54              :         /**
      55              :          * Represents access to an instance member without an actual instance,
      56              :          * e.g. `MyClass.an_instance_method`.
      57              :          */
      58       541586 :         public bool prototype_access { get; set; }
      59              : 
      60              :         /**
      61              :          * Requires indirect access due to possible side-effects of parent expression.
      62              :          */
      63      1765454 :         public bool tainted_access { get; set; }
      64              : 
      65              :         /**
      66              :          * Qualified access to global symbol.
      67              :          */
      68      1129210 :         public bool qualified { get; set; }
      69              : 
      70              :         /**
      71              :          * Null-safe access.
      72              :          */
      73       610067 :         public bool null_safe_access { get; set; }
      74              : 
      75      1947579 :         private Expression? _inner;
      76      3895158 :         private List<DataType> type_argument_list = new ArrayList<DataType> ();
      77              :         bool is_with_variable_access;
      78              : 
      79              :         /**
      80              :          * Creates a new member access expression.
      81              :          *
      82              :          * @param inner            parent of the member
      83              :          * @param member_name      member name
      84              :          * @param source_reference reference to source code
      85              :          * @return                 newly created member access expression
      86              :          */
      87      5192142 :         public MemberAccess (Expression? inner, string member_name, SourceReference? source_reference = null) {
      88      1730714 :                 this.inner = inner;
      89      1730714 :                 this.member_name = member_name;
      90      1730714 :                 this.source_reference = source_reference;
      91              :         }
      92              : 
      93       645981 :         public MemberAccess.simple (string member_name, SourceReference? source_reference = null) {
      94       215327 :                 this.inner = null;
      95       215327 :                 this.member_name = member_name;
      96       215327 :                 this.source_reference = source_reference;
      97              :         }
      98              : 
      99         4614 :         public MemberAccess.pointer (Expression inner, string member_name, SourceReference? source_reference = null) {
     100         1538 :                 this.inner = inner;
     101         1538 :                 this.member_name = member_name;
     102         1538 :                 this.source_reference = source_reference;
     103         1538 :                 pointer_member_access = true;
     104              :         }
     105              : 
     106              :         /**
     107              :          * Appends the specified type as generic type argument.
     108              :          *
     109              :          * @param arg a type reference
     110              :          */
     111         2182 :         public void add_type_argument (DataType arg) {
     112         2182 :                 type_argument_list.add (arg);
     113         2182 :                 arg.parent_node = this;
     114              :         }
     115              : 
     116              :         /**
     117              :          * Returns the list of generic type arguments.
     118              :          *
     119              :          * @return type argument list
     120              :          */
     121       416050 :         public unowned List<DataType> get_type_arguments () {
     122       416050 :                 return type_argument_list;
     123              :         }
     124              : 
     125      6567312 :         public override void accept (CodeVisitor visitor) {
     126      6567312 :                 visitor.visit_member_access (this);
     127              : 
     128      6567312 :                 visitor.visit_expression (this);
     129              :         }
     130              : 
     131      6567302 :         public override void accept_children (CodeVisitor visitor) {
     132      6567302 :                 if (inner != null) {
     133      1663126 :                         inner.accept (visitor);
     134              :                 }
     135              : 
     136      6584886 :                 foreach (DataType type_arg in type_argument_list) {
     137         8792 :                         type_arg.accept (visitor);
     138              :                 }
     139              :         }
     140              : 
     141         8163 :         public override string to_string () {
     142         8163 :                 if (symbol_reference == null || symbol_reference.is_instance_member ()) {
     143         7906 :                         if (inner == null) {
     144         6880 :                                 return member_name;
     145              :                         } else {
     146         4466 :                                 return "%s%s%s".printf (inner.to_string (), pointer_member_access ? "->" : ".", member_name);
     147              :                         }
     148              :                 } else {
     149              :                         // ensure to always use fully-qualified name
     150              :                         // to refer to static members
     151          257 :                         return symbol_reference.get_full_name ();
     152              :                 }
     153              :         }
     154              : 
     155           59 :         public override void replace_expression (Expression old_node, Expression new_node) {
     156           59 :                 if (inner == old_node) {
     157           59 :                         inner = new_node;
     158              :                 }
     159              :         }
     160              : 
     161            0 :         public override bool is_pure () {
     162              :                 // accessing property could have side-effects
     163            0 :                 return (inner == null || inner.is_pure ()) && !(symbol_reference is Property);
     164              :         }
     165              : 
     166       304203 :         public override bool is_accessible (Symbol sym) {
     167       304203 :                 return (inner == null || inner.is_accessible (sym)) && symbol_reference.is_accessible (sym);
     168              :         }
     169              : 
     170          542 :         public override void replace_type (DataType old_type, DataType new_type) {
     171          648 :                 for (int i = 0; i < type_argument_list.size; i++) {
     172          648 :                         if (type_argument_list[i] == old_type) {
     173          542 :                                 type_argument_list[i] = new_type;
     174          542 :                                 return;
     175              :                         }
     176              :                 }
     177              :         }
     178              : 
     179        14132 :         public override bool is_constant () {
     180        14132 :                 unowned Method? method = symbol_reference as Method;
     181        14132 :                 if (symbol_reference is Constant) {
     182        13583 :                         return true;
     183          559 :                 } else if (symbol_reference is ArrayLengthField && inner != null && inner.symbol_reference is Constant) {
     184              :                         // length of constant array
     185        13583 :                         return true;
     186          559 :                 } else if (method != null &&
     187           10 :                            (method.binding == MemberBinding.STATIC || prototype_access)) {
     188        13583 :                         return true;
     189              :                 } else {
     190          549 :                         return false;
     191              :                 }
     192              :         }
     193              : 
     194       101633 :         public override bool is_non_null () {
     195       101633 :                 unowned Constant? c = symbol_reference as Constant;
     196       101633 :                 unowned LocalVariable? l = symbol_reference as LocalVariable;
     197       101633 :                 unowned Method? m = symbol_reference as Method;
     198       101633 :                 if (c != null) {
     199          222 :                         return (c is EnumValue || !c.type_reference.nullable);
     200       101411 :                 } else if (l != null) {
     201        24698 :                         unowned DataType type = l.variable_type;
     202        24698 :                         if (type is ArrayType) {
     203         1606 :                                 return ((ArrayType) type).inline_allocated;
     204              :                         } else {
     205        23092 :                                 return type.is_real_non_null_struct_type () || type.is_non_null_simple_type ();
     206              :                         }
     207        76713 :                 } else if (m != null) {
     208        29762 :                         return (m.binding == MemberBinding.STATIC || prototype_access);
     209              :                 } else {
     210       101633 :                         return false;
     211              :                 }
     212              :         }
     213              : 
     214      2372643 :         public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
     215      2372643 :                 if (inner != null) {
     216       264012 :                         inner.get_error_types (collection, source_reference);
     217              :                 }
     218              :         }
     219              : 
     220      2018018 :         public override bool check (CodeContext context) {
     221      2018018 :                 if (checked) {
     222       321898 :                         return !error;
     223              :                 }
     224              : 
     225      1696120 :                 checked = true;
     226              : 
     227      1696120 :                 if (null_safe_access) {
     228           13 :                         error = !base.check (context);
     229           13 :                         return !error;
     230              :                 }
     231              : 
     232      1696107 :                 if (inner != null) {
     233       408090 :                         inner.check (context);
     234              :                 }
     235              : 
     236      1700027 :                 foreach (DataType type_arg in type_argument_list) {
     237         1960 :                         type_arg.check (context);
     238              :                 }
     239              : 
     240      1696107 :                 unowned Symbol? base_symbol = null;
     241      1696107 :                 unowned Parameter? this_parameter = null;
     242      1696107 :                 bool may_access_instance_members = false;
     243      1696107 :                 bool may_access_klass_members = false;
     244              : 
     245      1696107 :                 var visited_types = new ArrayList<DataType> ();
     246              : 
     247      1696107 :                 symbol_reference = null;
     248              : 
     249      1696107 :                 if (qualified) {
     250         7555 :                         base_symbol = context.root;
     251         7555 :                         symbol_reference = base_symbol.scope.lookup (member_name);
     252      1688552 :                 } else if (inner == null) {
     253      1280462 :                         if (member_name == "this") {
     254       116163 :                                 if (!context.analyzer.is_in_instance_method ()) {
     255            1 :                                         error = true;
     256            1 :                                         Report.error (source_reference, "This access invalid outside of instance methods");
     257            1 :                                         return false;
     258              :                                 }
     259              :                         }
     260              : 
     261      1280461 :                         base_symbol = context.analyzer.current_symbol;
     262              : 
     263              :                         // track whether method has been found to make sure that access
     264              :                         // to instance member is denied from within static lambda expressions
     265      1280461 :                         bool method_found = false;
     266              : 
     267      1280461 :                         unowned Symbol? sym = context.analyzer.current_symbol;
     268      4746856 :                         while (sym != null && symbol_reference == null) {
     269      3466395 :                                 if (!method_found) {
     270      2764920 :                                         if (sym is CreationMethod) {
     271        13044 :                                                 unowned CreationMethod cm = (CreationMethod) sym;
     272        13044 :                                                 this_parameter = cm.this_parameter;
     273        13044 :                                                 may_access_instance_members = true;
     274        13044 :                                                 may_access_klass_members = true;
     275        13044 :                                                 method_found = true;
     276      2751876 :                                         } else if (sym is Property) {
     277        10032 :                                                 unowned Property prop = (Property) sym;
     278        10032 :                                                 this_parameter = prop.this_parameter;
     279        10032 :                                                 may_access_instance_members = (prop.binding == MemberBinding.INSTANCE);
     280        10032 :                                                 may_access_klass_members = (prop.binding != MemberBinding.STATIC);
     281        10032 :                                                 method_found = true;
     282      2741844 :                                         } else if (sym is Constructor) {
     283          120 :                                                 unowned Constructor c = (Constructor) sym;
     284          120 :                                                 this_parameter = c.this_parameter;
     285          120 :                                                 may_access_instance_members = (c.binding == MemberBinding.INSTANCE);
     286          120 :                                                 may_access_klass_members = true;
     287          120 :                                                 method_found = true;
     288      2741724 :                                         } else if (sym is Destructor) {
     289           26 :                                                 unowned Destructor d = (Destructor) sym;
     290           26 :                                                 this_parameter = d.this_parameter;
     291           26 :                                                 may_access_instance_members = (d.binding == MemberBinding.INSTANCE);
     292           26 :                                                 may_access_klass_members = true;
     293           26 :                                                 method_found = true;
     294      2741698 :                                         } else if (sym is Method) {
     295       814435 :                                                 unowned Method m = (Method) sym;
     296       814435 :                                                 this_parameter = m.this_parameter;
     297       814435 :                                                 may_access_instance_members = (m.binding == MemberBinding.INSTANCE);
     298       814435 :                                                 may_access_klass_members = (m.binding != MemberBinding.STATIC);
     299       814435 :                                                 method_found = true;
     300              :                                         }
     301              :                                 }
     302              : 
     303      3466395 :                                 symbol_reference = SemanticAnalyzer.symbol_lookup_inherited (sym, member_name);
     304              : 
     305      3466463 :                                 if (!is_with_variable_access && symbol_reference == null && sym is WithStatement) {
     306           68 :                                         unowned WithStatement w = (WithStatement) sym;
     307              : 
     308           68 :                                         var variable_type = w.with_variable.variable_type;
     309           68 :                                         if (variable_type is PointerType) {
     310            2 :                                                 variable_type = ((PointerType) variable_type).base_type;
     311              :                                         }
     312           68 :                                         visited_types.add (variable_type);
     313              : 
     314           68 :                                         symbol_reference = variable_type.get_member (member_name);
     315           68 :                                         if (symbol_reference != null) {
     316           35 :                                                 inner = new MemberAccess (null, w.with_variable.name, source_reference);
     317           35 :                                                 ((MemberAccess) inner).is_with_variable_access = true;
     318           35 :                                                 inner.check (context);
     319           35 :                                                 may_access_instance_members = true;
     320              :                                         }
     321              :                                 }
     322              : 
     323      3466395 :                                 if (symbol_reference == null && sym is TypeSymbol && may_access_instance_members) {
     324              :                                         // used for generated to_string methods in enums
     325       124609 :                                         symbol_reference = this_parameter.variable_type.get_member (member_name);
     326              : 
     327       124609 :                                         if (symbol_reference != null && is_instance_symbol (symbol_reference)) {
     328              :                                                 // implicit this
     329            1 :                                                 inner = new MemberAccess (null, "this", source_reference);
     330            1 :                                                 inner.value_type = this_parameter.variable_type.copy ();
     331            1 :                                                 inner.value_type.value_owned = false;
     332            1 :                                                 inner.symbol_reference = this_parameter;
     333              : 
     334            1 :                                                 symbol_reference = inner.value_type.get_member (member_name);
     335              :                                         }
     336              :                                 }
     337              : 
     338      3466395 :                                 if (symbol_reference == null) {
     339      2192930 :                                         if (sym is TypeSymbol) {
     340              :                                                 // do not allow instance access to outer classes
     341      3466395 :                                                 this_parameter = null;
     342      3466395 :                                                 may_access_instance_members = false;
     343      3466395 :                                                 may_access_klass_members = false;
     344              :                                         }
     345              :                                 }
     346              : 
     347      3466395 :                                 sym = sym.parent_symbol;
     348              :                         }
     349              : 
     350      1280461 :                         if (symbol_reference == null && source_reference != null) {
     351        27822 :                                 foreach (UsingDirective ns in source_reference.using_directives) {
     352        10414 :                                         if (ns.error) {
     353              :                                                 // ignore previous error
     354            0 :                                                 continue;
     355              :                                         }
     356        10414 :                                         var local_sym = ns.namespace_symbol.scope.lookup (member_name);
     357        10414 :                                         if (local_sym != null) {
     358         7549 :                                                 if (symbol_reference != null && symbol_reference != local_sym) {
     359            1 :                                                         error = true;
     360            1 :                                                         Report.error (source_reference, "`%s' is an ambiguous reference between `%s' and `%s'", member_name, symbol_reference.get_full_name (), local_sym.get_full_name ());
     361            1 :                                                         return false;
     362              :                                                 }
     363              : 
     364              :                                                 // Transform to fully qualified member access
     365         7548 :                                                 unowned Symbol? inner_sym = local_sym.parent_symbol;
     366         7548 :                                                 unowned MemberAccess? inner_ma = this;
     367        15362 :                                                 while (inner_sym != null && inner_sym.name != null) {
     368         7814 :                                                         inner_ma.inner = new MemberAccess (null, inner_sym.name, source_reference);
     369         7814 :                                                         inner_ma = (MemberAccess) inner_ma.inner;
     370         7814 :                                                         inner_sym = inner_sym.parent_symbol;
     371              :                                                 }
     372         7548 :                                                 inner_ma.qualified = true;
     373         7548 :                                                 inner.check (context);
     374              : 
     375         7548 :                                                 symbol_reference = local_sym;
     376              :                                         }
     377              :                                 }
     378              :                         }
     379              :                 } else {
     380       408090 :                         if (inner.error) {
     381              :                                 /* if there was an error in the inner expression, skip this check */
     382           12 :                                 error = true;
     383           12 :                                 return false;
     384              :                         }
     385              : 
     386       408078 :                         if (inner.value_type is PointerType) {
     387         1431 :                                 unowned PointerType? pointer_type = inner.value_type as PointerType;
     388         1431 :                                 if (pointer_type != null && pointer_type.base_type is ValueType) {
     389         1429 :                                         if (inner.formal_value_type is GenericType) {
     390            1 :                                                 inner = new CastExpression (inner, pointer_type.copy (), source_reference);
     391              :                                         }
     392              :                                         // transform foo->bar to (*foo).bar
     393         1429 :                                         inner = new PointerIndirection (inner, source_reference);
     394         1429 :                                         inner.check (context);
     395         1429 :                                         pointer_member_access = false;
     396              :                                 }
     397              :                         }
     398              : 
     399       408078 :                         if (inner.value_type is SignalType && member_name == "emit") {
     400              :                                 // transform foo.sig.emit() to foo.sig()
     401            5 :                                 parent_node.replace_expression (this, inner);
     402            5 :                                 return true;
     403              :                         }
     404              : 
     405       408073 :                         if (inner is MemberAccess) {
     406       370049 :                                 unowned MemberAccess ma = (MemberAccess) inner;
     407       370049 :                                 if (ma.prototype_access) {
     408            0 :                                         error = true;
     409            0 :                                         Report.error (source_reference, "Access to instance member `%s' denied", inner.symbol_reference.get_full_name ());
     410            0 :                                         return false;
     411              :                                 }
     412              :                         }
     413              : 
     414       408073 :                         if (inner is CastExpression && ((CastExpression) inner).is_silent_cast) {
     415            2 :                                 Report.warning (source_reference, "Access to possible `null'. Perform a check or use an unsafe cast.");
     416              :                         }
     417              : 
     418       408073 :                         if (inner is MemberAccess || inner is BaseAccess) {
     419       370177 :                                 base_symbol = inner.symbol_reference;
     420              : 
     421       370177 :                                 if (symbol_reference == null && (base_symbol is Namespace || base_symbol is TypeSymbol)) {
     422       264288 :                                         symbol_reference = base_symbol.scope.lookup (member_name);
     423       264288 :                                         if (inner is BaseAccess) {
     424              :                                                 // inner expression is base access
     425              :                                                 // access to instance members of the base type possible
     426       408073 :                                                 may_access_instance_members = true;
     427       408073 :                                                 may_access_klass_members = true;
     428              :                                         }
     429              :                                 }
     430              :                         }
     431              : 
     432       408073 :                         if (inner is MemberAccess && inner.symbol_reference is TypeParameter) {
     433           18 :                                 inner.value_type = new GenericType ((TypeParameter) inner.symbol_reference, source_reference);
     434              :                         }
     435              : 
     436       408073 :                         if (symbol_reference == null && inner.value_type != null) {
     437       143841 :                                 if (pointer_member_access) {
     438            2 :                                         symbol_reference = inner.value_type.get_pointer_member (member_name);
     439              :                                 } else {
     440       143839 :                                         if (inner.value_type.type_symbol != null) {
     441       126300 :                                                 base_symbol = inner.value_type.type_symbol;
     442              :                                         }
     443       143839 :                                         symbol_reference = inner.value_type.get_member (member_name);
     444              :                                 }
     445       143841 :                                 if (symbol_reference != null) {
     446              :                                         // inner expression is variable, field, or parameter
     447              :                                         // access to instance members of the corresponding type possible
     448       143806 :                                         may_access_instance_members = true;
     449       143806 :                                         may_access_klass_members = true;
     450              :                                 }
     451              :                         }
     452              : 
     453       408107 :                         if (symbol_reference == null && inner.value_type != null && inner.value_type.is_dynamic) {
     454              :                                 // allow late bound members for dynamic types
     455           34 :                                 var dynamic_object_type = (ObjectType) inner.value_type;
     456           34 :                                 if (parent_node is MethodCall) {
     457            1 :                                         unowned MethodCall invoc = (MethodCall) parent_node;
     458            2 :                                         if (invoc.call == this) {
     459              :                                                 // dynamic method
     460              :                                                 DataType ret_type;
     461            1 :                                                 if (invoc.target_type != null) {
     462            1 :                                                         ret_type = invoc.target_type.copy ();
     463            1 :                                                         ret_type.value_owned = true;
     464            0 :                                                 } else if (invoc.parent_node is ExpressionStatement) {
     465            0 :                                                         ret_type = new VoidType ();
     466              :                                                 } else {
     467              :                                                         // expect dynamic object of the same type
     468            0 :                                                         ret_type = inner.value_type.copy ();
     469              :                                                 }
     470            1 :                                                 var m = new DynamicMethod (inner.value_type, member_name, ret_type, source_reference);
     471            1 :                                                 m.invocation = invoc;
     472            1 :                                                 var err = new ErrorType (null, null, m.source_reference);
     473            1 :                                                 err.dynamic_error = true;
     474            1 :                                                 m.add_error_type (err);
     475            1 :                                                 m.access = SymbolAccessibility.PUBLIC;
     476            1 :                                                 m.add_parameter (new Parameter.with_ellipsis ());
     477            1 :                                                 m.this_parameter = new Parameter ("this", dynamic_object_type.copy (), m.source_reference);
     478            1 :                                                 dynamic_object_type.type_symbol.scope.add (null, m);
     479            1 :                                                 symbol_reference = m;
     480              :                                         }
     481           33 :                                 } else if (parent_node is Assignment) {
     482            5 :                                         unowned Assignment a = (Assignment) parent_node;
     483            9 :                                         if (a.left == this) {
     484              :                                                 // dynamic property assignment
     485            4 :                                                 var prop = new DynamicProperty (inner.value_type, member_name, source_reference);
     486            4 :                                                 prop.access = SymbolAccessibility.PUBLIC;
     487            4 :                                                 prop.set_accessor = new PropertyAccessor (false, true, false, null, null, prop.source_reference);
     488            4 :                                                 prop.owner = inner.value_type.type_symbol.scope;
     489            4 :                                                 dynamic_object_type.type_symbol.scope.add (null, prop);
     490            4 :                                                 symbol_reference = prop;
     491            4 :                                                 if (!dynamic_object_type.type_symbol.is_subtype_of (context.analyzer.object_type)) {
     492            1 :                                                         Report.error (source_reference, "dynamic properties are not supported for `%s'", dynamic_object_type.type_symbol.get_full_name ());
     493            1 :                                                         error = true;
     494              :                                                 }
     495              :                                         }
     496           28 :                                 } else if (parent_node is MemberAccess && inner is MemberAccess && parent_node.parent_node is MethodCall) {
     497           12 :                                         unowned MemberAccess ma = (MemberAccess) parent_node;
     498           20 :                                         if (ma.member_name == "connect" || ma.member_name == "connect_after") {
     499              :                                                 // dynamic signal
     500            8 :                                                 var s = new DynamicSignal (inner.value_type, member_name, new VoidType (), source_reference);
     501            8 :                                                 var mcall = (MethodCall) parent_node.parent_node;
     502              :                                                 // the first argument is the handler
     503            8 :                                                 if (mcall.get_argument_list().size > 0) {
     504            8 :                                                         s.handler = mcall.get_argument_list()[0];
     505            8 :                                                         unowned MemberAccess? arg = s.handler as MemberAccess;
     506            8 :                                                         if (arg == null || !arg.check (context) || !(arg.symbol_reference is Method)) {
     507            2 :                                                                 error = true;
     508            2 :                                                                 if (s.handler is LambdaExpression) {
     509            1 :                                                                         Report.error (s.handler.source_reference, "Lambdas are not allowed for dynamic signals");
     510              :                                                                 } else {
     511            1 :                                                                         Report.error (s.handler.source_reference, "Cannot infer call signature for dynamic signal `%s' from given expression", s.get_full_name ());
     512              :                                                                 }
     513              :                                                         }
     514              :                                                 }
     515            8 :                                                 s.access = SymbolAccessibility.PUBLIC;
     516            8 :                                                 dynamic_object_type.type_symbol.scope.add (null, s);
     517            8 :                                                 symbol_reference = s;
     518            7 :                                         } else if (ma.member_name == "emit") {
     519              :                                                 // dynamic signal
     520            3 :                                                 unowned MethodCall mcall = (MethodCall) ma.parent_node;
     521            5 :                                                 var return_type = mcall.target_type ?? new VoidType ();
     522            3 :                                                 if (return_type is VarType) {
     523            1 :                                                         error = true;
     524            1 :                                                         Report.error (mcall.source_reference, "Cannot infer return type for dynamic signal `%s' from given context", member_name);
     525              :                                                 }
     526            3 :                                                 var s = new DynamicSignal (inner.value_type, member_name, return_type, source_reference);
     527            3 :                                                 s.access = SymbolAccessibility.PUBLIC;
     528            3 :                                                 s.add_parameter (new Parameter.with_ellipsis ());
     529            3 :                                                 dynamic_object_type.type_symbol.scope.add (null, s);
     530            3 :                                                 symbol_reference = s;
     531            1 :                                         } else if (ma.member_name == "disconnect") {
     532            1 :                                                 error = true;
     533            1 :                                                 Report.error (ma.source_reference, "Use SignalHandler.disconnect() to disconnect from dynamic signal");
     534              :                                         }
     535              :                                 }
     536           52 :                                 if (symbol_reference == null) {
     537              :                                         // dynamic property read access
     538           18 :                                         var prop = new DynamicProperty (inner.value_type, member_name, source_reference);
     539           18 :                                         if (target_type != null) {
     540           16 :                                                 prop.property_type = target_type;
     541              :                                         } else {
     542              :                                                 // expect dynamic object of the same type
     543            2 :                                                 prop.property_type = inner.value_type.copy ();
     544              :                                         }
     545           18 :                                         prop.access = SymbolAccessibility.PUBLIC;
     546           18 :                                         prop.get_accessor = new PropertyAccessor (true, false, false, prop.property_type.copy (), null, prop.source_reference);
     547           18 :                                         prop.owner = inner.value_type.type_symbol.scope;
     548           18 :                                         dynamic_object_type.type_symbol.scope.add (null, prop);
     549           18 :                                         symbol_reference = prop;
     550           18 :                                         if (!dynamic_object_type.type_symbol.is_subtype_of (context.analyzer.object_type)) {
     551            1 :                                                 Report.error (source_reference, "dynamic properties are not supported for %s", dynamic_object_type.type_symbol.get_full_name ());
     552            1 :                                                 error = true;
     553              :                                         }
     554              :                                 }
     555           34 :                                 if (symbol_reference != null) {
     556           34 :                                         may_access_instance_members = true;
     557           34 :                                         may_access_klass_members = true;
     558              :                                 }
     559              :                         }
     560              : 
     561       408073 :                         if (symbol_reference is ArrayResizeMethod) {
     562           35 :                                 if (inner.symbol_reference is Variable) {
     563              :                                         // require the real type with its original value_owned attritubte
     564           17 :                                         var inner_type = context.analyzer.get_value_type_for_symbol (inner.symbol_reference, true) as ArrayType;
     565           17 :                                         if (inner_type != null && inner_type.inline_allocated) {
     566            1 :                                                 Report.error (source_reference, "`resize' is not supported for arrays with fixed length");
     567            1 :                                                 error = true;
     568           16 :                                         } else if (inner_type != null && !inner_type.value_owned) {
     569            3 :                                                 Report.error (source_reference, "`resize' is not allowed for unowned array references");
     570            3 :                                                 error = true;
     571              :                                         }
     572            1 :                                 } else if (inner.symbol_reference is Constant) {
     573              :                                         // disallow resize() for const array
     574            1 :                                         Report.error (source_reference, "`resize' is not allowed for constant arrays");
     575            1 :                                         error = true;
     576              :                                 }
     577              :                         }
     578              :                 }
     579              : 
     580              :                 // enum-type inference
     581      1696088 :                 if (inner == null && symbol_reference == null && target_type != null && target_type.type_symbol is Enum) {
     582          108 :                         unowned Enum enum_type = (Enum) target_type.type_symbol;
     583          592 :                         foreach (var val in enum_type.get_values ()) {
     584          350 :                                 if (member_name == val.name) {
     585          108 :                                         symbol_reference = val;
     586          108 :                                         break;
     587              :                                 }
     588              :                         }
     589              :                 }
     590              : 
     591      1696088 :                 if (symbol_reference == null) {
     592           10 :                         error = true;
     593              : 
     594           10 :                         string base_type_name = "(null)";
     595           10 :                         unowned Symbol? base_type = null;
     596           10 :                         if (inner != null && inner.value_type != null) {
     597            1 :                                 base_type_name = inner.value_type.to_string ();
     598            1 :                                 base_type = inner.value_type.type_symbol;
     599            9 :                         } else if (base_symbol != null) {
     600            9 :                                 base_type_name = base_symbol.get_full_name ();
     601            9 :                                 base_type = base_symbol;
     602              :                         }
     603              : 
     604           10 :                         string? base_type_package = "";
     605           10 :                         if (base_type != null && base_type.external_package) {
     606            4 :                                 base_type_package = base_symbol.source_reference.file.package_name;
     607            2 :                                 if (base_type_package != null) {
     608            2 :                                         base_type_package = " (%s)".printf (base_type_package);
     609              :                                 }
     610              :                         }
     611              : 
     612           10 :                         string visited_types_string = "";
     613           12 :                         foreach (var type in visited_types) {
     614            1 :                                 visited_types_string += " or `%s'".printf (type.to_string ());
     615              :                         }
     616              : 
     617           10 :                         Report.error (source_reference, "The name `%s' does not exist in the context of `%s'%s%s", member_name, base_type_name, base_type_package, visited_types_string);
     618           10 :                         if (inner != null && inner.symbol_reference != null && inner.symbol_reference.source_reference != null) {
     619            3 :                                 Report.notice (inner.symbol_reference.source_reference, "`%s' was declared here", inner.symbol_reference.name);
     620              :                         }
     621           10 :                         value_type = new InvalidType ();
     622           10 :                         return false;
     623      1696078 :                 } else if (symbol_reference.error) {
     624              :                         //ignore previous error
     625            6 :                         error = true;
     626            6 :                         value_type = new InvalidType ();
     627            6 :                         return false;
     628              :                 }
     629              : 
     630      1696072 :                 if (symbol_reference is Signal) {
     631          217 :                         unowned Signal sig = (Signal) symbol_reference;
     632          217 :                         unowned CodeNode? ma = this;
     633          315 :                         while (ma.parent_node is MemberAccess) {
     634           98 :                                 ma = ma.parent_node;
     635              :                         }
     636          217 :                         unowned CodeNode? parent = ma.parent_node;
     637          217 :                         if (parent != null && !(parent is ElementAccess) && !(((MemberAccess) ma).inner is BaseAccess)
     638          197 :                             && (!(parent is MethodCall) || ((MethodCall) parent).get_argument_list ().contains (this))) {
     639           13 :                                 if (sig.has_attribute ("HasEmitter")) {
     640            8 :                                         if (!sig.check (context)) {
     641            0 :                                                 return false;
     642              :                                         }
     643            8 :                                         symbol_reference = sig.emitter;
     644              :                                 } else {
     645            5 :                                         error = true;
     646            5 :                                         Report.error (source_reference, "Signal `%s' requires emitter in this context", symbol_reference.get_full_name ());
     647            5 :                                         return false;
     648              :                                 }
     649              :                         }
     650              :                 }
     651              : 
     652      1696067 :                 unowned Symbol? member = symbol_reference;
     653      1696067 :                 var access = SymbolAccessibility.PUBLIC;
     654      1696067 :                 bool instance = false;
     655      1696067 :                 bool klass = false;
     656      1696067 :                 bool generics = false;
     657              : 
     658      1696067 :                 if (!member.check (context)) {
     659            0 :                         return false;
     660              :                 }
     661              : 
     662      1696067 :                 if (member is LocalVariable) {
     663       441835 :                         unowned LocalVariable local = (LocalVariable) member;
     664       441835 :                         unowned Block? block = local.parent_symbol as Block;
     665       441822 :                         if (block != null && SemanticAnalyzer.find_parent_method_or_property_accessor (block) != context.analyzer.current_method_or_property_accessor) {
     666              :                                 // mark all methods between current method and the captured
     667              :                                 // block as closures (to support nested closures)
     668           88 :                                 unowned Symbol? sym = context.analyzer.current_method_or_property_accessor;
     669          196 :                                 while (sym != block) {
     670          108 :                                         unowned Method? method = sym as Method;
     671           91 :                                         if (method != null) {
     672           91 :                                                 method.closure = true;
     673              :                                                 // consider captured variables as used
     674              :                                                 // as we require captured variables to be initialized
     675           91 :                                                 method.add_captured_variable (local);
     676              :                                         }
     677          108 :                                         sym = sym.parent_symbol;
     678              :                                 }
     679              : 
     680           88 :                                 local.captured = true;
     681           88 :                                 block.captured = true;
     682              : 
     683           88 :                                 if (local.variable_type.type_symbol == context.analyzer.va_list_type.type_symbol) {
     684            1 :                                         error = true;
     685            1 :                                         Report.error (source_reference, "Capturing `va_list' variable `%s' is not allowed", local.get_full_name ());
     686              :                                 }
     687              :                         }
     688      1254232 :                 } else if (member is Parameter) {
     689       485819 :                         unowned Parameter param = (Parameter) member;
     690       485819 :                         unowned Method? m = param.parent_symbol as Method;
     691       956936 :                         if (m != null && m != context.analyzer.current_method_or_property_accessor && param != m.this_parameter) {
     692              :                                 // mark all methods between current method and the captured
     693              :                                 // parameter as closures (to support nested closures)
     694         5695 :                                 unowned Symbol? sym = context.analyzer.current_method_or_property_accessor;
     695        17086 :                                 while (sym != m) {
     696        11391 :                                         unowned Method? method = sym as Method;
     697         5695 :                                         if (method != null) {
     698         5695 :                                                 method.closure = true;
     699              :                                         }
     700        11391 :                                         sym = sym.parent_symbol;
     701              :                                 }
     702              : 
     703         5695 :                                 param.captured = true;
     704         5695 :                                 m.body.captured = true;
     705              : 
     706         5695 :                                 if (param.direction != ParameterDirection.IN) {
     707            1 :                                         error = true;
     708            1 :                                         Report.error (source_reference, "Cannot capture reference or output parameter `%s'", param.get_full_name ());
     709              :                                 }
     710         5695 :                                 if (param.variable_type.type_symbol == context.analyzer.va_list_type.type_symbol) {
     711            1 :                                         error = true;
     712            1 :                                         Report.error (source_reference, "Capturing `va_list' parameter `%s' is not allowed", param.get_full_name ());
     713              :                                 }
     714              :                         } else {
     715       480124 :                                 unowned PropertyAccessor? acc = param.parent_symbol.parent_symbol as PropertyAccessor;
     716          503 :                                 if (acc != null && acc != context.analyzer.current_method_or_property_accessor && param != acc.prop.this_parameter) {
     717              :                                         // mark all methods between current method and the captured
     718              :                                         // parameter as closures (to support nested closures)
     719            1 :                                         unowned Symbol? sym = context.analyzer.current_method_or_property_accessor;
     720            7 :                                         while (sym != m) {
     721            6 :                                                 unowned Method? method = sym as Method;
     722            1 :                                                 if (method != null) {
     723            1 :                                                         method.closure = true;
     724              :                                                 }
     725            6 :                                                 sym = sym.parent_symbol;
     726              :                                         }
     727              : 
     728            1 :                                         param.captured = true;
     729            1 :                                         acc.body.captured = true;
     730              :                                 }
     731              :                         }
     732       768413 :                 } else if (member is Field) {
     733       119506 :                         unowned Field f = (Field) member;
     734       119506 :                         access = f.access;
     735       119506 :                         instance = (f.binding == MemberBinding.INSTANCE);
     736       119506 :                         klass = (f.binding == MemberBinding.CLASS);
     737              : 
     738              :                         // do not allow access to fields of generic types
     739              :                         // if instance type does not specify type arguments
     740       119506 :                         if (f.variable_type is GenericType) {
     741        15601 :                                 generics = true;
     742              :                         }
     743       648907 :                 } else if (member is Constant) {
     744       143979 :                         unowned Constant c = (Constant) member;
     745       143979 :                         access = c.access;
     746              : 
     747       143979 :                         unowned Block? block = c.parent_symbol as Block;
     748           34 :                         if (block != null && SemanticAnalyzer.find_parent_method_or_property_accessor (block) != context.analyzer.current_method_or_property_accessor) {
     749            1 :                                 error = true;
     750            1 :                                 Report.error (source_reference, "internal error: accessing local constants of outer methods is not supported yet");
     751            1 :                                 return false;
     752              :                         }
     753       504928 :                 } else if (member is Method) {
     754       184147 :                         unowned Method m = (Method) member;
     755       184147 :                         if (m.is_async_callback) {
     756              :                                 // ensure to use right callback method for virtual/abstract async methods
     757              :                                 // and also for lambda expressions within async methods
     758           20 :                                 unowned Method? async_method = context.analyzer.current_async_method;
     759              : 
     760           20 :                                 bool is_valid_access = false;
     761           20 :                                 if (async_method != null) {
     762           20 :                                         if (m == async_method.get_callback_method ()) {
     763              :                                                 is_valid_access = true;
     764            3 :                                         } else if (async_method.base_method != null && m == async_method.base_method.get_callback_method ()) {
     765              :                                                 is_valid_access = true;
     766            2 :                                         } else if (async_method.base_interface_method != null && m == async_method.base_interface_method.get_callback_method ()) {
     767              :                                                 is_valid_access = true;
     768              :                                         }
     769              :                                 }
     770              :                                 if (!is_valid_access) {
     771            1 :                                         error = true;
     772            1 :                                         Report.error (source_reference, "Access to async callback `%s' not allowed in this context", m.get_full_name ());
     773            1 :                                         return false;
     774              :                                 }
     775              : 
     776           19 :                                 if (async_method != context.analyzer.current_method) {
     777            2 :                                         unowned Symbol? sym = context.analyzer.current_method;
     778            6 :                                         while (sym != async_method) {
     779            4 :                                                 unowned Method? method = sym as Method;
     780            2 :                                                 if (method != null) {
     781            2 :                                                         method.closure = true;
     782              :                                                 }
     783            4 :                                                 sym = sym.parent_symbol;
     784              :                                         }
     785            2 :                                         async_method.body.captured = true;
     786              :                                 }
     787              : 
     788           19 :                                 m = async_method.get_callback_method ();
     789           19 :                                 symbol_reference = m;
     790           19 :                                 member = symbol_reference;
     791       184127 :                         } else if (m.base_method != null) {
     792              :                                 // refer to base method to inherit default arguments
     793         3246 :                                 m = m.base_method;
     794              : 
     795         3246 :                                 if (m.signal_reference != null) {
     796              :                                         // method is class/default handler for a signal
     797              :                                         // let signal deal with member access
     798            1 :                                         symbol_reference = m.signal_reference;
     799              :                                 } else {
     800         3245 :                                         symbol_reference = m;
     801              :                                 }
     802              : 
     803         3246 :                                 member = symbol_reference;
     804       180881 :                         } else if (m.base_interface_method != null) {
     805              :                                 // refer to base method to inherit default arguments
     806          385 :                                 m = m.base_interface_method;
     807              : 
     808          385 :                                 if (m.signal_reference != null) {
     809              :                                         // method is class/default handler for a signal
     810              :                                         // let signal deal with member access
     811            1 :                                         symbol_reference = m.signal_reference;
     812              :                                 } else {
     813          384 :                                         symbol_reference = m;
     814              :                                 }
     815              : 
     816          385 :                                 member = symbol_reference;
     817              :                         }
     818       184146 :                         access = m.access;
     819       184146 :                         if (!(m is CreationMethod)) {
     820       176748 :                                 instance = (m.binding == MemberBinding.INSTANCE);
     821              :                         }
     822       184146 :                         klass = (m.binding == MemberBinding.CLASS);
     823              : 
     824              :                         // do not allow access to methods using generic type parameters
     825              :                         // if instance type does not specify type arguments
     826       730758 :                         foreach (var param in m.get_parameters ()) {
     827       281465 :                                 unowned GenericType? generic_type = param.variable_type as GenericType;
     828       281465 :                                 if (generic_type != null && generic_type.type_parameter.parent_symbol is TypeSymbol) {
     829         8159 :                                         generics = true;
     830         8159 :                                         break;
     831              :                                 }
     832              :                         }
     833       184146 :                         unowned GenericType? generic_type = m.return_type as GenericType;
     834         2321 :                         if (generic_type != null && generic_type.type_parameter.parent_symbol is TypeSymbol) {
     835              :                                 generics = true;
     836              :                         }
     837       320781 :                 } else if (member is Property) {
     838        36360 :                         unowned Property prop = (Property) member;
     839        36360 :                         if (!prop.check (context)) {
     840            0 :                                 error = true;
     841            0 :                                 return false;
     842              :                         }
     843        36360 :                         if (prop.base_property != null) {
     844              :                                 // refer to base property
     845          127 :                                 prop = prop.base_property;
     846          127 :                                 symbol_reference = prop;
     847          127 :                                 member = symbol_reference;
     848        36233 :                         } else if (prop.base_interface_property != null) {
     849              :                                 // refer to base property
     850          427 :                                 prop = prop.base_interface_property;
     851          427 :                                 symbol_reference = prop;
     852          427 :                                 member = symbol_reference;
     853              :                         }
     854        36360 :                         access = prop.access;
     855        36360 :                         if (lvalue) {
     856         1537 :                                 if (prop.set_accessor == null) {
     857            1 :                                         error = true;
     858            1 :                                         Report.error (source_reference, "Property `%s' is read-only", prop.get_full_name ());
     859            1 :                                         return false;
     860         1536 :                                 } else if (!prop.set_accessor.writable && prop.set_accessor.construction) {
     861            6 :                                         if (context.analyzer.find_current_method () is CreationMethod) {
     862            2 :                                                 error = true;
     863            2 :                                                 Report.error (source_reference, "Cannot assign to construct-only properties, use Object (property: value) constructor chain up");
     864            2 :                                                 return false;
     865            4 :                                         } else if (context.analyzer.is_in_constructor ()) {
     866            3 :                                                 if (!context.analyzer.current_type_symbol.is_subtype_of ((TypeSymbol) prop.parent_symbol)) {
     867            1 :                                                         error = true;
     868            1 :                                                         Report.error (source_reference, "Cannot assign to construct-only property `%s' in `construct' of `%s'", prop.get_full_name (), context.analyzer.current_type_symbol.get_full_name ());
     869            1 :                                                         return false;
     870              :                                                 }
     871              :                                         } else {
     872            1 :                                                 error = true;
     873            1 :                                                 Report.error (source_reference, "Cannot assign to construct-only property in this context");
     874            1 :                                                 return false;
     875              :                                         }
     876              :                                 }
     877         1532 :                                 if (prop.access == SymbolAccessibility.PUBLIC) {
     878         1526 :                                         access = prop.set_accessor.access;
     879            6 :                                 } else if (prop.access == SymbolAccessibility.PROTECTED
     880            0 :                                            && prop.set_accessor.access != SymbolAccessibility.PUBLIC) {
     881            0 :                                         access = prop.set_accessor.access;
     882              :                                 }
     883              :                         } else {
     884        34823 :                                 if (prop.get_accessor == null) {
     885            1 :                                         error = true;
     886            1 :                                         Report.error (source_reference, "Property `%s' is write-only", prop.get_full_name ());
     887            1 :                                         return false;
     888              :                                 }
     889        34822 :                                 if (prop.access == SymbolAccessibility.PUBLIC) {
     890        34805 :                                         access = prop.get_accessor.access;
     891           17 :                                 } else if (prop.access == SymbolAccessibility.PROTECTED
     892            0 :                                            && prop.get_accessor.access != SymbolAccessibility.PUBLIC) {
     893            0 :                                         access = prop.get_accessor.access;
     894              :                                 }
     895              :                         }
     896        36354 :                         instance = (prop.binding == MemberBinding.INSTANCE);
     897              : 
     898              :                         // do not allow access to properties of generic types
     899              :                         // if instance type does not specify type arguments
     900        36354 :                         if (prop.property_type is GenericType) {
     901      1696059 :                                 generics = true;
     902              :                         }
     903       284421 :                 } else if (member is Signal) {
     904          204 :                         instance = true;
     905          204 :                         access = member.access;
     906       284217 :                 } else if (member is ErrorCode) {
     907         1505 :                         if (!(parent_node is CallableExpression && ((CallableExpression) parent_node).call == this)) {
     908           12 :                                 symbol_reference = ((ErrorCode) member).code;
     909           12 :                                 member = symbol_reference;
     910              :                         }
     911              :                 }
     912              : 
     913              :                 // recursive usage of itself doesn't count as used
     914      1696059 :                 unowned CodeNode? parent = this;
     915     11221448 :                 while (parent != member) {
     916     11221448 :                         parent = parent.parent_node;
     917     11221448 :                         if (parent == null || parent == member) {
     918              :                                 break;
     919              :                         }
     920              :                 }
     921      1696059 :                 if (parent != member) {
     922      1695944 :                         member.used = true;
     923              :                 }
     924      1696059 :                 member.version.check (context, source_reference);
     925              : 
     926              :                 // FIXME Code duplication with MemberInitializer.check()
     927      1696059 :                 if (access == SymbolAccessibility.PROTECTED && member.parent_symbol is TypeSymbol) {
     928          729 :                         unowned TypeSymbol target_type = (TypeSymbol) member.parent_symbol;
     929              : 
     930          729 :                         bool in_subtype = false;
     931         8941 :                         for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) {
     932         2980 :                                 if (this_symbol == target_type) {
     933              :                                         // required for interfaces with non-abstract methods
     934              :                                         // accessing protected interface members
     935              :                                         in_subtype = true;
     936              :                                         break;
     937              :                                 }
     938              : 
     939         2395 :                                 unowned Class? cl = this_symbol as Class;
     940         2395 :                                 if (cl != null && cl.is_subtype_of (target_type)) {
     941              :                                         in_subtype = true;
     942              :                                         break;
     943              :                                 }
     944              :                         }
     945              : 
     946          729 :                         if (!in_subtype) {
     947            1 :                                 error = true;
     948            1 :                                 Report.error (source_reference, "Access to protected member `%s' denied", member.get_full_name ());
     949            1 :                                 return false;
     950              :                         }
     951      1695330 :                 } else if (access == SymbolAccessibility.PRIVATE) {
     952        63518 :                         unowned Symbol? target_type = member.parent_symbol;
     953              : 
     954        63518 :                         bool in_target_type = false;
     955       687913 :                         for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) {
     956       229304 :                                 if (target_type == this_symbol) {
     957              :                                         in_target_type = true;
     958              :                                         break;
     959              :                                 }
     960              :                         }
     961              : 
     962        63518 :                         if (!in_target_type) {
     963            1 :                                 error = true;
     964            1 :                                 Report.error (source_reference, "Access to private member `%s' denied", member.get_full_name ());
     965            1 :                                 return false;
     966              :                         }
     967              :                 }
     968              : 
     969      1696057 :                 if (generics && inner != null) {
     970        24476 :                         unowned DataType instance_type = inner.value_type;
     971        24476 :                         unowned PointerType? pointer_type = inner.value_type as PointerType;
     972            0 :                         if (pointer_type != null) {
     973            0 :                                 instance_type = pointer_type.base_type;
     974              :                         }
     975              : 
     976              :                         // instance type might be a subtype of the parent symbol of the member
     977              :                         // that subtype might not be generic, so do not report an error in that case
     978        24476 :                         unowned ObjectType? object_type = instance_type as ObjectType;
     979        23059 :                         if (object_type != null && object_type.object_type_symbol.has_type_parameters ()
     980        23045 :                             && !instance_type.has_type_arguments ()) {
     981            0 :                                 error = true;
     982            0 :                                 Report.error (inner.source_reference, "missing generic type arguments");
     983            0 :                                 return false;
     984              :                         }
     985              :                 }
     986              : 
     987      1696057 :                 if ((instance && !may_access_instance_members) ||
     988      1696011 :                     (klass && !may_access_klass_members)) {
     989           46 :                         prototype_access = true;
     990              : 
     991           46 :                         if (symbol_reference is Method) {
     992              :                                 // also set static type for prototype access
     993              :                                 // required when using instance methods as delegates in constants
     994              :                                 // TODO replace by MethodPrototype
     995           39 :                                 value_type = context.analyzer.get_value_type_for_symbol (symbol_reference, lvalue);
     996           39 :                                 value_type.source_reference = source_reference;
     997            7 :                         } else if (symbol_reference is Field) {
     998            4 :                                 value_type = new FieldPrototype ((Field) symbol_reference, source_reference);
     999            3 :                         } else if (symbol_reference is Property) {
    1000            3 :                                 value_type = new PropertyPrototype ((Property) symbol_reference, source_reference);
    1001              :                         } else {
    1002            0 :                                 error = true;
    1003            0 :                                 value_type = new InvalidType ();
    1004              :                         }
    1005              : 
    1006           46 :                         if (target_type != null) {
    1007            8 :                                 value_type.value_owned = target_type.value_owned;
    1008              :                         }
    1009              :                 } else {
    1010              :                         // implicit this access
    1011      1696011 :                         if (instance && inner == null) {
    1012        51817 :                                 inner = new MemberAccess (null, "this", source_reference);
    1013        51817 :                                 inner.value_type = this_parameter.variable_type.copy ();
    1014        51817 :                                 inner.value_type.value_owned = false;
    1015        51817 :                                 inner.symbol_reference = this_parameter;
    1016              :                         } else {
    1017      1644194 :                                 check_lvalue_access ();
    1018              :                         }
    1019              : 
    1020      1696011 :                         if (!instance && !klass && !(symbol_reference is CreationMethod) && may_access_instance_members && inner != null) {
    1021           47 :                                 if (inner.symbol_reference is Method) {
    1022              :                                         // do not warn when calling .begin or .end on static async method
    1023              :                                 } else {
    1024            5 :                                         Report.warning (source_reference, "Access to static member `%s' with an instance reference", symbol_reference.get_full_name ());
    1025              : 
    1026              :                                         // Transform to static member access
    1027            5 :                                         unowned Symbol? inner_sym = symbol_reference.parent_symbol;
    1028            5 :                                         unowned MemberAccess? inner_ma = this;
    1029           11 :                                         while (inner_sym != null && inner_sym.name != null) {
    1030            6 :                                                 inner_ma.inner = new MemberAccess (null, inner_sym.name, source_reference);
    1031            6 :                                                 inner_ma = (MemberAccess) inner_ma.inner;
    1032            6 :                                                 inner_sym = inner_sym.parent_symbol;
    1033              :                                         }
    1034            5 :                                         inner_ma.qualified = true;
    1035            5 :                                         inner.check (context);
    1036              :                                 }
    1037              :                         }
    1038              : 
    1039      1696011 :                         if (context.experimental_non_null && instance && inner.value_type.nullable &&
    1040           93 :                             !(inner.value_type is PointerType) && !(inner.value_type is GenericType) &&
    1041           93 :                                 !(inner.value_type is ArrayType)) {
    1042            2 :                                 Report.error (source_reference, "Access to instance member `%s' from nullable reference denied", symbol_reference.get_full_name ());
    1043              :                         }
    1044              : 
    1045      1696011 :                         unowned Method? m = symbol_reference as Method;
    1046      1696011 :                         unowned MemberAccess? inner_ma = inner as MemberAccess;
    1047      1696011 :                         if (m != null && m.binding == MemberBinding.STATIC && m.parent_symbol is ObjectTypeSymbol &&
    1048        26291 :                             inner != null && inner.value_type == null && inner_ma.type_argument_list.size > 0) {
    1049              :                                 // support static methods in generic classes
    1050            1 :                                 inner.value_type = new ObjectType ((ObjectTypeSymbol) m.parent_symbol, source_reference);
    1051              : 
    1052            3 :                                 foreach (var type_argument in inner_ma.type_argument_list) {
    1053            1 :                                         inner.value_type.add_type_argument (type_argument);
    1054              :                                 }
    1055              :                         }
    1056              : 
    1057      1696011 :                         formal_value_type = context.analyzer.get_value_type_for_symbol (symbol_reference, lvalue);
    1058      1696011 :                         if (inner != null && formal_value_type != null) {
    1059       361769 :                                 value_type = formal_value_type.get_actual_type (inner.value_type, null, this);
    1060              :                         } else {
    1061      1334242 :                                 value_type = formal_value_type;
    1062              :                         }
    1063              : 
    1064      1696011 :                         if (symbol_reference is Method) {
    1065       184105 :                                 unowned Method method = (Method) symbol_reference;
    1066       184105 :                                 if (target_type != null) {
    1067         1606 :                                         value_type.value_owned = target_type.value_owned;
    1068              :                                 }
    1069       184105 :                                 if (instance && method.parent_symbol is TypeSymbol) {
    1070        79464 :                                         inner.target_type = SemanticAnalyzer.get_data_type_for_symbol (method.parent_symbol);
    1071        79464 :                                         inner.target_type.value_owned = method.this_parameter.variable_type.value_owned;
    1072              :                                 }
    1073      1511906 :                         } else if (symbol_reference is Property
    1074        36351 :                             && instance && symbol_reference.parent_symbol != null) {
    1075        36343 :                                 inner.target_type = SemanticAnalyzer.get_data_type_for_symbol (symbol_reference.parent_symbol);
    1076      1536523 :                         } else if ((symbol_reference is Field || symbol_reference is Signal)
    1077       119706 :                             && instance && symbol_reference.parent_symbol != null) {
    1078        60960 :                                 var parent_type = SemanticAnalyzer.get_data_type_for_symbol (symbol_reference.parent_symbol);
    1079        60960 :                                 inner.target_type = parent_type.get_actual_type (inner.value_type, null, this);
    1080              :                         }
    1081              : 
    1082      1696011 :                         if (inner == null && value_type != null && context.profile == Profile.GOBJECT) {
    1083      1049156 :                                 check_narrowed_value_type ();
    1084              :                         }
    1085              :                 }
    1086              : 
    1087      1696057 :                 if (value_type != null) {
    1088      1411848 :                         value_type.check (context);
    1089              :                 }
    1090              : 
    1091      1696057 :                 if (symbol_reference is ArrayLengthField) {
    1092        17320 :                         if (inner.value_type is ArrayType && ((ArrayType) inner.value_type).rank > 1 && !(parent_node is ElementAccess)) {
    1093            1 :                                 Report.error (source_reference, "unsupported use of length field of multi-dimensional array");
    1094            1 :                                 error = true;
    1095              :                         }
    1096      1678737 :                 } else if (symbol_reference is DelegateTargetField) {
    1097           15 :                         if (!((DelegateType) inner.value_type).delegate_symbol.has_target) {
    1098            1 :                                 Report.error (source_reference, "unsupported use of target field of delegate without target");
    1099            1 :                                 error = true;
    1100              :                         }
    1101      1678722 :                 } else if (symbol_reference is DelegateDestroyField) {
    1102            6 :                         if (!((DelegateType) inner.value_type).delegate_symbol.has_target) {
    1103            1 :                                 Report.error (source_reference, "unsupported use of destroy field of delegate without target");
    1104            1 :                                 error = true;
    1105              :                         }
    1106              :                 }
    1107              : 
    1108              :                 // Provide some extra information for the code generator
    1109      1696057 :                 if (!tainted_access) {
    1110      1696057 :                         tainted_access = is_tainted ();
    1111              :                 }
    1112              : 
    1113      1696057 :                 return !error;
    1114              :         }
    1115              : 
    1116            1 :         static bool is_instance_symbol (Symbol symbol) {
    1117            1 :                 if (symbol is Field && ((Field) symbol).binding == MemberBinding.INSTANCE) {
    1118              :                         return true;
    1119            1 :                 } else if (symbol is Method && !(symbol is CreationMethod) && ((Method) symbol).binding == MemberBinding.INSTANCE) {
    1120              :                         return true;
    1121            0 :                 } else if (symbol is Property && ((Property) symbol).binding == MemberBinding.INSTANCE) {
    1122              :                         return true;
    1123            0 :                 } else if (symbol is Signal) {
    1124              :                         return true;
    1125              :                 } else {
    1126              :                         return false;
    1127              :                 }
    1128              :         }
    1129              : 
    1130      1651445 :         public void check_lvalue_access () {
    1131      1651445 :                 if (inner == null) {
    1132              :                         return;
    1133              :                 }
    1134       424074 :                 var instance = symbol_reference is Field && ((Field) symbol_reference).binding == MemberBinding.INSTANCE;
    1135        58909 :                 if (!instance) {
    1136       365165 :                         instance = symbol_reference is Method && ((Method) symbol_reference).binding == MemberBinding.INSTANCE;
    1137              :                 }
    1138       108967 :                 if (!instance) {
    1139       299032 :                         instance = symbol_reference is Property && ((Property) symbol_reference).binding == MemberBinding.INSTANCE;
    1140              :                 }
    1141              : 
    1142       414940 :                 var this_access = inner.symbol_reference is Parameter && inner.symbol_reference.name == "this";
    1143       414940 :                 var struct_or_array = (inner.value_type is StructValueType && !inner.value_type.nullable) || inner.value_type is ArrayType;
    1144              : 
    1145       414940 :                 unowned MemberAccess? ma = inner as MemberAccess;
    1146        38024 :                 if (ma == null && struct_or_array && inner is PointerIndirection) {
    1147              :                         // (*struct)->method()
    1148         1428 :                         ma = ((PointerIndirection) inner).inner as MemberAccess;
    1149              :                 }
    1150              : 
    1151       414940 :                 if (instance && struct_or_array && (symbol_reference is Method || lvalue) && ((ma != null && ma.symbol_reference is Variable) || inner is ElementAccess) && !this_access) {
    1152         7227 :                         inner.lvalue = true;
    1153         7227 :                         if (ma != null) {
    1154         7221 :                                 ma.lvalue = true;
    1155         7221 :                                 ma.check_lvalue_access ();
    1156              :                         }
    1157              :                 }
    1158              : 
    1159       414940 :                 if (symbol_reference is DelegateTargetField || symbol_reference is DelegateDestroyField) {
    1160           21 :                         inner.lvalue = true;
    1161           21 :                         if (ma != null) {
    1162           21 :                                 ma.lvalue = true;
    1163           21 :                                 ma.check_lvalue_access ();
    1164              :                         }
    1165              :                 }
    1166              : 
    1167       414940 :                 if (symbol_reference is Method && ((Method) symbol_reference).has_attribute ("DestroysInstance")) {
    1168            9 :                         unowned Class? cl = ((Method) symbol_reference).parent_symbol as Class;
    1169            9 :                         if (cl != null && cl.is_compact && ma != null) {
    1170            7 :                                 ma.lvalue = true;
    1171            7 :                                 ma.check_lvalue_access ();
    1172              :                         }
    1173              :                 }
    1174              :         }
    1175              : 
    1176       130852 :         public override void emit (CodeGenerator codegen) {
    1177       130852 :                 if (inner != null) {
    1178        53437 :                         inner.emit (codegen);
    1179              :                 }
    1180              : 
    1181       130852 :                 codegen.visit_member_access (this);
    1182              : 
    1183       130852 :                 codegen.visit_expression (this);
    1184              :         }
    1185              : 
    1186      3043971 :         public override void get_defined_variables (Collection<Variable> collection) {
    1187      3043971 :                 if (inner != null) {
    1188       591165 :                         inner.get_defined_variables (collection);
    1189              :                 }
    1190              :         }
    1191              : 
    1192       864004 :         public override void get_used_variables (Collection<Variable> collection) {
    1193       864004 :                 if (inner != null) {
    1194       191810 :                         inner.get_used_variables (collection);
    1195              :                 }
    1196       864004 :                 unowned LocalVariable? local = symbol_reference as LocalVariable;
    1197       864004 :                 unowned Parameter? param = symbol_reference as Parameter;
    1198       864004 :                 if (local != null) {
    1199       210898 :                         collection.add (local);
    1200       653106 :                 } else if (param != null && param.direction == ParameterDirection.OUT) {
    1201        22264 :                         collection.add (param);
    1202              :                 }
    1203              :         }
    1204              : 
    1205      5955754 :         bool is_tainted () {
    1206      1696057 :                 unowned CodeNode node = this;
    1207      1696057 :                 if (node.parent_node is ElementAccess || node.parent_node is MemberAccess) {
    1208       414237 :                         return false;
    1209              :                 }
    1210              : 
    1211      1993659 :                 while (node.parent_node is Expression) {
    1212      1560647 :                         node = node.parent_node;
    1213      1560647 :                         if (node is Assignment || node is MethodCall || node is ObjectCreationExpression) {
    1214              :                                 break;
    1215              :                         }
    1216              :                 }
    1217              : 
    1218      1281820 :                 bool found = false;
    1219      8079645 :                 var traverse = new TraverseVisitor ((n) => {
    1220      6797825 :                         if (n is PostfixExpression) {
    1221         6224 :                                 found = true;
    1222         6224 :                                 return TraverseStatus.STOP;
    1223      6791601 :                         } else if (n is UnaryExpression) {
    1224       105486 :                                 unowned UnaryExpression e = (UnaryExpression) n;
    1225       105486 :                                 if (e.operator == UnaryOperator.INCREMENT || e.operator == UnaryOperator.DECREMENT) {
    1226          987 :                                         found = true;
    1227          987 :                                         return TraverseStatus.STOP;
    1228              :                                 }
    1229              :                         }
    1230      6797825 :                         return TraverseStatus.CONTINUE;
    1231              :                 });
    1232      1281820 :                 node.accept (traverse);
    1233              : 
    1234      1281820 :                 return found;
    1235              :         }
    1236              : 
    1237      1147151 :         void check_narrowed_value_type () {
    1238      1049156 :                 unowned Variable? variable = symbol_reference as Variable;
    1239      2008348 :                 if (variable == null) {
    1240              :                         return;
    1241              :                 }
    1242              : 
    1243       959192 :                 if (!(parent_node is MemberAccess)) {
    1244              :                         return;
    1245              :                 }
    1246              : 
    1247        97995 :                 bool is_negation = false;
    1248        97995 :                 unowned CodeNode? parent = parent_node;
    1249        97995 :                 unowned IfStatement? if_statement = null;
    1250        97995 :                 var scope_type_checks = new ArrayList<unowned TypeCheck> ();
    1251       437597 :                 while (parent != null && !(parent is Method)) {
    1252       427645 :                         if (parent is TypeCheck) {
    1253        97995 :                                 parent = null;
    1254              :                                 break;
    1255              :                         }
    1256       427189 :                         if (parent.parent_node is IfStatement) {
    1257        35096 :                                 if_statement = (IfStatement) parent.parent_node;
    1258        35096 :                                 is_negation = if_statement.false_statement == parent;
    1259        35096 :                                 break;
    1260              :                         }
    1261       392093 :                         if (parent.parent_node is Method) {
    1262        52501 :                                 foreach (Expression expr in ((Method) parent.parent_node).get_preconditions ()) {
    1263            5 :                                         if (expr is TypeCheck) {
    1264            2 :                                                 scope_type_checks.add ((TypeCheck) expr);
    1265              :                                         }
    1266              :                                 }
    1267              :                                 break;
    1268              :                         }
    1269       339602 :                         parent = parent.parent_node;
    1270              :                 }
    1271              : 
    1272        97995 :                 if (if_statement != null) {
    1273        35096 :                         unowned Expression expr = if_statement.condition;
    1274        35096 :                         if (expr is UnaryExpression && ((UnaryExpression) expr).operator == UnaryOperator.LOGICAL_NEGATION) {
    1275         2390 :                                 expr = ((UnaryExpression) expr).inner;
    1276         2390 :                                 is_negation = !is_negation;
    1277              :                         }
    1278        35096 :                         unowned TypeCheck? type_check = expr as TypeCheck;
    1279        35096 :                         if (!is_negation && type_check != null) {
    1280          641 :                                 unowned TypeSymbol? narrowed_symnol = type_check.type_reference.type_symbol;
    1281          641 :                                 if (variable == type_check.expression.symbol_reference) {
    1282           50 :                                         if (narrowed_symnol != value_type.type_symbol) {
    1283           48 :                                                 value_type.context_symbol = narrowed_symnol;
    1284              :                                         }
    1285           50 :                                         value_type.nullable = false;
    1286              :                                 }
    1287              :                         }
    1288              :                 }
    1289        97995 :                 if (value_type.context_symbol == null) {
    1290        97951 :                         foreach (TypeCheck type_check in scope_type_checks) {
    1291            2 :                                 unowned TypeSymbol? narrowed_symnol = type_check.type_reference.type_symbol;
    1292            2 :                                 if (variable == type_check.expression.symbol_reference) {
    1293            2 :                                         if (narrowed_symnol != value_type.type_symbol) {
    1294            2 :                                                 value_type.context_symbol = narrowed_symnol;
    1295              :                                         }
    1296            2 :                                         value_type.nullable = false;
    1297              :                                 }
    1298              :                         }
    1299              :                 }
    1300              :         }
    1301              : }
        

Generated by: LCOV version 2.0-1