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

            Line data    Source code
       1              : /* valaelementaccess.vala
       2              :  *
       3              :  * Copyright (C) 2006-2010  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              :  *      Raffaele Sandrini <raffaele@sandrini.ch>
      22              :  *      Jürg Billeter <j@bitron.ch>
      23              :  */
      24              : 
      25              : using GLib;
      26              : 
      27              : /**
      28              :  * Represents an array access expression.
      29              :  *
      30              :  * {{{ foo[1,2] }}}
      31              :  */
      32        50604 : public class Vala.ElementAccess : Expression {
      33              :         /**
      34              :          * Expression representing the container on which we want to access.
      35              :          */
      36              :         public Expression container {
      37       349700 :                 get {
      38       349700 :                         return _container;
      39              :                 }
      40        24539 :                 set {
      41        24539 :                         _container = value;
      42        24539 :                         _container.parent_node = this;
      43              :                 }
      44              :         }
      45              : 
      46              :         /**
      47              :          * Null-safe access.
      48              :          */
      49        24522 :         public bool null_safe_access { get; set; }
      50              : 
      51              :         /**
      52              :          * Expressions representing the indices we want to access inside the container.
      53              :          */
      54        49074 :         private List<Expression> indices = new ArrayList<Expression> ();
      55              : 
      56        24537 :         Expression _container;
      57              : 
      58        24605 :         public void append_index (Expression index) {
      59        24605 :                 indices.add (index);
      60        24605 :                 index.parent_node = this;
      61              :         }
      62              : 
      63        86414 :         public unowned List<Expression> get_indices () {
      64        86414 :                 return indices;
      65              :         }
      66              : 
      67        73611 :         public ElementAccess (Expression container, SourceReference? source_reference = null) {
      68        24537 :                 this.source_reference = source_reference;
      69        24537 :                 this.container = container;
      70              :         }
      71              : 
      72        74924 :         public override void accept (CodeVisitor visitor) {
      73        74924 :                 visitor.visit_element_access (this);
      74              : 
      75        74924 :                 visitor.visit_expression (this);
      76              :         }
      77              : 
      78        74924 :         public override void accept_children (CodeVisitor visitor) {
      79        74924 :                 container.accept (visitor);
      80       225200 :                 foreach (Expression e in indices) {
      81        75138 :                         e.accept (visitor);
      82              :                 }
      83              :         }
      84              : 
      85            0 :         public override string to_string () {
      86            0 :                 var s = "%s[".printf (container.to_string ());
      87            0 :                 bool first = true;
      88            0 :                 foreach (var index in indices) {
      89            0 :                         if (first) {
      90            0 :                                 s += index.to_string ();
      91            0 :                                 first = false;
      92              :                         } else {
      93            0 :                                 s += ", %s".printf (index.to_string ());
      94              :                         }
      95              :                 }
      96            0 :                 return s + "]";
      97              :         }
      98              : 
      99            2 :         public override void replace_expression (Expression old_node, Expression new_node) {
     100            2 :                 if (container == old_node) {
     101            2 :                         container = new_node;
     102              :                 }
     103              : 
     104            2 :                 int index = indices.index_of (old_node);
     105            2 :                 if (index >= 0) {
     106            0 :                         indices[index] = new_node;
     107            0 :                         new_node.parent_node = this;
     108              :                 }
     109              :         }
     110              : 
     111            0 :         public override bool is_pure () {
     112            0 :                 foreach (Expression index in indices) {
     113            0 :                         if (!index.is_pure ()) {
     114            0 :                                 return false;
     115              :                         }
     116              :                 }
     117            0 :                 return container.is_pure ();
     118              :         }
     119              : 
     120            0 :         public override bool is_accessible (Symbol sym) {
     121            0 :                 foreach (Expression index in indices) {
     122            0 :                         if (!index.is_accessible (sym)) {
     123            0 :                                 return false;
     124              :                         }
     125              :                 }
     126              : 
     127            0 :                 return container.is_accessible (sym);
     128              :         }
     129              : 
     130        34916 :         public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
     131        34916 :                 container.get_error_types (collection, source_reference);
     132       105480 :                 foreach (Expression e in indices) {
     133        35282 :                         e.get_error_types (collection, source_reference);
     134              :                 }
     135              :         }
     136              : 
     137        30634 :         public override bool check (CodeContext context) {
     138        30634 :                 if (checked) {
     139         7808 :                         return !error;
     140              :                 }
     141              : 
     142        22826 :                 checked = true;
     143              : 
     144        22826 :                 if (null_safe_access) {
     145            3 :                         error = !base.check (context);
     146            3 :                         return !error;
     147              :                 }
     148              : 
     149        22823 :                 if (!container.check (context)) {
     150              :                         /* don't proceed if a child expression failed */
     151            0 :                         error = true;
     152            0 :                         return false;
     153              :                 }
     154              : 
     155        22823 :                 if (container.value_type == null) {
     156            0 :                         error = true;
     157            0 :                         Report.error (container.source_reference, "Invalid container expression");
     158            0 :                         return false;
     159              :                 }
     160              : 
     161        22839 :                 if (container is MemberAccess && container.symbol_reference is Signal) {
     162              :                         // signal detail access
     163           18 :                         if (get_indices ().size != 1) {
     164            1 :                                 error = true;
     165            1 :                                 Report.error (source_reference, "Element access with more than one dimension is not supported for signals");
     166            1 :                                 return false;
     167              :                         }
     168              : 
     169           17 :                         var detail_expr = get_indices ().get (0);
     170           17 :                         detail_expr.target_type = context.analyzer.string_type.copy ();
     171           17 :                         detail_expr.check (context);
     172              : 
     173           17 :                         if (detail_expr.value_type is NullType || !detail_expr.value_type.compatible (context.analyzer.string_type)) {
     174            1 :                                 error = true;
     175            1 :                                 Report.error (detail_expr.source_reference, "only string details are supported");
     176            1 :                                 return false;
     177              :                         }
     178              :                 }
     179              : 
     180        68597 :                 foreach (Expression index in get_indices ()) {
     181        22888 :                         index.check (context);
     182              :                 }
     183              : 
     184        22821 :                 bool index_int_type_check = true;
     185              : 
     186        22821 :                 unowned PointerType? pointer_type = container.value_type as PointerType;
     187              : 
     188              :                 /* assign a value_type when possible */
     189        22821 :                 if (container.value_type is ArrayType) {
     190        19636 :                         unowned ArrayType array_type = (ArrayType) container.value_type;
     191        19636 :                         value_type = array_type.element_type.copy ();
     192        19636 :                         if (!lvalue) {
     193        13883 :                                 value_type.value_owned = false;
     194              :                         } else {
     195         5753 :                                 unowned MemberAccess? ma = container as MemberAccess;
     196         5753 :                                 if (context.profile == Profile.GOBJECT && ma != null && ma.symbol_reference is ArrayLengthField) {
     197              :                                         // propagate lvalue for gobject length access
     198            1 :                                         ma.inner.lvalue = true;
     199            1 :                                         ((MemberAccess) ma.inner).check_lvalue_access ();
     200         5752 :                                 } else if (ma != null && ma.symbol_reference is Field &&
     201         4251 :                                         ma.inner != null && ma.inner.symbol_reference is Variable &&
     202         4249 :                                         ma.inner.value_type is StructValueType && !ma.inner.value_type.nullable) {
     203              :                                         // propagate lvalue if container is a field and container.inner is a struct variable
     204            1 :                                         ma.lvalue = true;
     205            1 :                                         ma.check_lvalue_access ();
     206              :                                 }
     207              :                         }
     208              : 
     209        19636 :                         if (array_type.rank < get_indices ().size) {
     210            0 :                                 error = true;
     211            0 :                                 Report.error (source_reference, "%d extra indices for element access", get_indices ().size - array_type.rank);
     212        19636 :                         } else if (array_type.rank > get_indices ().size) {
     213            0 :                                 error = true;
     214            0 :                                 Report.error (source_reference, "%d missing indices for element access", array_type.rank - get_indices ().size);
     215              :                         }
     216         3185 :                 } else if (pointer_type != null && !pointer_type.base_type.is_reference_type_or_type_parameter ()) {
     217         2842 :                         value_type = pointer_type.base_type.copy ();
     218          343 :                 } else if (container is MemberAccess && container.symbol_reference is Signal) {
     219           16 :                         index_int_type_check = false;
     220              : 
     221           16 :                         symbol_reference = container.symbol_reference;
     222           16 :                         value_type = container.value_type;
     223              :                 } else {
     224          327 :                         if (lvalue) {
     225           13 :                                 var set_method = container.value_type.get_member ("set") as Method;
     226           13 :                                 unowned Assignment? assignment = parent_node as Assignment;
     227           13 :                                 if (assignment != null && set_method != null
     228           13 :                                     && (set_method.return_type is VoidType || set_method.return_type is BooleanType)) {
     229           13 :                                         return !error;
     230              :                                 }
     231              :                         } else {
     232          314 :                                 var get_method = container.value_type.get_member ("get") as Method;
     233          313 :                                 if (get_method != null) {
     234          313 :                                         var get_call = new MethodCall (new MemberAccess (container, "get", source_reference), source_reference);
     235          939 :                                         foreach (Expression e in get_indices ()) {
     236          313 :                                                 get_call.add_argument (e);
     237              :                                         }
     238          313 :                                         get_call.formal_target_type = this.formal_target_type;
     239          313 :                                         get_call.target_type = this.target_type;
     240          313 :                                         parent_node.replace_expression (this, get_call);
     241          313 :                                         return get_call.check (context);
     242              :                                 }
     243              :                         }
     244              : 
     245            1 :                         error = true;
     246            1 :                         Report.error (source_reference, "The expression `%s' does not denote an array", container.value_type.to_string ());
     247            1 :                         return false;
     248              :                 }
     249              : 
     250         2858 :                 if (index_int_type_check) {
     251              :                         /* check if the index is of type integer */
     252        67568 :                         foreach (Expression e in get_indices ()) {
     253              :                                 /* don't proceed if a child expression failed */
     254        22545 :                                 if (e.value_type == null) {
     255            0 :                                         return false;
     256              :                                 }
     257              : 
     258              :                                 /* check if the index is of type integer */
     259        22545 :                                 if (!(e.value_type is IntegerType || e.value_type is EnumValueType)) {
     260            0 :                                         error = true;
     261            0 :                                         Report.error (e.source_reference, "Expression of integer type expected");
     262              :                                 }
     263              :                         }
     264              :                 }
     265              : 
     266        22494 :                 value_type.check (context);
     267              : 
     268        22494 :                 return !error;
     269              :         }
     270              : 
     271         1469 :         public override void emit (CodeGenerator codegen) {
     272         1469 :                 container.emit (codegen);
     273         4541 :                 foreach (Expression e in indices) {
     274         1536 :                         e.emit (codegen);
     275              :                 }
     276              : 
     277         1469 :                 codegen.visit_element_access (this);
     278              : 
     279         1469 :                 codegen.visit_expression (this);
     280              :         }
     281              : 
     282        47085 :         public override void get_defined_variables (Collection<Variable> collection) {
     283        47085 :                 container.get_defined_variables (collection);
     284       141657 :                 foreach (Expression index in indices) {
     285        47286 :                         index.get_defined_variables (collection);
     286              :                 }
     287              :         }
     288              : 
     289        15695 :         public override void get_used_variables (Collection<Variable> collection) {
     290        15695 :                 container.get_used_variables (collection);
     291        47219 :                 foreach (Expression index in indices) {
     292        15762 :                         index.get_used_variables (collection);
     293              :                 }
     294              :         }
     295              : }
        

Generated by: LCOV version 2.0-1