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

            Line data    Source code
       1              : /* valaassignment.vala
       2              :  *
       3              :  * Copyright (C) 2006-2011  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              : 
      24              : /**
      25              :  * Represents an assignment expression in the source code.
      26              :  *
      27              :  * Supports =, |=, &=, ^=, +=, -=, *=, /=, %=, <<=, >>=.
      28              :  */
      29       218980 : public class Vala.Assignment : Expression {
      30              :         /**
      31              :          * Left hand side of the assignment.
      32              :          */
      33              :         public Expression left {
      34      5609984 :                 get { return _left; }
      35       217444 :                 private set {
      36       446798 :                         _left = value;
      37       217444 :                         _left.parent_node = this;
      38              :                 }
      39              :         }
      40              : 
      41              :         /**
      42              :          * Assignment operator.
      43              :          */
      44       220866 :         public AssignmentOperator operator { get; private set; }
      45              : 
      46              :         /**
      47              :          * Right hand side of the assignment.
      48              :          */
      49              :         public Expression right {
      50      3480081 :                 get { return _right; }
      51       227931 :                 private set {
      52       455862 :                         _right = value;
      53       227931 :                         _right.parent_node = this;
      54              :                 }
      55              :         }
      56              : 
      57       217443 :         private Expression _left;
      58       217443 :         private Expression _right;
      59              : 
      60              :         /**
      61              :          * Creates a new assignment.
      62              :          *
      63              :          * @param left             left hand side
      64              :          * @param operator         assignment operator
      65              :          * @param right            right hand side
      66              :          * @param source_reference reference to source code
      67              :          * @return                 newly created assignment
      68              :          */
      69       652329 :         public Assignment (Expression left, Expression right, AssignmentOperator operator = AssignmentOperator.SIMPLE, SourceReference? source_reference = null) {
      70       217443 :                 this.right = right;
      71       217443 :                 this.operator = operator;
      72       217443 :                 this.source_reference = source_reference;
      73       217443 :                 this.left = left;
      74              :         }
      75              : 
      76       601836 :         public override void accept (CodeVisitor visitor) {
      77       601836 :                 visitor.visit_assignment (this);
      78              : 
      79       601836 :                 visitor.visit_expression (this);
      80              :         }
      81              : 
      82       601830 :         public override void accept_children (CodeVisitor visitor) {
      83       601830 :                 left.accept (visitor);
      84       601830 :                 right.accept (visitor);
      85              :         }
      86              : 
      87            0 :         public override string to_string () {
      88            0 :                 return "(%s %s %s)".printf (_left.to_string (), operator.to_string (), _right.to_string ());
      89              :         }
      90              : 
      91         7403 :         public override void replace_expression (Expression old_node, Expression new_node) {
      92         7403 :                 if (left == old_node) {
      93            1 :                         left = new_node;
      94              :                 }
      95         7403 :                 if (right == old_node) {
      96         7402 :                         right = new_node;
      97              :                 }
      98              :         }
      99              : 
     100            0 :         public override bool is_pure () {
     101            0 :                 return false;
     102              :         }
     103              : 
     104            0 :         public override bool is_accessible (Symbol sym) {
     105            0 :                 return left.is_accessible (sym) && right.is_accessible (sym);
     106              :         }
     107              : 
     108       367970 :         public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
     109       367970 :                 left.get_error_types (collection, source_reference);
     110       367970 :                 right.get_error_types (collection, source_reference);
     111              :         }
     112              : 
     113       210224 :         public override bool check (CodeContext context) {
     114       210224 :                 if (checked) {
     115         1454 :                         return !error;
     116              :                 }
     117              : 
     118       208770 :                 checked = true;
     119              : 
     120       208770 :                 if (left is Tuple && operator == AssignmentOperator.SIMPLE && parent_node is ExpressionStatement) {
     121            2 :                         unowned Tuple tuple = (Tuple) left;
     122              : 
     123            2 :                         var local = new LocalVariable (null, get_temp_name (), right, right.source_reference);
     124            2 :                         var decl = new DeclarationStatement (local, source_reference);
     125            2 :                         insert_statement (context.analyzer.insert_block, decl);
     126            2 :                         decl.check (context);
     127              : 
     128            2 :                         int i = 0;
     129            2 :                         ExpressionStatement stmt = null;
     130           10 :                         foreach (var expr in tuple.get_expressions ()) {
     131            4 :                                 if (stmt != null) {
     132            2 :                                         insert_statement (context.analyzer.insert_block, stmt);
     133            2 :                                         stmt.check (context);
     134              :                                 }
     135              : 
     136            4 :                                 var temp_access = new MemberAccess.simple (local.name, right.source_reference);
     137            4 :                                 var ea = new ElementAccess (temp_access, expr.source_reference);
     138            4 :                                 ea.append_index (new IntegerLiteral (i.to_string (), expr.source_reference));
     139            4 :                                 var assign = new Assignment (expr, ea, operator, expr.source_reference);
     140            4 :                                 stmt = new ExpressionStatement (assign, expr.source_reference);
     141              : 
     142            4 :                                 i++;
     143              :                         }
     144              : 
     145            2 :                         context.analyzer.replaced_nodes.add (this);
     146            2 :                         parent_node.replace_expression (this, stmt.expression);
     147            2 :                         return stmt.expression.check (context);
     148              :                 }
     149              : 
     150       208768 :                 left.lvalue = true;
     151              : 
     152       208768 :                 if (!left.check (context)) {
     153              :                         // skip on error in inner expression
     154           18 :                         error = true;
     155           18 :                         return false;
     156              :                 }
     157              : 
     158       208750 :                 if (left is MemberAccess) {
     159       205812 :                         unowned MemberAccess ma = (MemberAccess) left;
     160              : 
     161       205812 :                         check_constant_assignment (ma);
     162              : 
     163       205812 :                         if ((!(ma.symbol_reference is DynamicProperty) && ma.value_type == null) ||
     164       205812 :                             (ma.inner == null && ma.member_name == "this" && context.analyzer.is_in_instance_method ())) {
     165            1 :                                 error = true;
     166            1 :                                 Report.error (source_reference, "unsupported lvalue in assignment");
     167            1 :                                 return false;
     168              :                         }
     169       205811 :                         if (ma.prototype_access) {
     170            0 :                                 error = true;
     171            0 :                                 Report.error (source_reference, "Access to instance member `%s' denied", ma.symbol_reference.get_full_name ());
     172            0 :                                 return false;
     173              :                         }
     174              : 
     175       205811 :                         if (ma.error || ma.symbol_reference == null) {
     176            0 :                                 error = true;
     177              :                                 /* if no symbol found, skip this check */
     178            0 :                                 return false;
     179              :                         }
     180              : 
     181       205811 :                         if (ma.symbol_reference.has_attribute ("GtkChild")) {
     182            3 :                                 error = true;
     183            3 :                                 Report.error (source_reference, "Assignment of [GtkChild] `%s' is not allowed", ma.symbol_reference.get_full_name ());
     184            3 :                                 return false;
     185              :                         }
     186              : 
     187       205808 :                         if (ma.symbol_reference is DynamicProperty) {
     188              :                                 // target_type not available for dynamic properties
     189              :                         } else {
     190       205805 :                                 right.formal_target_type = ma.formal_value_type.copy ();
     191       205805 :                                 right.target_type = ma.value_type.copy ();
     192              :                         }
     193         2938 :                 } else if (left is ElementAccess) {
     194         1517 :                         unowned ElementAccess ea = (ElementAccess) left;
     195              : 
     196         3034 :                         check_constant_assignment (ea.container as MemberAccess);
     197              : 
     198         1517 :                         if (ea.container.value_type.type_symbol == context.analyzer.string_type.type_symbol) {
     199            0 :                                 error = true;
     200            0 :                                 Report.error (ea.source_reference, "strings are immutable");
     201            0 :                                 return false;
     202         1517 :                         } else if (ea.container.value_type.get_member ("set") is Method) {
     203           13 :                                 var set_call = new MethodCall (new MemberAccess (ea.container, "set", source_reference), source_reference);
     204           39 :                                 foreach (Expression e in ea.get_indices ()) {
     205           13 :                                         set_call.add_argument (e);
     206              :                                 }
     207              : 
     208           17 :                                 if (operator != AssignmentOperator.SIMPLE && ea.container.value_type.get_member ("get") is Method) {
     209              :                                         // transform into binary expression inside set call
     210            4 :                                         var get_call = new MethodCall (new MemberAccess (ea.container, "get", source_reference), source_reference);
     211           12 :                                         foreach (Expression e in ea.get_indices ()) {
     212            4 :                                                 get_call.add_argument (e);
     213              :                                         }
     214              : 
     215              :                                         BinaryOperator bop;
     216              : 
     217            4 :                                         switch (operator) {
     218              :                                         case AssignmentOperator.BITWISE_OR: bop = BinaryOperator.BITWISE_OR; break;
     219              :                                         case AssignmentOperator.BITWISE_AND: bop = BinaryOperator.BITWISE_AND; break;
     220              :                                         case AssignmentOperator.BITWISE_XOR: bop = BinaryOperator.BITWISE_XOR; break;
     221              :                                         case AssignmentOperator.ADD: bop = BinaryOperator.PLUS; break;
     222              :                                         case AssignmentOperator.SUB: bop = BinaryOperator.MINUS; break;
     223              :                                         case AssignmentOperator.MUL: bop = BinaryOperator.MUL; break;
     224              :                                         case AssignmentOperator.DIV: bop = BinaryOperator.DIV; break;
     225              :                                         case AssignmentOperator.PERCENT: bop = BinaryOperator.MOD; break;
     226              :                                         case AssignmentOperator.SHIFT_LEFT: bop = BinaryOperator.SHIFT_LEFT; break;
     227              :                                         case AssignmentOperator.SHIFT_RIGHT: bop = BinaryOperator.SHIFT_RIGHT; break;
     228              :                                         default:
     229            0 :                                                 error = true;
     230            0 :                                                 Report.error (source_reference, "internal error: unsupported assignment operator");
     231            0 :                                                 return false;
     232              :                                         }
     233              : 
     234            4 :                                         right = new BinaryExpression (bop, get_call, right, source_reference);
     235              :                                 }
     236              : 
     237           13 :                                 set_call.add_argument (right);
     238           13 :                                 parent_node.replace_expression (this, set_call);
     239           13 :                                 return set_call.check (context);
     240              :                         } else {
     241         1504 :                                 right.target_type = left.value_type.copy ();
     242              :                         }
     243         1421 :                 } else if (left is PointerIndirection) {
     244         1420 :                         right.target_type = left.value_type.copy ();
     245            1 :                 } else if (left is Literal) {
     246            1 :                         error = true;
     247            1 :                         Report.error (source_reference, "Literals are immutable");
     248            1 :                         return false;
     249              :                 } else {
     250            0 :                         error = true;
     251            0 :                         Report.error (source_reference, "unsupported lvalue in assignment");
     252            0 :                         return false;
     253              :                 }
     254              : 
     255       208732 :                 if (!right.check (context)) {
     256              :                         // skip on error in inner expression
     257            0 :                         error = true;
     258            0 :                         return false;
     259              :                 }
     260              : 
     261       208732 :                 unowned MemberAccess? ma = left as MemberAccess;
     262       208732 :                 unowned ElementAccess? ea = left as ElementAccess;
     263       208732 :                 bool transform_assignment = false;
     264              : 
     265       208732 :                 if (ma != null && !(ma.symbol_reference is LocalVariable)) {
     266              :                         transform_assignment = true;
     267       129687 :                 } else if (left.value_type != null && !left.value_type.is_non_null_simple_type ()) {
     268              :                         transform_assignment = true;
     269        99189 :                 } else if (ea != null && ea.container.value_type is ArrayType) {
     270              :                         // check if the left is an array and its element is non-null simple type
     271           61 :                         unowned ArrayType array_type = (ArrayType) ea.container.value_type;
     272           61 :                         transform_assignment = !array_type.element_type.is_non_null_simple_type ();
     273              :                 }
     274              : 
     275       211814 :                 if ((operator != AssignmentOperator.SIMPLE) && transform_assignment) {
     276              :                         // transform into simple assignment
     277              :                         // FIXME: only do this if the backend doesn't support
     278              :                         // the assignment natively
     279         3082 :                         Expression old_value = null;
     280              : 
     281         3082 :                         if (ma != null) {
     282         3076 :                                 old_value = new MemberAccess (ma.inner, ma.member_name, left.source_reference);
     283           12 :                         } else if (ea !=null) {
     284            6 :                                 old_value = new ElementAccess (ea.container, left.source_reference);
     285            6 :                                 var indices = ea.get_indices ();
     286           18 :                                 foreach (var index in indices) {
     287            6 :                                         ((ElementAccess) old_value).append_index (index);
     288              :                                 }
     289              :                         } else {
     290            0 :                                 assert_not_reached ();
     291              :                         }
     292              : 
     293              :                         BinaryOperator bop;
     294              : 
     295         3082 :                         switch (operator) {
     296              :                         case AssignmentOperator.BITWISE_OR: bop = BinaryOperator.BITWISE_OR; break;
     297              :                         case AssignmentOperator.BITWISE_AND: bop = BinaryOperator.BITWISE_AND; break;
     298              :                         case AssignmentOperator.BITWISE_XOR: bop = BinaryOperator.BITWISE_XOR; break;
     299              :                         case AssignmentOperator.ADD: bop = BinaryOperator.PLUS; break;
     300              :                         case AssignmentOperator.SUB: bop = BinaryOperator.MINUS; break;
     301              :                         case AssignmentOperator.MUL: bop = BinaryOperator.MUL; break;
     302              :                         case AssignmentOperator.DIV: bop = BinaryOperator.DIV; break;
     303              :                         case AssignmentOperator.PERCENT: bop = BinaryOperator.MOD; break;
     304              :                         case AssignmentOperator.SHIFT_LEFT: bop = BinaryOperator.SHIFT_LEFT; break;
     305              :                         case AssignmentOperator.SHIFT_RIGHT: bop = BinaryOperator.SHIFT_RIGHT; break;
     306              :                         default:
     307            0 :                                 error = true;
     308            0 :                                 Report.error (source_reference, "internal error: unsupported assignment operator");
     309            0 :                                 return false;
     310              :                         }
     311              : 
     312         3082 :                         var bin = new BinaryExpression (bop, old_value, right, source_reference);
     313         3082 :                         bin.target_type = right.target_type;
     314         3082 :                         right.target_type = right.target_type.copy ();
     315         3082 :                         right.target_type.value_owned = false;
     316              : 
     317         3082 :                         right = bin;
     318         3082 :                         right.check (context);
     319              : 
     320         3082 :                         operator = AssignmentOperator.SIMPLE;
     321              :                 }
     322              : 
     323       208732 :                 if (ma != null) {
     324       205808 :                         if (ma.symbol_reference is Property) {
     325         1477 :                                 unowned Property prop = (Property) ma.symbol_reference;
     326         1477 :                                 if (right.value_type == null) {
     327            1 :                                         error = true;
     328            1 :                                         Report.error (source_reference, "Assignment: Invalid assignment attempt");
     329            1 :                                         return false;
     330              :                                 }
     331              : 
     332         1476 :                                 unowned DynamicProperty? dynamic_prop = prop as DynamicProperty;
     333            3 :                                 if (dynamic_prop != null) {
     334            3 :                                         dynamic_prop.property_type = right.value_type.copy ();
     335            3 :                                         left.value_type = dynamic_prop.property_type.copy ();
     336              :                                 }
     337       204331 :                         } else if (ma.symbol_reference is ArrayLengthField && ((ArrayType) ma.inner.value_type).inline_allocated) {
     338            1 :                                 error = true;
     339            1 :                                 Report.error (source_reference, "`length' field of fixed length arrays is read-only");
     340            1 :                                 return false;
     341       204330 :                         } else if (ma.symbol_reference is Variable && right.value_type is MethodType) {
     342           18 :                                 unowned Variable variable = (Variable) ma.symbol_reference;
     343              : 
     344           18 :                                 if (variable.variable_type is DelegateType) {
     345              :                                         /* check whether method matches callback type */
     346           18 :                                         if (!right.value_type.compatible (variable.variable_type)) {
     347            2 :                                                 unowned Method m = (Method) right.symbol_reference;
     348            2 :                                                 unowned Delegate cb = ((DelegateType) variable.variable_type).delegate_symbol;
     349            2 :                                                 error = true;
     350            2 :                                                 Report.error (source_reference, "Declaration of method `%s' is not compatible with delegate `%s'", m.get_full_name (), cb.get_full_name ());
     351            2 :                                                 return false;
     352              :                                         }
     353              :                                 } else {
     354            0 :                                         error = true;
     355            0 :                                         Report.error (source_reference, "Assignment: Invalid assignment attempt");
     356            0 :                                         return false;
     357              :                                 }
     358       204312 :                         } else if (ma.symbol_reference is Variable && right.value_type == null) {
     359            1 :                                 error = true;
     360            1 :                                 Report.error (source_reference, "Assignment: Invalid assignment attempt");
     361            1 :                                 return false;
     362       204311 :                         } else if (ma.symbol_reference is Variable) {
     363       204310 :                                 unowned Variable variable = (Variable) ma.symbol_reference;
     364       204310 :                                 unowned ArrayType? variable_array_type = variable.variable_type as ArrayType;
     365          231 :                                 if (variable_array_type != null && variable_array_type.inline_allocated
     366            6 :                                     && right is ArrayCreationExpression && ((ArrayCreationExpression) right).initializer_list == null) {
     367            1 :                                         Report.warning (source_reference, "Inline allocated arrays don't require an explicit instantiation");
     368            1 :                                         ((Block) parent_node.parent_node).replace_statement ((Statement) parent_node, new EmptyStatement (source_reference));
     369            1 :                                         return true;
     370              :                                 }
     371              :                         }
     372              : 
     373       205802 :                         if (left.value_type != null && right.value_type != null) {
     374              :                                 /* if there was an error on either side,
     375              :                                  * i.e. {left|right}.value_type == null, skip type check */
     376              : 
     377       205802 :                                 if (!right.value_type.compatible (left.value_type)) {
     378            0 :                                         error = true;
     379            0 :                                         Report.error (source_reference, "Assignment: Cannot convert from `%s' to `%s'", right.value_type.to_string (), left.value_type.to_string ());
     380            0 :                                         return false;
     381       205802 :                                 } else if (left.value_type is EnumValueType && right.value_type is IntegerType
     382            8 :                                     && (!(right is IntegerLiteral) || ((IntegerLiteral) right).value != "0")) {
     383              :                                         //FIXME This will have to be an error in the future?
     384            1 :                                         Report.notice (source_reference, "Assignment: Unsafe conversion from `%s' to `%s'", right.value_type.to_string (), left.value_type.to_string ());
     385              :                                 }
     386              : 
     387       205802 :                                 if (!(ma.symbol_reference is Property)) {
     388       204326 :                                         if (right.value_type.is_disposable ()) {
     389              :                                                 /* rhs transfers ownership of the expression */
     390         3354 :                                                 if (!(left.value_type is PointerType) && !left.value_type.value_owned) {
     391              :                                                         /* lhs doesn't own the value */
     392            0 :                                                         error = true;
     393            0 :                                                         Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
     394              :                                                 }
     395       200972 :                                         } else if (left.value_type.value_owned) {
     396              :                                                 /* lhs wants to own the value
     397              :                                                  * rhs doesn't transfer the ownership
     398              :                                                  * code generator needs to add reference
     399              :                                                  * increment calls */
     400              :                                         }
     401              :                                 }
     402              :                         }
     403              : 
     404       205802 :                         unowned MemberAccess? right_ma = right as MemberAccess;
     405        29588 :                         if (right_ma != null && ma.symbol_reference == right_ma.symbol_reference) {
     406           69 :                                 if (ma.symbol_reference is LocalVariable || ma.symbol_reference is Parameter) {
     407            1 :                                         Report.warning (source_reference, "Assignment to same variable");
     408           68 :                                 } else if (ma.symbol_reference is Field) {
     409           24 :                                         unowned Field f = (Field) ma.symbol_reference;
     410           24 :                                         if (f.binding == MemberBinding.STATIC) {
     411            1 :                                                 Report.warning (source_reference, "Assignment to same variable");
     412              :                                         } else {
     413           23 :                                                 unowned MemberAccess? ma_inner = ma.inner as MemberAccess;
     414           23 :                                                 unowned MemberAccess? right_ma_inner = right_ma.inner as MemberAccess;
     415           23 :                                                 if (ma_inner != null && ma_inner.member_name == "this" && ma_inner.inner == null &&
     416            1 :                                                     right_ma_inner != null && right_ma_inner.member_name == "this" && right_ma_inner.inner == null) {
     417            1 :                                                         Report.warning (source_reference, "Assignment to same variable");
     418              :                                                 }
     419              :                                         }
     420              :                                 }
     421              :                         }
     422         2924 :                 } else if (ea != null) {
     423         1504 :                         if (!right.value_type.compatible (left.value_type)) {
     424            1 :                                 error = true;
     425            1 :                                 Report.error (source_reference, "Assignment: Cannot convert from `%s' to `%s'", right.value_type.to_string (), left.value_type.to_string ());
     426            1 :                                 return false;
     427              :                         }
     428              : 
     429         2925 :                         if (right.value_type.is_disposable ()) {
     430              :                                 /* rhs transfers ownership of the expression */
     431              : 
     432              :                                 DataType element_type;
     433              : 
     434         1423 :                                 if (ea.container.value_type is ArrayType) {
     435         1423 :                                         unowned ArrayType array_type = (ArrayType) ea.container.value_type;
     436         1423 :                                         element_type = array_type.element_type;
     437              :                                 } else {
     438            0 :                                         var args = ea.container.value_type.get_type_arguments ();
     439            0 :                                         assert (args.size == 1);
     440            0 :                                         element_type = args.get (0);
     441              :                                 }
     442              : 
     443         1423 :                                 if (!(element_type is PointerType) && !element_type.value_owned) {
     444              :                                         /* lhs doesn't own the value */
     445            1 :                                         error = true;
     446            1 :                                         Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
     447            1 :                                         return false;
     448              :                                 }
     449           80 :                         } else if (left.value_type.value_owned) {
     450              :                                 /* lhs wants to own the value
     451              :                                  * rhs doesn't transfer the ownership
     452              :                                  * code generator needs to add reference
     453              :                                  * increment calls */
     454              :                         }
     455              :                 } else {
     456         1421 :                         return true;
     457              :                 }
     458              : 
     459       207304 :                 if (left.value_type != null) {
     460       207304 :                         value_type = left.value_type.copy ();
     461       207304 :                         value_type.value_owned = false;
     462              :                 } else {
     463            0 :                         value_type = null;
     464              :                 }
     465              : 
     466       207304 :                 if (value_type != null) {
     467       207304 :                         value_type.check (context);
     468              :                 }
     469              : 
     470       207304 :                 return !error;
     471              :         }
     472              : 
     473        11308 :         bool is_array_add () {
     474        11308 :                 unowned BinaryExpression? binary = right as BinaryExpression;
     475         1445 :                 if (binary != null && binary.left.value_type is ArrayType) {
     476           69 :                         if (binary.operator == BinaryOperator.PLUS) {
     477           65 :                                 if (left.symbol_reference == binary.left.symbol_reference) {
     478              :                                         // Allow direct access to array variable
     479           65 :                                         binary.left.lvalue = true;
     480           65 :                                         return true;
     481              :                                 }
     482              :                         }
     483              :                 }
     484              : 
     485        11308 :                 return false;
     486              :         }
     487              : 
     488       207329 :         void check_constant_assignment (MemberAccess? inner) {
     489       215196 :                 while (inner != null) {
     490       215196 :                         if (inner.symbol_reference is Constant) {
     491            3 :                                 error = true;
     492            3 :                                 Report.error (source_reference, "Assignment to constant after initialization");
     493            3 :                                 break;
     494              :                         }
     495       215193 :                         if (inner.inner is MemberAccess) {
     496         7866 :                                 inner = (MemberAccess) inner.inner;
     497       207327 :                         } else if (inner.inner is ElementAccess) {
     498            1 :                                 inner = ((ElementAccess) inner.inner).container as MemberAccess;
     499              :                         } else {
     500              :                                 inner = null;
     501              :                         }
     502              :                 }
     503              :         }
     504              : 
     505        12971 :         public override void emit (CodeGenerator codegen) {
     506        12971 :                 unowned MemberAccess? ma = left as MemberAccess;
     507        12971 :                 unowned ElementAccess? ea = left as ElementAccess;
     508        12971 :                 unowned PointerIndirection? pi = left as PointerIndirection;
     509        12971 :                 if (ma != null) {
     510        12878 :                         unowned LocalVariable? local = ma.symbol_reference as LocalVariable;
     511        12878 :                         unowned Parameter? param = ma.symbol_reference as Parameter;
     512        12878 :                         unowned Field? field = ma.symbol_reference as Field;
     513        12878 :                         unowned Property? property = ma.symbol_reference as Property;
     514              : 
     515        12878 :                         bool instance = (field != null && field.binding != MemberBinding.STATIC)
     516        10809 :                                 || (property != null && property.binding != MemberBinding.STATIC);
     517              : 
     518        12878 :                         if (operator == AssignmentOperator.SIMPLE &&
     519        12784 :                             (local != null || param != null || field != null) &&
     520        11308 :                             !is_array_add () &&
     521        11243 :                             !(field is ArrayLengthField) &&
     522        11198 :                             !(field is DelegateTargetField) &&
     523        11196 :                             !(field is DelegateDestroyField) &&
     524        11194 :                                 !(left.value_type.is_real_non_null_struct_type () && right is ObjectCreationExpression)) {
     525              :                                 // visit_assignment not necessary
     526        11188 :                                 if (instance && ma.inner != null) {
     527         1981 :                                         ma.inner.emit (codegen);
     528              :                                 }
     529              : 
     530        11188 :                                 right.emit (codegen);
     531        11188 :                                 var new_value = right.target_value;
     532              : 
     533        11188 :                                 if (local != null) {
     534         8561 :                                         codegen.store_local (local, new_value, false, source_reference);
     535         2627 :                                 } else if (param != null) {
     536          326 :                                         codegen.store_parameter (param, new_value, false, source_reference);
     537         2301 :                                 } else if (field != null) {
     538         2621 :                                         codegen.store_field (field, instance && ma.inner != null ? ma.inner.target_value : null, new_value, false, source_reference);
     539              :                                 }
     540              : 
     541        11188 :                                 if (!(parent_node is ExpressionStatement)) {
     542              :                                         // when load_variable is changed to use temporary
     543              :                                         // variables, replace following code with this line
     544              :                                         // target_value = new_value;
     545           56 :                                         if (local != null) {
     546           48 :                                                 target_value = codegen.load_local (local);
     547            8 :                                         } else if (param != null) {
     548            0 :                                                 target_value = codegen.load_parameter (param);
     549            8 :                                         } else if (field != null) {
     550            8 :                                                 target_value = codegen.load_field (field, instance && ma.inner != null ? ma.inner.target_value : null);
     551              :                                         }
     552              :                                 }
     553              : 
     554        11188 :                                 codegen.visit_expression (this);
     555        11188 :                                 return;
     556              :                         }
     557              : 
     558         1690 :                         if (instance && ma.inner != null && property != null) {
     559         1469 :                                 ma.inner.emit (codegen);
     560          221 :                         } else if (property == null) {
     561              :                                 // always process full lvalue
     562              :                                 // current codegen depends on it
     563              :                                 // should be removed when moving codegen from
     564              :                                 // visit_assignment to emit_store_field/local/param
     565          214 :                                 ma.emit (codegen);
     566              :                         }
     567           93 :                 } else if (ea != null) {
     568              :                         // always process full lvalue
     569              :                         // current codegen depends on it
     570              :                         // should be removed when moving codegen from
     571              :                         // visit_assignment to emit_store_element
     572           88 :                         ea.emit (codegen);
     573            5 :                 } else if (pi != null) {
     574              :                         // always process full lvalue
     575              :                         // current codegen depends on it
     576              :                         // should be removed when moving codegen from
     577              :                         // visit_assignment to emit_store_indirectZ
     578            5 :                         pi.emit (codegen);
     579              :                 }
     580              : 
     581         1783 :                 right.emit (codegen);
     582              : 
     583         1783 :                 codegen.visit_assignment (this);
     584              : 
     585         1783 :                 codegen.visit_expression (this);
     586              :         }
     587              : 
     588       437403 :         public override void get_defined_variables (Collection<Variable> collection) {
     589       437403 :                 right.get_defined_variables (collection);
     590       437403 :                 left.get_defined_variables (collection);
     591       437403 :                 unowned LocalVariable? local = left.symbol_reference as LocalVariable;
     592       437403 :                 unowned Parameter? param = left.symbol_reference as Parameter;
     593       437403 :                 if (local != null) {
     594       266346 :                         collection.add (local);
     595       171057 :                 } else if (param != null && param.direction == ParameterDirection.OUT) {
     596        95682 :                         collection.add (param);
     597              :                 }
     598              :         }
     599              : 
     600       145801 :         public override void get_used_variables (Collection<Variable> collection) {
     601       145801 :                 unowned MemberAccess? ma = left as MemberAccess;
     602       145801 :                 unowned ElementAccess? ea = left as ElementAccess;
     603       145801 :                 if (ma != null && ma.inner != null) {
     604         6365 :                         ma.inner.get_used_variables (collection);
     605       139436 :                 } else if (ea != null) {
     606         1050 :                         ea.get_used_variables (collection);
     607              :                 }
     608       145801 :                 right.get_used_variables (collection);
     609              :         }
     610              : }
     611              : 
     612              : public enum Vala.AssignmentOperator {
     613              :         NONE,
     614              :         SIMPLE,
     615              :         BITWISE_OR,
     616              :         BITWISE_AND,
     617              :         BITWISE_XOR,
     618              :         ADD,
     619              :         SUB,
     620              :         MUL,
     621              :         DIV,
     622              :         PERCENT,
     623              :         SHIFT_LEFT,
     624              :         SHIFT_RIGHT;
     625              : 
     626              :         public unowned string to_string () {
     627            0 :                 switch (this) {
     628            0 :                 case SIMPLE: return "=";
     629            0 :                 case BITWISE_OR: return "|=";
     630            0 :                 case BITWISE_AND: return "&=";
     631            0 :                 case BITWISE_XOR: return "^=";
     632            0 :                 case ADD: return "+=";
     633            0 :                 case SUB: return "-=";
     634            0 :                 case MUL: return "*=";
     635            0 :                 case DIV: return "/=";
     636            0 :                 case PERCENT: return "%=";
     637            0 :                 case SHIFT_LEFT: return "<<=";
     638            0 :                 case SHIFT_RIGHT: return ">>=";
     639            0 :                 default: assert_not_reached ();
     640              :                 }
     641              :         }
     642              : }
        

Generated by: LCOV version 2.0-1