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

            Line data    Source code
       1              : /* valainitializerlist.vala
       2              :  *
       3              :  * Copyright (C) 2006-2011  Jürg Billeter
       4              :  * Copyright (C) 2006-2008  Raffaele Sandrini
       5              :  *
       6              :  * This library is free software; you can redistribute it and/or
       7              :  * modify it under the terms of the GNU Lesser General Public
       8              :  * License as published by the Free Software Foundation; either
       9              :  * version 2.1 of the License, or (at your option) any later version.
      10              : 
      11              :  * This library is distributed in the hope that it will be useful,
      12              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14              :  * Lesser General Public License for more details.
      15              : 
      16              :  * You should have received a copy of the GNU Lesser General Public
      17              :  * License along with this library; if not, write to the Free Software
      18              :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
      19              :  *
      20              :  * Author:
      21              :  *      Jürg Billeter <j@bitron.ch>
      22              :  *      Raffaele Sandrini <raffaele@sandrini.ch>
      23              :  */
      24              : 
      25              : using GLib;
      26              : 
      27              : /**
      28              :  * Represents an array or struct initializer list in the source code.
      29              :  */
      30         2314 : public class Vala.InitializerList : Expression {
      31         2106 :         private List<Expression> initializers = new ArrayList<Expression> ();
      32              : 
      33              :         /**
      34              :          * Appends the specified expression to this initializer
      35              :          *
      36              :          * @param expr an expression
      37              :          */
      38         2991 :         public void append (Expression expr) {
      39         2991 :                 initializers.add (expr);
      40         2991 :                 expr.parent_node = this;
      41              :         }
      42              : 
      43              :         /**
      44              :          * Returns the initializer expression list
      45              :          *
      46              :          * @return expression list
      47              :          */
      48         4518 :         public unowned List<Expression> get_initializers () {
      49         4518 :                 return initializers;
      50              :         }
      51              : 
      52              :         /**
      53              :          * Returns the initializer count in this initializer
      54              :          */
      55              :         public int size {
      56         1797 :                 get { return initializers.size; }
      57              :         }
      58              : 
      59              :         /**
      60              :          * Creates a new initializer
      61              :          *
      62              :          * @param source_reference reference to source code
      63              :          * @return                 newly created initializer list
      64              :          */
      65         2106 :         public InitializerList (SourceReference? source_reference = null) {
      66         1053 :                 this.source_reference = source_reference;
      67              :         }
      68              : 
      69        14817 :         public override void accept_children (CodeVisitor visitor) {
      70       209283 :                 foreach (Expression expr in initializers) {
      71        97233 :                         expr.accept (visitor);
      72              :                 }
      73              :         }
      74              : 
      75        14817 :         public override void accept (CodeVisitor visitor) {
      76        14817 :                 visitor.visit_initializer_list (this);
      77              : 
      78        14817 :                 visitor.visit_expression (this);
      79              :         }
      80              : 
      81          229 :         public override bool is_constant () {
      82         2521 :                 foreach (Expression initializer in initializers) {
      83         1147 :                         if (!initializer.is_constant ()) {
      84            1 :                                 return false;
      85              :                         }
      86              :                 }
      87          228 :                 return !(target_type == null || target_type.is_disposable ());
      88              :         }
      89              : 
      90            0 :         public override bool is_pure () {
      91            0 :                 foreach (Expression initializer in initializers) {
      92            0 :                         if (!initializer.is_pure ()) {
      93            0 :                                 return false;
      94              :                         }
      95              :                 }
      96            0 :                 return true;
      97              :         }
      98              : 
      99          217 :         public override bool is_accessible (Symbol sym) {
     100         2463 :                 foreach (Expression initializer in initializers) {
     101         1123 :                         if (!initializer.is_accessible (sym)) {
     102            0 :                                 return false;
     103              :                         }
     104              :                 }
     105              : 
     106          217 :                 return true;
     107              :         }
     108              : 
     109            0 :         public override string to_string () {
     110            0 :                 var builder = new StringBuilder ("{");
     111            0 :                 bool first = true;
     112            0 :                 foreach (var initializer in initializers) {
     113            0 :                         if (first) {
     114            0 :                                 builder.append (initializer.to_string ());
     115            0 :                                 first = false;
     116              :                         } else {
     117            0 :                                 builder.append_printf (", %s", initializer.to_string ());
     118              :                         }
     119              :                 }
     120            0 :                 builder.append_c ('}');
     121            0 :                 return builder.str;
     122              :         }
     123              : 
     124           32 :         public override void replace_expression (Expression old_node, Expression new_node) {
     125          114 :                 for (int i = 0; i < initializers.size; i++) {
     126           82 :                         if (initializers[i] == old_node) {
     127           32 :                                 initializers[i] = new_node;
     128           32 :                                 new_node.parent_node = this;
     129              :                         }
     130              :                 }
     131              :         }
     132              : 
     133         1611 :         public override bool check (CodeContext context) {
     134         1611 :                 if (checked) {
     135            1 :                         return !error;
     136              :                 }
     137              : 
     138         1610 :                 checked = true;
     139              : 
     140         1610 :                 if (target_type == null) {
     141            0 :                         error = true;
     142            0 :                         Report.error (source_reference, "initializer list used for unknown type");
     143            0 :                         return false;
     144         1610 :                 } else if (target_type.error) {
     145            1 :                         error = true;
     146            1 :                         return false;
     147         2336 :                 } else if (target_type is ArrayType) {
     148              :                         /* initializer is used as array initializer */
     149         1294 :                         unowned ArrayType array_type = (ArrayType) target_type;
     150              : 
     151         1294 :                         bool requires_constants_only = false;
     152         1294 :                         bool is_global_constant_inline = false;
     153         1294 :                         unowned CodeNode? node = parent_node;
     154        10875 :                         while (node != null) {
     155         9638 :                                 if (node is Constant) {
     156              :                                         requires_constants_only = true;
     157              :                                         break;
     158         9581 :                                 } else if (node is Field && ((Field) node).parent_symbol is Namespace) {
     159            2 :                                         is_global_constant_inline = array_type.inline_allocated && is_constant ();
     160              :                                 }
     161         9581 :                                 node = node.parent_node;
     162              :                         }
     163              : 
     164         1294 :                         if (!(parent_node is ArrayCreationExpression) && !requires_constants_only && !is_global_constant_inline
     165          618 :                             && (!(parent_node is InitializerList) || ((InitializerList) parent_node).target_type.type_symbol is Struct)) {
     166              :                                 // transform shorthand form
     167              :                                 //     int[] array = { 42 };
     168              :                                 // into
     169              :                                 //     int[] array = new int[] { 42 };
     170              : 
     171          631 :                                 var old_parent_node = parent_node;
     172              : 
     173          567 :                                 var array_creation = new ArrayCreationExpression (array_type.element_type.copy (), array_type.rank, this, source_reference);
     174          567 :                                 array_creation.length_type = array_type.length_type.copy ();
     175          567 :                                 array_creation.target_type = target_type;
     176          567 :                                 array_creation.formal_target_type = formal_target_type;
     177          567 :                                 old_parent_node.replace_expression (this, array_creation);
     178              : 
     179          567 :                                 checked = false;
     180          567 :                                 return array_creation.check (context);
     181              :                         }
     182              : 
     183              :                         DataType inner_target_type;
     184          727 :                         if (array_type.rank > 1) {
     185              :                                 // allow initialization of multi-dimensional arrays
     186           31 :                                 var inner_array_type = (ArrayType) array_type.copy ();
     187           31 :                                 inner_array_type.rank--;
     188          758 :                                 inner_target_type = inner_array_type;
     189              :                         } else {
     190          696 :                                 inner_target_type = array_type.element_type.copy ();
     191              :                         }
     192              : 
     193         4479 :                         foreach (Expression e in get_initializers ()) {
     194         1876 :                                 e.target_type = inner_target_type;
     195              :                         }
     196          601 :                 } else if (target_type.type_symbol is Struct) {
     197              :                         /* initializer is used as struct initializer */
     198          313 :                         unowned Struct st = (Struct) target_type.type_symbol;
     199          323 :                         while (st.base_struct != null) {
     200           10 :                                 st = st.base_struct;
     201              :                         }
     202              : 
     203          313 :                         var in_array_creation_initializer = parent_node is InitializerList && parent_node.parent_node is ArrayCreationExpression;
     204           27 :                         ObjectCreationExpression? struct_creation = null;
     205          193 :                         if (in_array_creation_initializer) {
     206           27 :                                 unowned Symbol? sym = st;
     207           27 :                                 var ma = new MemberAccess.simple (sym.name, source_reference);
     208           27 :                                 ma.symbol_reference = sym;
     209           27 :                                 MemberAccess inner = ma;
     210           39 :                                 while (sym.parent_symbol != null && sym.parent_symbol != context.root) {
     211            6 :                                         sym = sym.parent_symbol;
     212            6 :                                         var ma_inner = new MemberAccess.simple (sym.name, source_reference);
     213            6 :                                         inner.inner = ma_inner;
     214           12 :                                         inner = ma_inner;
     215              :                                 }
     216           27 :                                 struct_creation = new ObjectCreationExpression (ma, source_reference);
     217           27 :                                 struct_creation.target_type = target_type.copy ();
     218           27 :                                 struct_creation.struct_creation = true;
     219              :                         }
     220              : 
     221          313 :                         var field_it = st.get_fields ().iterator ();
     222         2525 :                         foreach (Expression e in get_initializers ()) {
     223         1106 :                                 Field field = null;
     224         2212 :                                 while (field == null) {
     225         1106 :                                         if (!field_it.next ()) {
     226            0 :                                                 error = true;
     227            0 :                                                 Report.error (e.source_reference, "too many expressions in initializer list for `%s'", target_type.to_string ());
     228            0 :                                                 return false;
     229              :                                         }
     230         1106 :                                         field = field_it.get ();
     231         1106 :                                         if (field.binding != MemberBinding.INSTANCE) {
     232              :                                                 // we only initialize instance fields
     233         1106 :                                                 field = null;
     234              :                                         }
     235              :                                 }
     236              : 
     237         1143 :                                 if (in_array_creation_initializer) {
     238           37 :                                         var member_init = new MemberInitializer (field.name, e, e.source_reference);
     239           37 :                                         struct_creation.add_member_initializer (member_init);
     240              :                                 } else {
     241         1069 :                                         e.target_type = field.variable_type.copy ();
     242         1069 :                                         if (!target_type.value_owned) {
     243          896 :                                                 e.target_type.value_owned = false;
     244              :                                         }
     245              :                                 }
     246              :                         }
     247              : 
     248          313 :                         if (in_array_creation_initializer) {
     249           27 :                                 parent_node.replace_expression (this, struct_creation);
     250           27 :                                 checked = false;
     251           27 :                                 return struct_creation.check (context);
     252              :                         }
     253              :                 } else {
     254            2 :                         error = true;
     255            2 :                         Report.error (source_reference, "initializer list used for `%s', which is neither array nor struct", target_type.to_string ());
     256            2 :                         return false;
     257              :                 }
     258              : 
     259         6903 :                 foreach (Expression expr in initializers) {
     260         2945 :                         if (!expr.check (context)) {
     261            1 :                                 error = true;
     262              :                         }
     263              :                 }
     264              : 
     265         1013 :                 if (error) {
     266            4 :                         return false;
     267              :                 }
     268              : 
     269         6900 :                 foreach (Expression e in get_initializers ()) {
     270         2944 :                         if (e.value_type == null) {
     271            0 :                                 error = true;
     272            0 :                                 Report.error (e.source_reference, "expression type not allowed as initializer");
     273            0 :                                 continue;
     274              :                         }
     275              : 
     276         2944 :                         if (e is NullLiteral && e.target_type != null && e.target_type.is_real_non_null_struct_type ()) {
     277              :                                 // Allow using null instead of {} to initialize struct
     278         2942 :                         } else if (!e.value_type.compatible (e.target_type)) {
     279            1 :                                 error = true;
     280            1 :                                 e.error = true;
     281            1 :                                 Report.error (e.source_reference, "Expected initializer of type `%s' but got `%s'", e.target_type.to_string (), e.value_type.to_string ());
     282              :                         }
     283              :                 }
     284              : 
     285         1012 :                 if (!error) {
     286              :                         /* everything seems to be correct */
     287         1011 :                         value_type = target_type.copy ();
     288         1011 :                         value_type.nullable = false;
     289              :                 }
     290              : 
     291         1012 :                 if (value_type != null) {
     292         1011 :                         value_type.check (context);
     293              :                 }
     294              : 
     295         1012 :                 return !error;
     296              :         }
     297              : 
     298         1057 :         public override void emit (CodeGenerator codegen) {
     299         7233 :                 foreach (Expression expr in initializers) {
     300         3088 :                         expr.emit (codegen);
     301              :                 }
     302              : 
     303         1057 :                 codegen.visit_initializer_list (this);
     304              : 
     305         1057 :                 codegen.visit_expression (this);
     306              :         }
     307              : 
     308          757 :         public override void get_used_variables (Collection<Variable> collection) {
     309         4247 :                 foreach (Expression expr in initializers) {
     310         1745 :                         expr.get_used_variables (collection);
     311              :                 }
     312              :         }
     313              : }
        

Generated by: LCOV version 2.0-1