Added few unsafe tests.
[mono.git] / mcs / mcs / support.cs
1 //
2 // support.cs: Support routines to work around the fact that System.Reflection.Emit
3 // can not introspect types that are being constructed
4 //
5 // Author:
6 //   Miguel de Icaza (miguel@ximian.com)
7 //
8 // Copyright 2001 Ximian, Inc (http://www.ximian.com)
9 // Copyright 2003-2008 Novell, Inc
10 //
11
12 using System;
13 using System.IO;
14 using System.Text;
15 using System.Reflection;
16 using System.Collections;
17 using System.Reflection.Emit;
18 using System.Globalization;
19
20 namespace Mono.CSharp {
21
22         public interface ParameterData {
23                 Type ParameterType (int pos);
24                 Type [] Types { get; }
25                 int  Count { get; }
26                 Type ExtensionMethodType { get; }
27                 bool HasParams { get; }
28                 string ParameterName (int pos);
29                 string ParameterDesc (int pos);
30
31                 Parameter.Modifier ParameterModifier (int pos);
32                 string GetSignatureForError ();
33
34 #if MS_COMPATIBLE
35                 ParameterData InflateTypes (Type[] genArguments, Type[] argTypes);
36 #endif
37         }
38
39         public class ReflectionParameters : ParameterData {
40                 ParameterInfo [] pi;
41                 Type [] types;
42                 int params_idx = int.MaxValue;
43                 bool is_varargs;
44                 bool is_extension;
45                 ParameterData gpd;
46
47                 public ReflectionParameters (MethodBase mb)
48                 {
49                         ParameterInfo [] pi = mb.GetParameters ();
50                         is_varargs = (mb.CallingConvention & CallingConventions.VarArgs) != 0;
51
52                         this.pi = pi;
53                         int count = pi.Length;
54
55                         if (count == 0) {
56                                 types = Type.EmptyTypes;
57                                 return;
58                         }
59
60                         types = new Type [count];
61                         for (int i = 0; i < count; i++)
62                                 types [i] = TypeManager.TypeToCoreType (pi [i].ParameterType);
63
64                         // TODO: This (if) should be done one level higher to correctly use
65                         // out caching facilities.
66                         MethodBase generic = TypeManager.DropGenericMethodArguments (mb);
67                         if (generic != mb) {
68                                 gpd = TypeManager.GetParameterData (generic);
69                                 if (gpd.HasParams) {
70                                         for (int i = gpd.Count; i != 0; --i) {
71                                                 if ((gpd.ParameterModifier (i-1) & Parameter.Modifier.PARAMS) != 0) {
72                                                         this.params_idx = i-1;
73                                                         break;
74                                                 }
75                                         }
76                                 }
77                                 return;
78                         }
79
80                         //
81                         // So far, the params attribute can be used in C# for the last
82                         // and next to last method parameters.
83                         // If some other language can place it anywhere we will
84                         // have to analyze all parameters and not just last 2.
85                         //
86                         --count;
87                         for (int i = count; i >= 0 && i > count - 2; --i) {
88                                 if (!pi [i].ParameterType.IsArray)
89                                         continue;
90
91                                 if (pi [i].IsDefined (TypeManager.param_array_type, false)) {
92                                         params_idx = i;
93                                         break;
94                                 }
95                         }
96
97                         if (TypeManager.extension_attribute_type != null && mb.IsStatic &&
98                                 (mb.DeclaringType.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute &&
99                                 mb.IsDefined (TypeManager.extension_attribute_type, false))
100                                 is_extension = true;
101                 }
102
103                 public override bool Equals (object obj)
104                 {
105                         ReflectionParameters rp = obj as ReflectionParameters;
106                         if (rp == null)
107                                 return false;
108
109                         if (Count != rp.Count)
110                                 return false;
111
112                         for (int i = 0; i < Count; ++i) {
113                         if (!types [i].Equals (rp.types [i]))
114                                 return false;
115                         }
116                         return true;
117                 }
118
119                 public override int GetHashCode ()
120                 {
121                         return base.GetHashCode ();
122                 }
123
124                 public string GetSignatureForError ()
125                 {
126                         StringBuilder sb = new StringBuilder ("(");
127                         for (int i = 0; i < pi.Length; ++i) {
128                                 if (i != 0)
129                                         sb.Append (", ");
130                                 sb.Append (ParameterDesc (i));
131                         }
132                         if (is_varargs) {
133                                 if (pi.Length > 0)
134                                         sb.Append (", ");
135                                 sb.Append ("__arglist");
136                         }
137                         sb.Append (')');
138                         return sb.ToString ();
139                 }
140
141 #if MS_COMPATIBLE
142                 public ParameterData InflateTypes (Type[] genArguments, Type[] argTypes)
143                 {
144                         ReflectionParameters p = (ReflectionParameters)MemberwiseClone ();
145
146                         for (int i = 0; i < types.Length; ++i) {
147                                 if (types[i].IsGenericParameter) {
148                                         for (int ii = 0; ii < genArguments.Length; ++ii) {
149                                                 if (types[i] != genArguments[ii])
150                                                         continue;
151
152                                                 p.types[i] = argTypes[ii];
153                                                 break;
154                                         }
155                                         continue;
156                                 }
157                                 
158                                 if (types[i].IsGenericType) {
159                                         Type[] gen_arguments_open = types[i].GetGenericTypeDefinition ().GetGenericArguments ();
160                                         Type[] gen_arguments = types[i].GetGenericArguments ();
161                                         for (int ii = 0; ii < gen_arguments_open.Length; ++ii) {
162                                                 if (gen_arguments [ii].IsGenericParameter) {
163                                                         for (int iii = 0; iii < genArguments.Length; ++iii) {
164                                                                 if (gen_arguments [ii] != genArguments [iii])
165                                                                         continue;
166
167                                                                 gen_arguments_open [ii] = argTypes [iii];
168                                                                 break;
169                                                         }
170                                                 } else {
171                                                         gen_arguments_open [ii] = gen_arguments [ii];
172                                                 }
173                                         }
174
175                                         p.types[i] = types[i].GetGenericTypeDefinition ().MakeGenericType (gen_arguments_open);
176                                 }
177                         }
178                         return p;
179                 }
180 #endif
181
182                 public Type ParameterType (int pos)
183                 {
184                         if (is_varargs && pos >= pi.Length)
185                                 return TypeManager.runtime_argument_handle_type;
186
187                         return types [pos];
188                 }
189
190                 public string ParameterName (int pos)
191                 {
192                         if (gpd != null)
193                                 return gpd.ParameterName (pos);
194
195                         if (is_varargs && pos >= pi.Length)
196                                 return "__arglist";
197
198                         return pi [pos].Name;
199                 }
200
201                 public string ParameterDesc (int pos)
202                 {
203                         if (is_varargs && pos >= pi.Length)
204                                 return "";
205
206                         StringBuilder sb = new StringBuilder ();
207
208                         if (pi [pos].IsIn)
209                                 sb.Append ("in ");
210
211                         Type partype = ParameterType (pos);
212                         if (partype.IsByRef){
213                                 partype = TypeManager.GetElementType (partype);
214                                 if (pi [pos].IsOut)
215                                         sb.Append ("out ");
216                                 else
217                                         sb.Append ("ref ");
218                         }
219
220                         if (params_idx == pos)
221                                 sb.Append ("params ");
222
223                         if (pos == 0 && ExtensionMethodType != null)
224                                 sb.Append ("this ");
225
226                         sb.Append (TypeManager.CSharpName (partype).Replace ("&", ""));
227
228                         return sb.ToString ();
229                 }
230
231                 public Parameter.Modifier ParameterModifier (int pos)
232                 {
233                         if (pos >= params_idx)
234                                 return Parameter.Modifier.PARAMS;
235                         if (is_varargs && pos >= pi.Length)
236                                 return Parameter.Modifier.ARGLIST;
237
238                         if (gpd != null)
239                                 return gpd.ParameterModifier (pos);
240
241                         Type t = types [pos];
242                         if (t.IsByRef){
243                                 if ((pi [pos].Attributes & (ParameterAttributes.Out|ParameterAttributes.In)) == ParameterAttributes.Out)
244                                         return Parameter.Modifier.OUT;
245                                 else
246                                         return Parameter.Modifier.REF;
247                         }
248
249                         return Parameter.Modifier.NONE;
250                 }
251
252                 public int Count {
253                         get { return is_varargs ? pi.Length + 1 : pi.Length; }
254                 }
255
256                 public Type ExtensionMethodType {
257                         get {
258                                 if (!is_extension)
259                                         return null;
260
261                                 return types [0];
262                         }
263                 }
264
265                 public bool HasParams {
266                         get { return params_idx != int.MaxValue; }
267                 }
268
269                 public Type[] Types {
270                         get { return types; }
271                 }
272         }
273
274 #if GMCS_SOURCE
275         public class ReflectionConstraints : GenericConstraints
276         {
277                 GenericParameterAttributes attrs;
278                 Type base_type;
279                 Type class_constraint;
280                 Type[] iface_constraints;
281                 string name;
282
283                 public static GenericConstraints GetConstraints (Type t)
284                 {
285                         Type [] constraints = t.GetGenericParameterConstraints ();
286                         GenericParameterAttributes attrs = t.GenericParameterAttributes;
287                         if (constraints.Length == 0 && attrs == GenericParameterAttributes.None)
288                                 return null;
289                         return new ReflectionConstraints (t.Name, constraints, attrs);
290                 }
291
292                 private ReflectionConstraints (string name, Type [] constraints, GenericParameterAttributes attrs)
293                 {
294                         this.name = name;
295                         this.attrs = attrs;
296
297                         if ((constraints.Length > 0) && !constraints [0].IsInterface) {
298                                 class_constraint = constraints [0];
299                                 iface_constraints = new Type [constraints.Length - 1];
300                                 Array.Copy (constraints, 1, iface_constraints, 0, constraints.Length - 1);
301                         } else
302                                 iface_constraints = constraints;
303
304                         if (HasValueTypeConstraint)
305                                 base_type = TypeManager.value_type;
306                         else if (class_constraint != null)
307                                 base_type = class_constraint;
308                         else
309                                 base_type = TypeManager.object_type;
310                 }
311
312                 public override string TypeParameter {
313                         get { return name; }
314                 }
315
316                 public override GenericParameterAttributes Attributes {
317                         get { return attrs; }
318                 }
319
320                 public override Type ClassConstraint {
321                         get { return class_constraint; }
322                 }
323
324                 public override Type EffectiveBaseClass {
325                         get { return base_type; }
326                 }
327
328                 public override Type[] InterfaceConstraints {
329                         get { return iface_constraints; }
330                 }
331         }
332 #endif
333
334         class PtrHashtable : Hashtable {
335                 sealed class PtrComparer : IComparer {
336                         private PtrComparer () {}
337
338                         public static PtrComparer Instance = new PtrComparer ();
339
340                         public int Compare (object x, object y)
341                         {
342                                 if (x == y)
343                                         return 0;
344                                 else
345                                         return 1;
346                         }
347                 }
348
349                 public PtrHashtable ()
350                 {
351                         comparer = PtrComparer.Instance;
352                 }
353         }
354
355         /*
356          * Hashtable whose keys are character arrays with the same length
357          */
358         class CharArrayHashtable : Hashtable {
359                 sealed class ArrComparer : IComparer {
360                         private int len;
361
362                         public ArrComparer (int len) {
363                                 this.len = len;
364                         }
365
366                         public int Compare (object x, object y)
367                         {
368                                 char[] a = (char[])x;
369                                 char[] b = (char[])y;
370
371                                 for (int i = 0; i < len; ++i)
372                                         if (a [i] != b [i])
373                                                 return 1;
374                                 return 0;
375                         }
376                 }
377
378                 private int len;
379
380                 protected override int GetHash (Object key)
381                 {
382                         char[] arr = (char[])key;
383                         int h = 0;
384
385                         for (int i = 0; i < len; ++i)
386                                 h = (h << 5) - h + arr [i];
387
388                         return h;
389                 }
390
391                 public CharArrayHashtable (int len)
392                 {
393                         this.len = len;
394                         comparer = new ArrComparer (len);
395                 }
396         }
397
398         struct Pair {
399                 public object First;
400                 public object Second;
401
402                 public Pair (object f, object s)
403                 {
404                         First = f;
405                         Second = s;
406                 }
407         }
408
409         public class Accessors {
410                 public Accessor get_or_add;
411                 public Accessor set_or_remove;
412
413                 // was 'set' declared before 'get'?  was 'remove' declared before 'add'?
414                 public bool declared_in_reverse;
415
416                 public Accessors (Accessor get_or_add, Accessor set_or_remove)
417                 {
418                         this.get_or_add = get_or_add;
419                         this.set_or_remove = set_or_remove;
420                 }
421         }
422
423         /// <summary>
424         ///   This is a wrapper around StreamReader which is seekable backwards
425         ///   within a window of around 2048 chars.
426         /// </summary>
427         public class SeekableStreamReader
428         {
429                 const int AverageReadLength = 1024;
430                 TextReader reader;
431                 Stream stream;
432                 Encoding encoding;
433
434                 char[] buffer;
435                 int buffer_start;       // in chars
436                 int char_count;         // count buffer[] valid characters
437                 int pos;                // index into buffer[]
438
439                 public SeekableStreamReader (Stream stream, Encoding encoding)
440                 {
441                         this.stream = stream;
442                         this.encoding = encoding;
443                         
444                         this.reader = new StreamReader (stream, encoding, true);
445                         this.buffer = new char [AverageReadLength * 3];
446
447                         // Let the StreamWriter autodetect the encoder
448                         reader.Peek ();
449                 }
450
451                 /// <remarks>
452                 ///   This value corresponds to the current position in a stream of characters.
453                 ///   The StreamReader hides its manipulation of the underlying byte stream and all
454                 ///   character set/decoding issues.  Thus, we cannot use this position to guess at
455                 ///   the corresponding position in the underlying byte stream even though there is
456                 ///   a correlation between them.
457                 /// </remarks>
458                 public int Position {
459                         get { return buffer_start + pos; }
460
461                         set {
462                                 if (value > buffer_start + char_count)
463                                         throw new InternalErrorException ("can't seek that far forward: " + (pos - value));
464                                 
465                                 if (value < buffer_start){
466                                         // Reinitialize.
467                                         stream.Position = 0;
468                                         reader = new StreamReader (stream, encoding, true);
469                                         buffer_start = 0;
470                                         char_count = 0;
471                                         pos = 0;
472                                         Peek ();
473
474                                         while (value > buffer_start + char_count){
475                                                 pos = char_count+1;
476                                                 Peek ();
477                                         }
478                                         pos = value - buffer_start;
479                                 }
480
481                                 pos = value - buffer_start;
482                         }
483                 }
484
485                 private bool ReadBuffer ()
486                 {
487                         int slack = buffer.Length - char_count;
488                         if (slack <= AverageReadLength / 2) {
489                                 // shift the buffer to make room for AverageReadLength number of characters
490                                 int shift = AverageReadLength - slack;
491                                 Array.Copy (buffer, shift, buffer, 0, char_count - shift);
492                                 pos -= shift;
493                                 char_count -= shift;
494                                 buffer_start += shift;
495                                 slack += shift;         // slack == AverageReadLength
496                         }
497
498                         int chars_read = reader.Read (buffer, char_count, slack);
499                         char_count += chars_read;
500
501                         return pos < char_count;
502                 }
503
504                 public int Peek ()
505                 {
506                         if ((pos >= char_count) && !ReadBuffer ())
507                                 return -1;
508
509                         return buffer [pos];
510                 }
511
512                 public int Read ()
513                 {
514                         if ((pos >= char_count) && !ReadBuffer ())
515                                 return -1;
516
517                         return buffer [pos++];
518                 }
519         }
520
521         public class DoubleHash {
522                 const int DEFAULT_INITIAL_BUCKETS = 100;
523
524                 public DoubleHash () : this (DEFAULT_INITIAL_BUCKETS) {}
525
526                 public DoubleHash (int size)
527                 {
528                         count = size;
529                         buckets = new Entry [size];
530                 }
531
532                 int count;
533                 Entry [] buckets;
534                 int size = 0;
535
536                 class Entry {
537                         public object key1;
538                         public object key2;
539                         public int hash;
540                         public object value;
541                         public Entry next;
542
543                         public Entry (object key1, object key2, int hash, object value, Entry next)
544                         {
545                                 this.key1 = key1;
546                                 this.key2 = key2;
547                                 this.hash = hash;
548                                 this.next = next;
549                                 this.value = value;
550                         }
551                 }
552
553                 public bool Lookup (object a, object b, out object res)
554                 {
555                         int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
556
557                         for (Entry e = buckets [h % count]; e != null; e = e.next) {
558                                 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b)) {
559                                         res = e.value;
560                                         return true;
561                                 }
562                         }
563                         res = null;
564                         return false;
565                 }
566
567                 public void Insert (object a, object b, object value)
568                 {
569                         // Is it an existing one?
570
571                         int h = (a.GetHashCode () ^ b.GetHashCode ()) & 0x7FFFFFFF;
572
573                         for (Entry e = buckets [h % count]; e != null; e = e.next) {
574                                 if (e.hash == h && e.key1.Equals (a) && e.key2.Equals (b))
575                                         e.value = value;
576                         }
577
578                         int bucket = h % count;
579                         buckets [bucket] = new Entry (a, b, h, value, buckets [bucket]);
580
581                         // Grow whenever we double in size
582                         if (size++ == count) {
583                                 count <<= 1;
584                                 count ++;
585
586                                 Entry [] newBuckets = new Entry [count];
587                                 foreach (Entry root in buckets) {
588                                         Entry e = root;
589                                         while (e != null) {
590                                                 int newLoc = e.hash % count;
591                                                 Entry n = e.next;
592                                                 e.next = newBuckets [newLoc];
593                                                 newBuckets [newLoc] = e;
594                                                 e = n;
595                                         }
596                                 }
597
598                                 buckets = newBuckets;
599                         }
600                 }
601         }
602
603         class PartialMethodDefinitionInfo : MethodInfo
604         {
605                 MethodOrOperator mc;
606                 MethodAttributes attrs;
607
608                 public PartialMethodDefinitionInfo (MethodOrOperator mc)
609                 {
610                         this.mc = mc;
611                         if ((mc.ModFlags & Modifiers.STATIC) != 0)
612                                 attrs = MethodAttributes.Static;
613                 }
614
615                 public override MethodInfo GetBaseDefinition ()
616                 {
617                         throw new NotImplementedException ();
618                 }
619
620                 public override ICustomAttributeProvider ReturnTypeCustomAttributes
621                 {
622                         get { throw new NotImplementedException (); }
623                 }
624
625                 public override MethodAttributes Attributes
626                 {
627                         get { return attrs; }
628                 }
629
630                 public override MethodImplAttributes GetMethodImplementationFlags ()
631                 {
632                         throw new NotImplementedException ();
633                 }
634
635                 public override ParameterInfo [] GetParameters ()
636                 {
637                         throw new NotImplementedException ();
638                 }
639
640                 public override object Invoke (object obj, BindingFlags invokeAttr, Binder binder, object [] parameters, CultureInfo culture)
641                 {
642                         throw new NotImplementedException ();
643                 }
644
645                 public override RuntimeMethodHandle MethodHandle
646                 {
647                         get { throw new NotImplementedException (); }
648                 }
649
650                 public override Type DeclaringType
651                 {
652                         get { return mc.Parent.TypeBuilder; }
653                 }
654
655                 public override object [] GetCustomAttributes (Type attributeType, bool inherit)
656                 {
657                         throw new NotImplementedException ();
658                 }
659
660                 public override object [] GetCustomAttributes (bool inherit)
661                 {
662                         throw new NotImplementedException ();
663                 }
664
665                 public override Type ReturnType {
666                         get {
667                                 return mc.MemberType;
668                         }
669                 }
670
671                 public override bool IsDefined (Type attributeType, bool inherit)
672                 {
673                         throw new NotImplementedException ();
674                 }
675
676                 public override string Name
677                 {
678                         get { return mc.Name; }
679                 }
680
681                 public override Type ReflectedType
682                 {
683                         get { throw new NotImplementedException (); }
684                 }
685         }
686
687 }