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

            Line data    Source code
       1              : /* valastruct.vala
       2              :  *
       3              :  * Copyright (C) 2006-2010  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 a struct declaration in the source code.
      27              :  */
      28       289734 : public class Vala.Struct : TypeSymbol, GenericSymbol {
      29       286658 :         private List<TypeParameter> type_parameters = new ArrayList<TypeParameter> ();
      30       286658 :         private List<Constant> constants = new ArrayList<Constant> ();
      31       286658 :         private List<Field> fields = new ArrayList<Field> ();
      32       286658 :         private List<Method> methods = new ArrayList<Method> ();
      33       286658 :         private List<Property> properties = new ArrayList<Property> ();
      34       286658 :         private Set<weak Field> property_fields = new HashSet<weak Field> ();
      35       143329 :         private DataType _base_type = null;
      36              : 
      37       143329 :         private bool? boolean_type;
      38       143329 :         private bool? integer_type;
      39       143329 :         private bool? floating_type;
      40       143329 :         private bool? decimal_floating_type;
      41       143329 :         private bool? simple_type;
      42       143329 :         private int? _rank;
      43       143329 :         private int? _width;
      44       143329 :         private bool? _signed;
      45       143329 :         private bool? _is_immutable;
      46              : 
      47              :         /**
      48              :          * Specifies the base type.
      49              :          */
      50              :         public DataType? base_type {
      51     10707670 :                 get {
      52     10707670 :                         return _base_type;
      53              :                 }
      54        21757 :                 set {
      55        21757 :                         value.parent_node = this;
      56       210306 :                         _base_type = value;
      57              :                 }
      58              :         }
      59              : 
      60              :         /**
      61              :          * Specifies the base Struct.
      62              :          */
      63              :         public Struct? base_struct {
      64      9070933 :                 get {
      65      9070933 :                         if (_base_type != null) {
      66      1624877 :                                 return _base_type.type_symbol as Struct;
      67              :                         }
      68      9070933 :                         return null;
      69              :                 }
      70              :         }
      71              : 
      72              :         /**
      73              :          * Specifies the default construction method.
      74              :          */
      75       196024 :         public CreationMethod? default_construction_method { get; private set; }
      76              : 
      77              :         /**
      78              :          * Specifies if 'const' should be emitted for input parameters
      79              :          * of this type.
      80              :          */
      81              :         public bool is_immutable {
      82          205 :                 get {
      83          205 :                         if (_is_immutable == null) {
      84       109004 :                                 _is_immutable = has_attribute ("Immutable");
      85              :                         }
      86          205 :                         return _is_immutable;
      87              :                 }
      88            0 :                 set {
      89            0 :                         _is_immutable = value;
      90            0 :                         set_attribute ("Immutable", value);
      91              :                 }
      92              :         }
      93              : 
      94              :         public int width {
      95           14 :                 get {
      96           14 :                         if (_width == null) {
      97            7 :                                 if (is_integer_type ()) {
      98        25752 :                                         _width = get_attribute_integer ("IntegerType", "width", 32);
      99              :                                 } else {
     100            2 :                                         _width = get_attribute_integer ("FloatingType", "width", 32);
     101              :                                 }
     102              :                         }
     103           14 :                         return _width;
     104              :                 }
     105            0 :                 set {
     106            0 :                         _width = value;
     107            0 :                         if (is_integer_type ()) {
     108            0 :                                 set_attribute_integer ("IntegerType", "width", value);
     109              :                         } else {
     110            0 :                                 set_attribute_integer ("FloatingType", "width", value);
     111              :                         }
     112              :                 }
     113              :         }
     114              : 
     115              :         public bool signed {
     116           10 :                 get {
     117           10 :                         if (_signed == null) {
     118            5 :                                 _signed = get_attribute_bool ("IntegerType", "signed", true);
     119              :                         }
     120           10 :                         return _signed;
     121              :                 }
     122            0 :                 set {
     123            0 :                         _signed = value;
     124            0 :                         set_attribute_bool ("IntegerType", "signed", value);
     125              :                 }
     126              :         }
     127              : 
     128              :         /**
     129              :          * Specifies the rank of this integer or floating point type.
     130              :          */
     131              :         public int rank {
     132       356514 :                 get {
     133       356514 :                         if (_rank == null) {
     134        12869 :                                 if (is_integer_type () && has_attribute_argument ("IntegerType", "rank")) {
     135        11407 :                                         _rank = get_attribute_integer ("IntegerType", "rank");
     136         1462 :                                 } else if (has_attribute_argument ("FloatingType", "rank")) {
     137         1441 :                                         _rank = get_attribute_integer ("FloatingType", "rank");
     138              :                                 } else {
     139           21 :                                         var st = base_struct;
     140           21 :                                         if (st != null) {
     141           21 :                                                 _rank = st.rank;
     142              :                                         } else {
     143            0 :                                                 Report.error (source_reference, "internal error: struct has no rank");
     144            0 :                                                 return 0;
     145              :                                         }
     146              :                                 }
     147              :                         }
     148       356514 :                         return _rank;
     149              :                 }
     150            0 :                 set {
     151            0 :                         _rank = value;
     152            0 :                         if (is_integer_type ()) {
     153            0 :                                 set_attribute_integer ("IntegerType", "rank", _rank);
     154              :                         } else {
     155            0 :                                 set_attribute_integer ("FloatingType", "rank", _rank);
     156              :                         }
     157              :                 }
     158              :         }
     159              : 
     160              :         /**
     161              :          * Creates a new struct.
     162              :          *
     163              :          * @param name             type name
     164              :          * @param source_reference reference to source code
     165              :          * @return                 newly created struct
     166              :          */
     167       429987 :         public Struct (string name, SourceReference? source_reference = null, Comment? comment = null) {
     168       143329 :                 base (name, source_reference, comment);
     169              :         }
     170              : 
     171              :         /**
     172              :          * Appends the specified parameter to the list of type parameters.
     173              :          *
     174              :          * @param p a type parameter
     175              :          */
     176         9178 :         public void add_type_parameter (TypeParameter p) {
     177         9178 :                 type_parameters.add (p);
     178         9178 :                 scope.add (p.name, p);
     179              :         }
     180              : 
     181              :         /**
     182              :          * Returns the type parameter list.
     183              :          *
     184              :          * @return list of type parameters
     185              :          */
     186     13726948 :         public unowned List<TypeParameter> get_type_parameters () {
     187     13726948 :                 return type_parameters;
     188              :         }
     189              : 
     190            0 :         public bool has_type_parameters () {
     191            0 :                 return (type_parameters != null && type_parameters.size > 0);
     192              :         }
     193              : 
     194              :         /**
     195              :          * Adds the specified constant as a member to this struct.
     196              :          *
     197              :          * @param c a constant
     198              :          */
     199       177430 :         public override void add_constant (Constant c) {
     200       177430 :                 constants.add (c);
     201       177430 :                 scope.add (c.name, c);
     202              :         }
     203              : 
     204              :         /**
     205              :          * Adds the specified field as a member to this struct.
     206              :          *
     207              :          * @param f a field
     208              :          */
     209       254165 :         public override void add_field (Field f) {
     210       254165 :                 f.access = SymbolAccessibility.PUBLIC;
     211              : 
     212       254165 :                 fields.add (f);
     213       254165 :                 scope.add (f.name, f);
     214              :         }
     215              : 
     216              :         /**
     217              :          * Returns the list of fields.
     218              :          *
     219              :          * @return list of fields
     220              :          */
     221         8079 :         public unowned List<Field> get_fields () {
     222         8079 :                 return fields;
     223              :         }
     224              : 
     225              :         /**
     226              :          * Returns the list of constants.
     227              :          *
     228              :          * @return list of constants
     229              :          */
     230           87 :         public unowned List<Constant> get_constants () {
     231           87 :                 return constants;
     232              :         }
     233              : 
     234              :         /**
     235              :          * Adds the specified method as a member to this struct.
     236              :          *
     237              :          * @param m a method
     238              :          */
     239       819035 :         public override void add_method (Method m) {
     240       819035 :                 if (m.binding == MemberBinding.INSTANCE || m is CreationMethod) {
     241       587861 :                         m.this_parameter = new Parameter ("this", SemanticAnalyzer.get_this_type (m, this), m.source_reference);
     242       587861 :                         m.scope.add (m.this_parameter.name, m.this_parameter);
     243              :                 }
     244       819035 :                 if (!(m.return_type is VoidType) && m.get_postconditions ().size > 0) {
     245            1 :                         m.result_var = new LocalVariable (m.return_type.copy (), "result", null, m.source_reference);
     246            1 :                         m.result_var.is_result = true;
     247              :                 }
     248       848345 :                 if (m is CreationMethod) {
     249        29311 :                         if (m.name == null) {
     250        26185 :                                 default_construction_method = (CreationMethod) m;
     251        26185 :                                 m.name = ".new";
     252              :                         }
     253              : 
     254        29311 :                         var cm = (CreationMethod) m;
     255        29311 :                         if (cm.class_name != null && cm.class_name != name) {
     256              :                                 // type_name is null for constructors generated by GIdlParser
     257            1 :                                 Report.error (m.source_reference, "missing return type in method `%s.%s´", get_full_name (), cm.class_name);
     258            1 :                                 m.error = true;
     259            1 :                                 return;
     260              :                         }
     261              :                 }
     262              : 
     263       819034 :                 methods.add (m);
     264       819034 :                 scope.add (m.name, m);
     265              :         }
     266              : 
     267              :         /**
     268              :          * Returns the list of methods.
     269              :          *
     270              :          * @return list of methods
     271              :          */
     272           87 :         public unowned List<Method> get_methods () {
     273           87 :                 return methods;
     274              :         }
     275              : 
     276              :         /**
     277              :          * Adds the specified property as a member to this struct.
     278              :          *
     279              :          * @param prop a property
     280              :          */
     281           16 :         public override void add_property (Property prop) {
     282           16 :                 properties.add (prop);
     283           16 :                 scope.add (prop.name, prop);
     284              : 
     285           16 :                 if (prop.binding == MemberBinding.INSTANCE) {
     286           11 :                         prop.this_parameter = new Parameter ("this", SemanticAnalyzer.get_this_type (prop, this), prop.source_reference);
     287           11 :                         prop.scope.add (prop.this_parameter.name, prop.this_parameter);
     288              :                 }
     289              : 
     290           16 :                 if (prop.field != null) {
     291            9 :                         add_field (prop.field);
     292            9 :                         property_fields.add (prop.field);
     293              :                 }
     294              :         }
     295              : 
     296              :         /**
     297              :          * Returns the list of properties.
     298              :          *
     299              :          * @return list of properties
     300              :          */
     301           87 :         public unowned List<Property> get_properties () {
     302           87 :                 return properties;
     303              :         }
     304              : 
     305       327139 :         public override void accept (CodeVisitor visitor) {
     306       327139 :                 visitor.visit_struct (this);
     307              :         }
     308              : 
     309       316180 :         public override void accept_children (CodeVisitor visitor) {
     310       316180 :                 if (base_type != null) {
     311        24869 :                         base_type.accept (visitor);
     312              :                 }
     313              : 
     314       356208 :                 foreach (TypeParameter p in type_parameters) {
     315        20014 :                         p.accept (visitor);
     316              :                 }
     317              : 
     318      1452590 :                 foreach (Field f in fields) {
     319       568205 :                         f.accept (visitor);
     320              :                 }
     321              : 
     322      1090068 :                 foreach (Constant c in constants) {
     323       386944 :                         c.accept (visitor);
     324              :                 }
     325              : 
     326      3894906 :                 foreach (Method m in methods) {
     327      1789363 :                         m.accept (visitor);
     328              :                 }
     329              : 
     330       316272 :                 foreach (Property prop in properties) {
     331           46 :                         prop.accept (visitor);
     332              :                 }
     333              :         }
     334              : 
     335              :         /**
     336              :          * Returns whether this is a boolean type.
     337              :          *
     338              :          * @return true if this is a boolean type, false otherwise
     339              :          */
     340        17650 :         public bool is_boolean_type () {
     341        17650 :                 unowned Struct? st = base_struct;
     342        17650 :                 if (st != null && st.is_boolean_type ()) {
     343        17650 :                         return true;
     344              :                 }
     345        17645 :                 if (boolean_type == null) {
     346         6063 :                         boolean_type = has_attribute ("BooleanType");
     347              :                 }
     348        17645 :                 return boolean_type;
     349              :         }
     350              : 
     351              :         /**
     352              :          * Returns whether this is an integer type.
     353              :          *
     354              :          * @return true if this is an integer type, false otherwise
     355              :          */
     356       616979 :         public bool is_integer_type () {
     357       616979 :                 unowned Struct? st = base_struct;
     358       616979 :                 if (st != null && st.is_integer_type ()) {
     359       616979 :                         return true;
     360              :                 }
     361       616721 :                 if (integer_type == null) {
     362        17484 :                         integer_type = has_attribute ("IntegerType");
     363              :                 }
     364       616721 :                 return integer_type;
     365              :         }
     366              : 
     367              :         /**
     368              :          * Returns whether this is a floating point type.
     369              :          *
     370              :          * @return true if this is a floating point type, false otherwise
     371              :          */
     372       555421 :         public bool is_floating_type () {
     373       555421 :                 unowned Struct? st = base_struct;
     374       555421 :                 if (st != null && st.is_floating_type ()) {
     375       555421 :                         return true;
     376              :                 }
     377       555411 :                 if (floating_type == null) {
     378        16015 :                         floating_type = has_attribute ("FloatingType");
     379              :                 }
     380       555411 :                 return floating_type;
     381              :         }
     382              : 
     383            0 :         public bool is_decimal_floating_type () {
     384            0 :                 unowned Struct? st = base_struct;
     385            0 :                 if (st != null && st.is_decimal_floating_type ()) {
     386            0 :                         return true;
     387              :                 }
     388            0 :                 if (decimal_floating_type == null) {
     389            0 :                         decimal_floating_type = get_attribute_bool ("FloatingType", "decimal");
     390              :                 }
     391            0 :                 return decimal_floating_type;
     392              :         }
     393              : 
     394         2840 :         public override int get_type_parameter_index (string name) {
     395         2840 :                 int i = 0;
     396              : 
     397         5670 :                 foreach (TypeParameter p in type_parameters) {
     398         4255 :                         if (p.name == name) {
     399         2840 :                                 return (i);
     400              :                         }
     401         1415 :                         i++;
     402              :                 }
     403              : 
     404         2840 :                 return -1;
     405              :         }
     406              : 
     407              :         /**
     408              :          * Returns whether this struct is a simple type, i.e. whether
     409              :          * instances are passed by value.
     410              :          */
     411       316656 :         public bool is_simple_type () {
     412       316656 :                 unowned Struct? st = base_struct;
     413       316656 :                 if (st != null && st.is_simple_type ()) {
     414       316656 :                         return true;
     415              :                 }
     416       310119 :                 if (simple_type == null) {
     417        14897 :                         simple_type = has_attribute ("SimpleType") || has_attribute ("BooleanType") || has_attribute ("IntegerType") || has_attribute ("FloatingType");
     418              :                 }
     419       310119 :                 return simple_type;
     420              :         }
     421              : 
     422              :         /**
     423              :          * Marks this struct as simple type, i.e. instances will be passed by
     424              :          * value.
     425              :          */
     426            2 :         public void set_simple_type (bool simple_type) {
     427            2 :                 this.simple_type = simple_type;
     428            2 :                 set_attribute ("SimpleType", simple_type);
     429              :         }
     430              : 
     431        10500 :         public override void replace_type (DataType old_type, DataType new_type) {
     432        10500 :                 if (base_type == old_type) {
     433        10500 :                         base_type = new_type;
     434              :                 }
     435              :         }
     436              : 
     437      2464166 :         public override bool is_subtype_of (TypeSymbol t) {
     438      2464166 :                 if (this == t) {
     439              :                         return true;
     440              :                 }
     441              : 
     442      1735049 :                 if (base_type != null) {
     443         6285 :                         if (base_type.type_symbol != null && base_type.type_symbol.is_subtype_of (t)) {
     444              :                                 return true;
     445              :                         }
     446              :                 }
     447              : 
     448              :                 return false;
     449              :         }
     450              : 
     451       442704 :         public bool is_disposable () {
     452       442704 :                 if (has_attribute_argument ("CCode", "destroy_function")) {
     453        21860 :                         return true;
     454              :                 }
     455              : 
     456       424816 :                 if (base_struct != null) {
     457        20632 :                         return base_struct.is_disposable ();
     458              :                 }
     459              : 
     460       979420 :                 foreach (Field f in fields) {
     461       856308 :                         if (f.binding == MemberBinding.INSTANCE
     462       291533 :                             && f.get_attribute_bool ("CCode", "delegate_target", true)
     463       273185 :                             && f.variable_type.is_disposable ()) {
     464         3972 :                                 if (is_simple_type ()) {
     465            1 :                                         error = true;
     466            1 :                                         Report.error (f.source_reference, "[SimpleType] struct `%s' cannot have owned heap-allocated fields", get_full_name ());
     467              :                                 }
     468         3972 :                                 return true;
     469              :                         }
     470              :                 }
     471              : 
     472       422072 :                 return false;
     473              :         }
     474              : 
     475       242270 :         bool is_recursive_value_type (CodeContext context, DataType type) {
     476       242270 :                 unowned StructValueType? struct_type = type as StructValueType;
     477         5932 :                 if (struct_type != null && !struct_type.nullable) {
     478         3094 :                         unowned Struct st = (Struct) struct_type.type_symbol;
     479         3094 :                         if (st == this) {
     480            3 :                                 return true;
     481              :                         }
     482         3091 :                         if (!st.check (context)) {
     483       242267 :                                 return false;
     484              :                         }
     485        19478 :                         foreach (Field f in st.fields) {
     486         8194 :                                 if (f.binding == MemberBinding.INSTANCE && is_recursive_value_type (context, f.variable_type)) {
     487            0 :                                         return true;
     488              :                                 }
     489              :                         }
     490              :                 }
     491       242270 :                 return false;
     492              :         }
     493              : 
     494     12866072 :         public override bool check (CodeContext context) {
     495     12866072 :                 if (checked) {
     496     12733040 :                         return !error;
     497              :                 }
     498              : 
     499       133032 :                 checked = true;
     500              : 
     501       133032 :                 var old_source_file = context.analyzer.current_source_file;
     502       133032 :                 var old_symbol = context.analyzer.current_symbol;
     503              : 
     504       133032 :                 if (source_reference != null) {
     505       133032 :                         context.analyzer.current_source_file = source_reference.file;
     506              :                 }
     507       133032 :                 context.analyzer.current_symbol = this;
     508              : 
     509       133032 :                 if (base_type != null) {
     510        10456 :                         base_type.check (context);
     511              : 
     512        10456 :                         if (!(base_type is ValueType)) {
     513            1 :                                 error = true;
     514            1 :                                 Report.error (source_reference, "The base type `%s' of struct `%s' is not a struct", base_type.to_string (), get_full_name ());
     515            1 :                                 return false;
     516              :                         }
     517              : 
     518              :                         // check whether base type is at least as accessible as the struct
     519        10455 :                         if (!base_type.is_accessible (this)) {
     520            1 :                                 error = true;
     521            1 :                                 Report.error (source_reference, "base type `%s' is less accessible than struct `%s'", base_type.to_string (), get_full_name ());
     522              :                         }
     523              :                 }
     524              : 
     525       150019 :                 foreach (TypeParameter p in get_type_parameters ()) {
     526         8494 :                         if (!p.check (context)) {
     527            0 :                                 error = true;
     528              :                         }
     529              :                 }
     530              : 
     531       606913 :                 foreach (Field f in fields) {
     532       236945 :                         f.check (context);
     533              : 
     534       236945 :                         if (f.binding == MemberBinding.INSTANCE && is_recursive_value_type (context, f.variable_type)) {
     535            3 :                                 error = true;
     536            3 :                                 Report.error (f.source_reference, "Recursive value types are not allowed");
     537            3 :                                 return false;
     538              :                         }
     539              : 
     540       236942 :                         if (f.binding == MemberBinding.INSTANCE && f.initializer != null) {
     541            1 :                                 error = true;
     542            1 :                                 Report.error (f.source_reference, "Instance field initializers not supported");
     543            1 :                                 return false;
     544              :                         }
     545              : 
     546       236941 :                         if (f.binding == MemberBinding.STATIC && f.initializer != null) {
     547              :                                 // for backing property fields a dedicated error will be reported later
     548            4 :                                 if (!(f in property_fields) && !(f.initializer.value_type is NullType) && f.variable_type.is_disposable () && f.variable_type.value_owned) {
     549            1 :                                         error = true;
     550            1 :                                         Report.error (f.initializer.source_reference, "Owned static struct fields can only be initialized in a function or method");
     551              :                                 }
     552              :                         }
     553              :                 }
     554              : 
     555       461439 :                 foreach (Constant c in constants) {
     556       164206 :                         c.check (context);
     557              :                 }
     558              : 
     559      1649799 :                 foreach (Method m in methods) {
     560       758386 :                         m.check (context);
     561              :                 }
     562              : 
     563       133059 :                 foreach (Property prop in properties) {
     564           16 :                         prop.check (context);
     565              : 
     566           16 :                         if (prop.binding == MemberBinding.STATIC) {
     567            5 :                                 unowned Field? field = prop.field;
     568            5 :                                 if (field != null && field.initializer != null && !(field.initializer.value_type is NullType) && field.variable_type.is_disposable () && field.variable_type.value_owned) {
     569            1 :                                         error = true;
     570            1 :                                         Report.error (field.initializer.source_reference, "Owned static struct properties can only be initialized in a function or method");
     571              :                                 }
     572              :                         }
     573              :                 }
     574              : 
     575              :                 // FIXME Perform this [SimpleType] check in a better way
     576       133027 :                 is_disposable ();
     577              : 
     578       133027 :                 if (!external && !external_package) {
     579          230 :                         bool has_instance_field = false;
     580          236 :                         foreach (Field f in fields) {
     581          184 :                                 if (f.binding == MemberBinding.INSTANCE) {
     582          181 :                                         has_instance_field = true;
     583          181 :                                         break;
     584              :                                 }
     585              :                         }
     586          230 :                         if (base_type == null && !has_instance_field && !is_boolean_type () && !is_integer_type () && !is_floating_type ()) {
     587            4 :                                 error = true;
     588            4 :                                 Report.error (source_reference, "struct `%s' cannot be empty", get_full_name ());
     589          226 :                         } else if (base_type != null && has_instance_field) {
     590            1 :                                 error = true;
     591            1 :                                 Report.error (source_reference, "derived struct `%s' may not have instance fields", get_full_name ());
     592              :                         }
     593              :                 }
     594              : 
     595       133027 :                 context.analyzer.current_source_file = old_source_file;
     596       133027 :                 context.analyzer.current_symbol = old_symbol;
     597              : 
     598       133027 :                 return !error;
     599              :         }
     600              : }
     601              : 
     602              : // vim:sw=8 noet
        

Generated by: LCOV version 2.0-1