[corlib] ParseNumber.StringToInt now check for overflows.
[mono.git] / mcs / mcs / flowanalysis.cs
1 //
2 // flowanalyis.cs: The control flow analysis code
3 //
4 // Authors:
5 //   Martin Baulig (martin@ximian.com)
6 //   Raja R Harinath (rharinath@novell.com)
7 //   Marek Safar (marek.safar@gmail.com)
8 //
9 // Copyright 2001, 2002, 2003 Ximian, Inc.
10 // Copyright 2003-2008 Novell, Inc.
11 // Copyright 2011 Xamarin, Inc.
12 //
13
14 using System;
15 using System.Text;
16 using System.Collections.Generic;
17
18 namespace Mono.CSharp
19 {
20         // <summary>
21         //   This is used by the flow analysis code to keep track of the type of local variables.
22         //
23         //   The flow code uses a BitVector to keep track of whether a variable has been assigned
24         //   or not.  This is easy for fundamental types (int, char etc.) or reference types since
25         //   you can only assign the whole variable as such.
26         //
27         //   For structs, we also need to keep track of all its fields.  To do this, we allocate one
28         //   bit for the struct itself (it's used if you assign/access the whole struct) followed by
29         //   one bit for each of its fields.
30         //
31         //   This class computes this `layout' for each type.
32         // </summary>
33         public class TypeInfo
34         {
35                 // <summary>
36                 //   Total number of bits a variable of this type consumes in the flow vector.
37                 // </summary>
38                 public readonly int TotalLength;
39
40                 // <summary>
41                 //   Number of bits the simple fields of a variable of this type consume
42                 //   in the flow vector.
43                 // </summary>
44                 public readonly int Length;
45
46                 // <summary>
47                 //   This is only used by sub-structs.
48                 // </summary>
49                 public readonly int Offset;
50
51                 // <summary>
52                 //   If this is a struct.
53                 // </summary>
54                 public readonly bool IsStruct;
55
56                 // <summary>
57                 //   If this is a struct, all fields which are structs theirselves.
58                 // </summary>
59                 public TypeInfo[] SubStructInfo;
60
61                 readonly StructInfo struct_info;
62                 private static Dictionary<TypeSpec, TypeInfo> type_hash;
63
64                 static readonly TypeInfo simple_type = new TypeInfo (1);
65                 
66                 static TypeInfo ()
67                 {
68                         Reset ();
69                 }
70                 
71                 public static void Reset ()
72                 {
73                         type_hash = new Dictionary<TypeSpec, TypeInfo> ();
74                         StructInfo.field_type_hash = new Dictionary<TypeSpec, StructInfo> ();
75                 }
76
77                 TypeInfo (int totalLength)
78                 {
79                         this.TotalLength = totalLength;
80                 }
81                 
82                 TypeInfo (StructInfo struct_info, int offset)
83                 {
84                         this.struct_info = struct_info;
85                         this.Offset = offset;
86                         this.Length = struct_info.Length;
87                         this.TotalLength = struct_info.TotalLength;
88                         this.SubStructInfo = struct_info.StructFields;
89                         this.IsStruct = true;
90                 }
91                 
92                 public int GetFieldIndex (string name)
93                 {
94                         if (struct_info == null)
95                                 return 0;
96
97                         return struct_info [name];
98                 }
99
100                 public TypeInfo GetStructField (string name)
101                 {
102                         if (struct_info == null)
103                                 return null;
104
105                         return struct_info.GetStructField (name);
106                 }
107
108                 public static TypeInfo GetTypeInfo (TypeSpec type, IMemberContext context)
109                 {
110                         if (!type.IsStruct)
111                                 return simple_type;
112
113                         TypeInfo info;
114                         if (type_hash.TryGetValue (type, out info))
115                                 return info;
116
117                         var struct_info = StructInfo.GetStructInfo (type, context);
118                         if (struct_info != null) {
119                                 info = new TypeInfo (struct_info, 0);
120                         } else {
121                                 info = simple_type;
122                         }
123
124                         type_hash.Add (type, info);
125                         return info;
126                 }
127
128                 // <summary>
129                 //   A struct's constructor must always assign all fields.
130                 //   This method checks whether it actually does so.
131                 // </summary>
132                 public bool IsFullyInitialized (FlowAnalysisContext fc, VariableInfo vi, Location loc)
133                 {
134                         if (struct_info == null)
135                                 return true;
136
137                         bool ok = true;
138                         for (int i = 0; i < struct_info.Count; i++) {
139                                 var field = struct_info.Fields[i];
140
141                                 if (!fc.IsStructFieldDefinitelyAssigned (vi, field.Name)) {
142                                         var bf = field.MemberDefinition as Property.BackingFieldDeclaration;
143                                         if (bf != null) {
144                                                 if (bf.Initializer != null)
145                                                         continue;
146
147                                                 fc.Report.Error (843, loc,
148                                                         "An automatically implemented property `{0}' must be fully assigned before control leaves the constructor. Consider calling the default struct contructor from a constructor initializer",
149                                                         field.GetSignatureForError ());
150
151                                                 ok = false;
152                                                 continue;
153                                         }
154
155                                         fc.Report.Error (171, loc,
156                                                 "Field `{0}' must be fully assigned before control leaves the constructor",
157                                                 field.GetSignatureForError ());
158                                         ok = false;
159                                 }
160                         }
161
162                         return ok;
163                 }
164
165                 public override string ToString ()
166                 {
167                         return String.Format ("TypeInfo ({0}:{1}:{2})",
168                                               Offset, Length, TotalLength);
169                 }
170
171                 class StructInfo
172                 {
173                         readonly List<FieldSpec> fields;
174                         public readonly TypeInfo[] StructFields;
175                         public readonly int Length;
176                         public readonly int TotalLength;
177
178                         public static Dictionary<TypeSpec, StructInfo> field_type_hash;
179                         private Dictionary<string, TypeInfo> struct_field_hash;
180                         private Dictionary<string, int> field_hash;
181
182                         bool InTransit;
183
184                         //
185                         // We only need one instance per type
186                         //
187                         StructInfo (TypeSpec type, IMemberContext context)
188                         {
189                                 field_type_hash.Add (type, this);
190
191                                 fields = MemberCache.GetAllFieldsForDefiniteAssignment (type, context);
192
193                                 struct_field_hash = new Dictionary<string, TypeInfo> ();
194                                 field_hash = new Dictionary<string, int> (fields.Count);
195
196                                 StructFields = new TypeInfo[fields.Count];
197                                 StructInfo[] sinfo = new StructInfo[fields.Count];
198
199                                 InTransit = true;
200
201                                 for (int i = 0; i < fields.Count; i++) {
202                                         var field = fields [i];
203
204                                         if (field.MemberType.IsStruct)
205                                                 sinfo [i] = GetStructInfo (field.MemberType, context);
206
207                                         if (sinfo [i] == null)
208                                                 field_hash.Add (field.Name, ++Length);
209                                         else if (sinfo [i].InTransit) {
210                                                 sinfo [i] = null;
211                                                 return;
212                                         }
213                                 }
214
215                                 InTransit = false;
216
217                                 TotalLength = Length + 1;
218                                 for (int i = 0; i < fields.Count; i++) {
219                                         var field = fields [i];
220
221                                         if (sinfo [i] == null)
222                                                 continue;
223
224                                         field_hash.Add (field.Name, TotalLength);
225
226                                         StructFields [i] = new TypeInfo (sinfo [i], TotalLength);
227                                         struct_field_hash.Add (field.Name, StructFields [i]);
228                                         TotalLength += sinfo [i].TotalLength;
229                                 }
230                         }
231
232                         public int Count {
233                                 get {
234                                         return fields.Count;
235                                 }
236                         }
237
238                         public List<FieldSpec> Fields {
239                                 get {
240                                         return fields;
241                                 }
242                         }
243
244                         public int this [string name] {
245                                 get {
246                                         int val;
247                                         if (!field_hash.TryGetValue (name, out val))
248                                                 return 0;
249
250                                         return val;
251                                 }
252                         }
253
254                         public TypeInfo GetStructField (string name)
255                         {
256                                 TypeInfo ti;
257                                 if (struct_field_hash.TryGetValue (name, out ti))
258                                         return ti;
259
260                                 return null;
261                         }
262
263                         public static StructInfo GetStructInfo (TypeSpec type, IMemberContext context)
264                         {
265                                 if (type.BuiltinType > 0)
266                                         return null;
267
268                                 StructInfo info;
269                                 if (field_type_hash.TryGetValue (type, out info))
270                                         return info;
271
272                                 return new StructInfo (type, context);
273                         }
274                 }
275         }
276
277         //
278         // This is used by definite assignment analysis code to store information about a local variable
279         // or parameter.  Depending on the variable's type, we need to allocate one or more elements
280         // in the BitVector - if it's a fundamental or reference type, we just need to know whether
281         // it has been assigned or not, but for structs, we need this information for each of its fields.
282         //
283         public class VariableInfo
284         {
285                 readonly string Name;
286
287                 readonly TypeInfo TypeInfo;
288
289                 // <summary>
290                 //   The bit offset of this variable in the flow vector.
291                 // </summary>
292                 readonly int Offset;
293
294                 // <summary>
295                 //   The number of bits this variable needs in the flow vector.
296                 //   The first bit always specifies whether the variable as such has been assigned while
297                 //   the remaining bits contain this information for each of a struct's fields.
298                 // </summary>
299                 readonly int Length;
300
301                 // <summary>
302                 //   If this is a parameter of local variable.
303                 // </summary>
304                 public bool IsParameter;
305
306                 VariableInfo[] sub_info;
307
308                 VariableInfo (string name, TypeSpec type, int offset, IMemberContext context)
309                 {
310                         this.Name = name;
311                         this.Offset = offset;
312                         this.TypeInfo = TypeInfo.GetTypeInfo (type, context);
313
314                         Length = TypeInfo.TotalLength;
315
316                         Initialize ();
317                 }
318
319                 VariableInfo (VariableInfo parent, TypeInfo type)
320                 {
321                         this.Name = parent.Name;
322                         this.TypeInfo = type;
323                         this.Offset = parent.Offset + type.Offset;
324                         this.Length = type.TotalLength;
325
326                         this.IsParameter = parent.IsParameter;
327
328                         Initialize ();
329                 }
330
331                 void Initialize ()
332                 {
333                         TypeInfo[] sub_fields = TypeInfo.SubStructInfo;
334                         if (sub_fields != null) {
335                                 sub_info = new VariableInfo [sub_fields.Length];
336                                 for (int i = 0; i < sub_fields.Length; i++) {
337                                         if (sub_fields [i] != null)
338                                                 sub_info [i] = new VariableInfo (this, sub_fields [i]);
339                                 }
340                         } else
341                                 sub_info = new VariableInfo [0];
342                 }
343
344                 public static VariableInfo Create (BlockContext bc, LocalVariable variable)
345                 {
346                         var info = new VariableInfo (variable.Name, variable.Type, bc.AssignmentInfoOffset, bc);
347                         bc.AssignmentInfoOffset += info.Length;
348                         return info;
349                 }
350
351                 public static VariableInfo Create (BlockContext bc, Parameter parameter)
352                 {
353                         var info = new VariableInfo (parameter.Name, parameter.Type, bc.AssignmentInfoOffset, bc) {
354                                 IsParameter = true
355                         };
356
357                         bc.AssignmentInfoOffset += info.Length;
358                         return info;
359                 }
360
361                 public bool IsAssigned (DefiniteAssignmentBitSet vector)
362                 {
363                         if (vector == null)
364                                 return true;
365
366                         if (vector [Offset])
367                                 return true;
368
369                         // Unless this is a struct
370                         if (!TypeInfo.IsStruct)
371                                 return false;
372
373                         //
374                         // Following case cannot be handled fully by SetStructFieldAssigned
375                         // because we may encounter following case
376                         // 
377                         // struct A { B b }
378                         // struct B { int value; }
379                         //
380                         // setting a.b.value is propagated only to B's vector and not upwards to possible parents
381                         //
382                         //
383                         // Each field must be assigned
384                         //
385                         for (int i = Offset + 1; i <= TypeInfo.Length + Offset; i++) {
386                                 if (!vector[i])
387                                         return false;
388                         }
389
390                         // Ok, now check all fields which are structs.
391                         for (int i = 0; i < sub_info.Length; i++) {
392                                 VariableInfo sinfo = sub_info[i];
393                                 if (sinfo == null)
394                                         continue;
395
396                                 if (!sinfo.IsAssigned (vector))
397                                         return false;
398                         }
399                         
400                         vector.Set (Offset);
401                         return true;
402                 }
403
404                 public bool IsEverAssigned { get; set; }
405
406                 public bool IsFullyInitialized (FlowAnalysisContext fc, Location loc)
407                 {
408                         return TypeInfo.IsFullyInitialized (fc, this, loc);
409                 }
410
411                 public bool IsStructFieldAssigned (DefiniteAssignmentBitSet vector, string field_name)
412                 {
413                         int field_idx = TypeInfo.GetFieldIndex (field_name);
414
415                         if (field_idx == 0)
416                                 return true;
417
418                         return vector [Offset + field_idx];
419                 }
420
421                 public void SetAssigned (DefiniteAssignmentBitSet vector, bool generatedAssignment)
422                 {
423                         if (Length == 1)
424                                 vector.Set (Offset);
425                         else
426                                 vector.Set (Offset, Length);
427
428                         if (!generatedAssignment)
429                                 IsEverAssigned = true;
430                 }
431
432                 public void SetStructFieldAssigned (DefiniteAssignmentBitSet vector, string field_name)
433                 {
434                         if (vector [Offset])
435                                 return;
436
437                         int field_idx = TypeInfo.GetFieldIndex (field_name);
438
439                         if (field_idx == 0)
440                                 return;
441
442                         var complex_field = TypeInfo.GetStructField (field_name);
443                         if (complex_field != null) {
444                                 vector.Set (Offset + complex_field.Offset, complex_field.TotalLength);
445                         } else {
446                                 vector.Set (Offset + field_idx);
447                         }
448
449                         IsEverAssigned = true;
450
451                         //
452                         // Each field must be assigned before setting master bit
453                         //
454                         for (int i = Offset + 1; i < TypeInfo.TotalLength + Offset; i++) {
455                                 if (!vector[i])
456                                         return;
457                         }
458
459                         //
460                         // Set master struct flag to assigned when all tested struct
461                         // fields have been assigned
462                         //
463                         vector.Set (Offset);
464                 }
465
466                 public VariableInfo GetStructFieldInfo (string fieldName)
467                 {
468                         TypeInfo type = TypeInfo.GetStructField (fieldName);
469
470                         if (type == null)
471                                 return null;
472
473                         return new VariableInfo (this, type);
474                 }
475
476                 public override string ToString ()
477                 {
478                         return String.Format ("Name={0} Offset={1} Length={2} {3})", Name, Offset, Length, TypeInfo);
479                 }
480         }
481
482         public struct Reachability
483         {
484                 readonly bool unreachable;
485
486                 Reachability (bool unreachable)
487                 {
488                         this.unreachable = unreachable;
489                 }
490
491                 public bool IsUnreachable {
492                         get {
493                                 return unreachable;
494                         }
495                 }
496
497                 public static Reachability CreateUnreachable ()
498                 {
499                         return new Reachability (true);
500                 }
501
502                 public static Reachability operator & (Reachability a, Reachability b)
503                 {
504                     return new Reachability (a.unreachable && b.unreachable);
505                 }
506
507                 public static Reachability operator | (Reachability a, Reachability b)
508                 {
509                         return new Reachability (a.unreachable | b.unreachable);
510                 }
511         }
512
513         //
514         // Special version of bit array. Many operations can be simplified because
515         // we are always dealing with arrays of same sizes
516         //
517         public class DefiniteAssignmentBitSet
518         {
519                 const uint copy_on_write_flag = 1u << 31;
520
521                 uint bits;
522
523                 // Used when bits overflows
524                 int[] large_bits;
525
526                 public static readonly DefiniteAssignmentBitSet Empty = new DefiniteAssignmentBitSet (0);
527
528                 public DefiniteAssignmentBitSet (int length)
529                 {
530                         if (length > 31)
531                                 large_bits = new int[(length + 31) / 32];
532                 }
533
534                 public DefiniteAssignmentBitSet (DefiniteAssignmentBitSet source)
535                 {
536                         if (source.large_bits != null) {
537                                 large_bits = source.large_bits;
538                                 bits = source.bits | copy_on_write_flag;
539                         } else {
540                                 bits = source.bits & ~copy_on_write_flag;
541                         }
542                 }
543
544                 public static DefiniteAssignmentBitSet operator & (DefiniteAssignmentBitSet a, DefiniteAssignmentBitSet b)
545                 {
546                         if (AreEqual (a, b))
547                                 return a;
548
549                         DefiniteAssignmentBitSet res;
550                         if (a.large_bits == null) {
551                                 res = new DefiniteAssignmentBitSet (a);
552                                 res.bits &= (b.bits & ~copy_on_write_flag);
553                                 return res;
554                         }
555
556                         res = new DefiniteAssignmentBitSet (a);
557                         res.Clone ();
558                         var dest = res.large_bits;
559                         var src = b.large_bits;
560                         for (int i = 0; i < dest.Length; ++i) {
561                                 dest[i] &= src[i];
562                         }
563
564                         return res;
565                 }
566
567                 public static DefiniteAssignmentBitSet operator | (DefiniteAssignmentBitSet a, DefiniteAssignmentBitSet b)
568                 {
569                         if (AreEqual (a, b))
570                                 return a;
571
572                         DefiniteAssignmentBitSet res;
573                         if (a.large_bits == null) {
574                                 res = new DefiniteAssignmentBitSet (a);
575                                 res.bits |= b.bits;
576                                 res.bits &= ~copy_on_write_flag;
577                                 return res;
578                         }
579
580                         res = new DefiniteAssignmentBitSet (a);
581                         res.Clone ();
582                         var dest = res.large_bits;
583                         var src = b.large_bits;
584
585                         for (int i = 0; i < dest.Length; ++i) {
586                                 dest[i] |= src[i];
587                         }
588
589                         return res;
590                 }
591
592                 public static DefiniteAssignmentBitSet And (List<DefiniteAssignmentBitSet> das)
593                 {
594                         if (das.Count == 0)
595                                 throw new ArgumentException ("Empty das");
596
597                         DefiniteAssignmentBitSet res = das[0];
598                         for (int i = 1; i < das.Count; ++i) {
599                                 res &= das[i];
600                         }
601
602                         return res;
603                 }
604
605                 bool CopyOnWrite {
606                         get {
607                                 return (bits & copy_on_write_flag) != 0;
608                         }
609                 }
610
611                 int Length {
612                         get {
613                                 return large_bits == null ? 31 : large_bits.Length * 32;
614                         }
615                 }
616
617                 public void Set (int index)
618                 {
619                         if (CopyOnWrite && !this[index])
620                                 Clone ();
621
622                         SetBit (index);
623                 }
624
625                 public void Set (int index, int length)
626                 {
627                         for (int i = 0; i < length; ++i) {
628                                 if (CopyOnWrite && !this[index + i])
629                                         Clone ();
630
631                                 SetBit (index + i);
632                         }
633                 }
634
635                 public bool this[int index] {
636                         get {
637                                 return GetBit (index);
638                         }
639                 }
640
641                 public override string ToString ()
642                 {
643                         var length = Length;
644                         StringBuilder sb = new StringBuilder (length);
645                         for (int i = 0; i < length; ++i) {
646                                 sb.Append (this[i] ? '1' : '0');
647                         }
648
649                         return sb.ToString ();
650                 }
651
652                 void Clone ()
653                 {
654                         large_bits = (int[]) large_bits.Clone ();
655                 }
656
657                 bool GetBit (int index)
658                 {
659                         return large_bits == null ?
660                                 (bits & (1 << index)) != 0 :
661                                 (large_bits[index >> 5] & (1 << (index & 31))) != 0;
662                 }
663
664                 void SetBit (int index)
665                 {
666                         if (large_bits == null)
667                                 bits = (uint) ((int) bits | (1 << index));
668                         else
669                                 large_bits[index >> 5] |= (1 << (index & 31));
670                 }
671
672                 public static bool AreEqual (DefiniteAssignmentBitSet a, DefiniteAssignmentBitSet b)
673                 {
674                         if (a.large_bits == null)
675                                 return (a.bits & ~copy_on_write_flag) == (b.bits & ~copy_on_write_flag);
676
677                         for (int i = 0; i < a.large_bits.Length; ++i) {
678                                 if (a.large_bits[i] != b.large_bits[i])
679                                         return false;
680                         }
681
682                         return true;
683                 }
684         }
685 }