Add new test
[mono.git] / mcs / mcs / typemanager.cs
1 //
2 // typemanager.cs: C# type manager
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //
6 // Licensed under the terms of the GNU GPL
7 //
8 // (C) 2001 Ximian, Inc (http://www.ximian.com)
9 //
10 //
11
12 using System;
13 using System.Collections;
14 using System.Reflection;
15 using System.Reflection.Emit;
16
17 namespace Mono.CSharp {
18
19 public class TypeManager {
20         //
21         // A list of core types that the compiler requires or uses
22         //
23         static public Type object_type;
24         static public Type value_type;
25         static public Type string_type;
26         static public Type int32_type;
27         static public Type uint32_type;
28         static public Type int64_type;
29         static public Type uint64_type;
30         static public Type float_type;
31         static public Type double_type;
32         static public Type char_type;
33         static public Type char_ptr_type;
34         static public Type short_type;
35         static public Type decimal_type;
36         static public Type bool_type;
37         static public Type sbyte_type;
38         static public Type byte_type;
39         static public Type ushort_type;
40         static public Type enum_type;
41         static public Type delegate_type;
42         static public Type multicast_delegate_type;
43         static public Type void_type;
44         static public Type enumeration_type;
45         static public Type array_type;
46         static public Type runtime_handle_type;
47         static public Type icloneable_type;
48         static public Type type_type;
49         static public Type ienumerator_type;
50         static public Type idisposable_type;
51         static public Type default_member_type;
52         static public Type iasyncresult_type;
53         static public Type asynccallback_type;
54         static public Type intptr_type;
55         static public Type monitor_type;
56         static public Type runtime_field_handle_type;
57         static public Type attribute_usage_type;
58         static public Type dllimport_type;
59         static public Type unverifiable_code_type;
60         static public Type methodimpl_attr_type;
61         static public Type param_array_type;
62         static public Type void_ptr_type;
63         
64         //
65         // Internal, not really used outside
66         //
67         Type runtime_helpers_type;
68         
69         //
70         // These methods are called by code generated by the compiler
71         //
72         static public MethodInfo string_concat_string_string;
73         static public MethodInfo string_concat_object_object;
74         static public MethodInfo string_isinterneted_string;
75         static public MethodInfo system_type_get_type_from_handle;
76         static public MethodInfo object_getcurrent_void;
77         static public MethodInfo bool_movenext_void;
78         static public MethodInfo void_dispose_void;
79         static public MethodInfo void_monitor_enter_object;
80         static public MethodInfo void_monitor_exit_object;
81         static public MethodInfo void_initializearray_array_fieldhandle;
82         static public MethodInfo int_getlength_int;
83         static public MethodInfo delegate_combine_delegate_delegate;
84         static public MethodInfo delegate_remove_delegate_delegate;
85         static public MethodInfo int_get_offset_to_string_data;
86         
87         //
88         // The attribute constructors.
89         //
90         static public ConstructorInfo cons_param_array_attribute;
91         
92         // <remarks>
93         //   Holds the Array of Assemblies that have been loaded
94         //   (either because it is the default or the user used the
95         //   -r command line option)
96         // </remarks>
97         ArrayList assemblies;
98
99         // <remarks>
100         //  Keeps a list of module builders. We used this to do lookups
101         //  on the modulebuilder using GetType -- needed for arrays
102         // </remarks>
103         ArrayList modules;
104
105         // <remarks>
106         //   This is the type_cache from the assemblies to avoid
107         //   hitting System.Reflection on every lookup.
108         // </summary>
109         Hashtable types;
110
111         // <remarks>
112         //  This is used to hotld the corresponding TypeContainer objects
113         //  since we need this in FindMembers
114         // </remarks>
115         Hashtable typecontainers;
116
117         // <remarks>
118         //   Keeps track of those types that are defined by the
119         //   user's program
120         // </remarks>
121         ArrayList user_types;
122
123         // <remarks>
124         //   Keeps a mapping between TypeBuilders and their TypeContainers
125         // </remarks>
126         static PtrHashtable builder_to_container;
127
128         // <remarks>
129         //   Maps MethodBase.RuntimeTypeHandle to a Type array that contains
130         //   the arguments to the method
131         // </remarks>
132         static Hashtable method_arguments;
133
134         // <remarks>
135         //   Maybe `method_arguments' should be replaced and only
136         //   method_internal_params should be kept?
137         // <remarks>
138         static Hashtable method_internal_params;
139
140         static PtrHashtable builder_to_interface;
141
142         // <remarks>
143         //  Keeps track of delegate types
144         // </remarks>
145
146         static Hashtable builder_to_delegate;
147
148         // <remarks>
149         //  Keeps track of enum types
150         // </remarks>
151
152         static Hashtable builder_to_enum;
153
154         // <remarks>
155         //  Keeps track of attribute types
156         // </remarks>
157
158         static Hashtable builder_to_attr;
159
160         public TypeManager ()
161         {
162                 assemblies = new ArrayList ();
163                 modules = new ArrayList ();
164                 user_types = new ArrayList ();
165                 types = new Hashtable ();
166                 typecontainers = new Hashtable ();
167                 builder_to_interface = new PtrHashtable ();
168                 builder_to_delegate = new PtrHashtable ();
169                 builder_to_enum  = new PtrHashtable ();
170                 builder_to_attr = new PtrHashtable ();
171         }
172
173         static TypeManager ()
174         {
175                 method_arguments = new PtrHashtable ();
176                 method_internal_params = new PtrHashtable ();
177                 builder_to_container = new PtrHashtable ();
178                 type_interface_cache = new PtrHashtable ();
179         }
180
181         public void AddUserType (string name, TypeBuilder t)
182         {
183                 types.Add (name, t);
184                 user_types.Add (t);
185         }
186         
187         public void AddUserType (string name, TypeBuilder t, TypeContainer tc)
188         {
189                 AddUserType (name, t);
190                 builder_to_container.Add (t, tc);
191                 typecontainers.Add (name, tc);
192         }
193
194         public void AddDelegateType (string name, TypeBuilder t, Delegate del)
195         {
196                 types.Add (name, t);
197                 builder_to_delegate.Add (t, del);
198         }
199         
200         public void AddEnumType (string name, TypeBuilder t, Enum en)
201         {
202                 types.Add (name, t);
203                 builder_to_enum.Add (t, en);
204         }
205
206         public void AddUserInterface (string name, TypeBuilder t, Interface i)
207         {
208                 AddUserType (name, t);
209                 builder_to_interface.Add (t, i);
210         }
211
212         public void RegisterAttrType (Type t, TypeContainer tc)
213         {
214                 builder_to_attr.Add (t, tc);
215         }
216                 
217         /// <summary>
218         ///   Returns the TypeContainer whose Type is `t' or null if there is no
219         ///   TypeContainer for `t' (ie, the Type comes from a library)
220         /// </summary>
221         public static TypeContainer LookupTypeContainer (Type t)
222         {
223                 return (TypeContainer) builder_to_container [t];
224         }
225
226         public Interface LookupInterface (Type t)
227         {
228                 return (Interface) builder_to_interface [t];
229         }
230
231         public static Delegate LookupDelegate (Type t)
232         {
233                 return (Delegate) builder_to_delegate [t];
234         }
235
236         public static Enum LookupEnum (Type t)
237         {
238                 return (Enum) builder_to_enum [t];
239         }
240         
241         public static TypeContainer LookupAttr (Type t)
242         {
243                 return (TypeContainer) builder_to_attr [t];
244         }
245         
246         /// <summary>
247         ///   Registers an assembly to load types from.
248         /// </summary>
249         public void AddAssembly (Assembly a)
250         {
251                 assemblies.Add (a);
252         }
253
254         /// <summary>
255         ///  Registers a module builder to lookup types from
256         /// </summary>
257         public void AddModule (ModuleBuilder mb)
258         {
259                 modules.Add (mb);
260         }
261
262         /// <summary>
263         ///   Returns the Type associated with @name
264         /// </summary>
265         public Type LookupType (string name)
266         {
267                 Type t;
268
269                 //
270                 // First lookup in user defined and cached values
271                 //
272
273                 t = (Type) types [name];
274                 if (t != null)
275                         return t;
276
277                 foreach (Assembly a in assemblies){
278                         t = a.GetType (name);
279                         if (t != null){
280                                 types [name] = t;
281
282                                 return t;
283                         }
284                 }
285
286                 foreach (ModuleBuilder mb in modules) {
287                         t = mb.GetType (name);
288                         if (t != null) {
289                                 types [name] = t;
290                                 return t;
291                         }
292                 }
293
294                 return null;
295         }
296
297         /// <summary>
298         ///   Returns the C# name of a type if possible, or the full type name otherwise
299         /// </summary>
300         static public string CSharpName (Type t)
301         {
302                 if (t == int32_type)
303                         return "int";
304                 else if (t == uint32_type)
305                         return "uint";
306                 else if (t == int64_type)
307                         return "long";
308                 else if (t == uint64_type)
309                         return "ulong";
310                 else if (t == float_type)
311                         return "float";
312                 else if (t == double_type)
313                         return "double";
314                 else if (t == char_type)
315                         return "char";
316                 else if (t == short_type)
317                         return "short";
318                 else if (t == decimal_type)
319                         return "decimal";
320                 else if (t == bool_type)
321                         return "bool";
322                 else if (t == sbyte_type)
323                         return "sbyte";
324                 else if (t == byte_type)
325                         return "byte";
326                 else if (t == short_type)
327                         return "short";
328                 else if (t == ushort_type)
329                         return "ushort";
330                 else if (t == string_type)
331                         return "string";
332                 else if (t == object_type)
333                         return "object";
334                 else if (t == void_type)
335                         return "void";
336                 else
337                         return t.FullName;
338         }
339
340         /// <summary>
341         ///   Looks up a type, and aborts if it is not found.  This is used
342         ///   by types required by the compiler
343         /// </summary>
344         Type CoreLookupType (string name)
345         {
346                 Type t = LookupType (name);
347
348                 if (t == null){
349                         Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
350                         Environment.Exit (0);
351                 }
352
353                 return t;
354         }
355
356         /// <summary>
357         ///   Returns the MethodInfo for a method named `name' defined
358         ///   in type `t' which takes arguments of types `args'
359         /// </summary>
360         MethodInfo GetMethod (Type t, string name, Type [] args)
361         {
362                 MethodInfo mi = t.GetMethod (name, args);
363
364                 if (mi == null)
365                         throw new Exception ("Can not find the core function `" + name + "'");
366
367                 return mi;
368         }
369
370         ConstructorInfo GetConstructor (Type t, Type [] args)
371         {
372                 ConstructorInfo ci = t.GetConstructor (args);
373
374                 if (ci == null)
375                         throw new Exception ("Can not find the core constructor for `" + t.FullName + "'");
376
377                 return ci;
378         }
379         
380         /// <remarks>
381         ///   The types have to be initialized after the initial
382         ///   population of the type has happened (for example, to
383         ///   bootstrap the corlib.dll
384         /// </remarks>
385         public void InitCoreTypes ()
386         {
387                 object_type   = CoreLookupType ("System.Object");
388                 value_type    = CoreLookupType ("System.ValueType");
389                 string_type   = CoreLookupType ("System.String");
390                 int32_type    = CoreLookupType ("System.Int32");
391                 int64_type    = CoreLookupType ("System.Int64");
392                 uint32_type   = CoreLookupType ("System.UInt32"); 
393                 uint64_type   = CoreLookupType ("System.UInt64"); 
394                 float_type    = CoreLookupType ("System.Single");
395                 double_type   = CoreLookupType ("System.Double");
396                 byte_type     = CoreLookupType ("System.Byte");
397                 sbyte_type    = CoreLookupType ("System.SByte");
398                 char_type     = CoreLookupType ("System.Char");
399                 char_ptr_type = CoreLookupType ("System.Char*");
400                 short_type    = CoreLookupType ("System.Int16");
401                 ushort_type   = CoreLookupType ("System.UInt16");
402                 decimal_type  = CoreLookupType ("System.Decimal");
403                 bool_type     = CoreLookupType ("System.Boolean");
404                 enum_type     = CoreLookupType ("System.Enum");
405
406                 multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
407                 delegate_type           = CoreLookupType ("System.Delegate");
408
409                 array_type    = CoreLookupType ("System.Array");
410                 void_type     = CoreLookupType ("System.Void");
411                 type_type     = CoreLookupType ("System.Type");
412
413                 runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
414                 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
415                 default_member_type  = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
416                 runtime_handle_type  = CoreLookupType ("System.RuntimeTypeHandle");
417                 asynccallback_type   = CoreLookupType ("System.AsyncCallback");
418                 iasyncresult_type    = CoreLookupType ("System.IAsyncResult");
419                 ienumerator_type     = CoreLookupType ("System.Collections.IEnumerator");
420                 idisposable_type     = CoreLookupType ("System.IDisposable");
421                 icloneable_type      = CoreLookupType ("System.ICloneable");
422                 monitor_type         = CoreLookupType ("System.Threading.Monitor");
423                 intptr_type          = CoreLookupType ("System.IntPtr");
424
425                 attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
426                 dllimport_type       = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute");
427                 methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute");
428                 param_array_type     = CoreLookupType ("System.ParamArrayAttribute");
429
430                 unverifiable_code_type = CoreLookupType ("System.Security.UnverifiableCodeAttribute");
431
432                 void_ptr_type        = CoreLookupType ("System.Void*");
433                 
434                 //
435                 // Now load the default methods that we use.
436                 //
437                 Type [] string_string = { string_type, string_type };
438                 string_concat_string_string = GetMethod (
439                         string_type, "Concat", string_string);
440
441                 Type [] object_object = { object_type, object_type };
442                 string_concat_object_object = GetMethod (
443                         string_type, "Concat", object_object);
444
445                 Type [] string_ = { string_type };
446                 string_isinterneted_string = GetMethod (
447                         string_type, "IsInterned", string_);
448                 
449                 Type [] runtime_type_handle = { runtime_handle_type };
450                 system_type_get_type_from_handle = GetMethod (
451                         type_type, "GetTypeFromHandle", runtime_type_handle);
452
453                 Type [] delegate_delegate = { delegate_type, delegate_type };
454                 delegate_combine_delegate_delegate = GetMethod (
455                                 delegate_type, "Combine", delegate_delegate);
456
457                 delegate_remove_delegate_delegate = GetMethod (
458                                 delegate_type, "Remove", delegate_delegate);
459
460                 //
461                 // Void arguments
462                 //
463                 Type [] void_arg = {  };
464                 object_getcurrent_void = GetMethod (
465                         ienumerator_type, "get_Current", void_arg);
466                 bool_movenext_void = GetMethod (
467                         ienumerator_type, "MoveNext", void_arg);
468                 void_dispose_void = GetMethod (
469                         idisposable_type, "Dispose", void_arg);
470                 int_get_offset_to_string_data = GetMethod (
471                         runtime_helpers_type, "get_OffsetToStringData", void_arg);
472
473                 //
474                 // object arguments
475                 //
476                 Type [] object_arg = { object_type };
477                 void_monitor_enter_object = GetMethod (
478                         monitor_type, "Enter", object_arg);
479                 void_monitor_exit_object = GetMethod (
480                         monitor_type, "Exit", object_arg);
481
482                 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
483                 
484                 void_initializearray_array_fieldhandle = GetMethod (
485                         runtime_helpers_type, "InitializeArray", array_field_handle_arg);
486
487                 //
488                 // Array functions
489                 //
490                 Type [] int_arg = { int32_type };
491                 int_getlength_int = GetMethod (
492                         array_type, "GetLength", int_arg);
493                 
494                 //
495                 // Attributes
496                 //
497                 cons_param_array_attribute = GetConstructor (
498                         param_array_type, void_arg);
499                 
500         }
501
502         const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
503         
504         public MemberInfo [] FindMembers (Type t, MemberTypes mt, BindingFlags bf,
505                                           MemberFilter filter, object criteria)
506         {
507                 //
508                 // We have to take care of arrays specially, because GetType on
509                 // a TypeBuilder array will return a Type, not a TypeBuilder,
510                 // and we can not call FindMembers on this type.
511                 //
512                 if (t.IsSubclassOf (TypeManager.array_type))
513                         return TypeManager.array_type.FindMembers (mt, bf, filter, criteria);
514                 
515                 if (!(t is TypeBuilder)){
516                         //
517                         // Since FindMembers will not lookup both static and instance
518                         // members, we emulate this behaviour here.
519                         //
520                         if ((bf & instance_and_static) == instance_and_static){
521                                 MemberInfo [] i_members = t.FindMembers (
522                                         mt, bf & ~BindingFlags.Static, filter, criteria);
523                                 MemberInfo [] s_members = t.FindMembers (
524                                         mt, bf & ~BindingFlags.Instance, filter, criteria);
525
526                                 int i_len = i_members.Length;
527                                 int s_len = s_members.Length;
528                                 if (i_len > 0 || s_len > 0){
529                                         MemberInfo [] both = new MemberInfo [i_len + s_len];
530
531                                         i_members.CopyTo (both, 0);
532                                         s_members.CopyTo (both, i_len);
533
534                                         return both;
535                                 } else
536                                         return i_members;
537                         }
538                         return t.FindMembers (mt, bf, filter, criteria);
539                 }
540
541                 //
542                 // FIXME: We should not have builder_to_blah everywhere,
543                 // we should just have a builder_to_findmemberizable
544                 // and have them implement a new ICanFindMembers interface
545                 //
546                 Enum e = (Enum) builder_to_enum [t];
547
548                 if (e != null)
549                         return e.FindMembers (mt, bf, filter, criteria);
550                 
551                 Delegate del = (Delegate) builder_to_delegate [t];
552
553                 if (del != null)
554                         return del.FindMembers (mt, bf, filter, criteria);
555
556                 Interface iface = (Interface) builder_to_interface [t];
557
558                 if (iface != null) 
559                         return iface.FindMembers (mt, bf, filter, criteria);
560                 
561                 TypeContainer tc = (TypeContainer) builder_to_container [t];
562
563                 if (tc != null)
564                         return tc.FindMembers (mt, bf, filter, criteria);
565
566                 return null;
567         }
568
569         public static bool IsBuiltinType (Type t)
570         {
571                 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
572                     t == int64_type || t == uint64_type || t == float_type || t == double_type ||
573                     t == char_type || t == short_type || t == decimal_type || t == bool_type ||
574                     t == sbyte_type || t == byte_type || t == ushort_type)
575                         return true;
576                 else
577                         return false;
578         }
579
580         public static bool IsDelegateType (Type t)
581         {
582                 if (t.IsSubclassOf (TypeManager.delegate_type))
583                         return true;
584                 else
585                         return false;
586         }
587         
588         public static bool IsEnumType (Type t)
589         {
590                 if (t.IsSubclassOf (TypeManager.enum_type))
591                         return true;
592                 else
593                         return false;
594         }
595         
596         public static bool IsInterfaceType (Type t)
597         {
598                 Interface iface = (Interface) builder_to_interface [t];
599
600                 if (iface != null)
601                         return true;
602                 else
603                         return false;
604         }
605
606         /// <summary>
607         ///   Returns the User Defined Types
608         /// </summary>
609         public ArrayList UserTypes {
610                 get {
611                         return user_types;
612                 }
613         }
614
615         public Hashtable TypeContainers {
616                 get {
617                         return typecontainers;
618                 }
619         }
620
621         static Hashtable builder_to_constant;
622
623         public static void RegisterConstant (FieldBuilder fb, Const c)
624         {
625                 if (builder_to_constant == null)
626                         builder_to_constant = new PtrHashtable ();
627
628                 if (builder_to_constant.Contains (fb))
629                         return;
630
631                 builder_to_constant.Add (fb, c);
632         }
633
634         public static Const LookupConstant (FieldBuilder fb)
635         {
636                 if (builder_to_constant == null)
637                         return null;
638                 
639                 return (Const) builder_to_constant [fb];
640         }
641         
642         /// <summary>
643         ///   Gigantic work around for missing features in System.Reflection.Emit follows.
644         /// </summary>
645         ///
646         /// <remarks>
647         ///   Since System.Reflection.Emit can not return MethodBase.GetParameters
648         ///   for anything which is dynamic, and we need this in a number of places,
649         ///   we register this information here, and use it afterwards.
650         /// </remarks>
651         static public bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
652         {
653                 method_arguments.Add (mb, args);
654                 method_internal_params.Add (mb, ip);
655                 
656                 return true;
657         }
658         
659         static public InternalParameters LookupParametersByBuilder (MethodBase mb)
660         {
661                 if (! (mb is ConstructorBuilder || mb is MethodBuilder))
662                         return null;
663                 
664                 if (method_internal_params.Contains (mb))
665                         return (InternalParameters) method_internal_params [mb];
666                 else
667                         throw new Exception ("Argument for Method not registered" + mb);
668         }
669
670         /// <summary>
671         ///    Returns the argument types for a method based on its methodbase
672         ///
673         ///    For dynamic methods, we use the compiler provided types, for
674         ///    methods from existing assemblies we load them from GetParameters,
675         ///    and insert them into the cache
676         /// </summary>
677         static public Type [] GetArgumentTypes (MethodBase mb)
678         {
679                 if (method_arguments.Contains (mb))
680                         return (Type []) method_arguments [mb];
681                 else {
682                         ParameterInfo [] pi = mb.GetParameters ();
683                         int c = pi.Length;
684                         Type [] types = new Type [c];
685                         
686                         for (int i = 0; i < c; i++)
687                                 types [i] = pi [i].ParameterType;
688
689                         method_arguments.Add (mb, types);
690                         return types;
691                 }
692         }
693         
694         // <remarks>
695         //  This is a workaround the fact that GetValue is not
696         //  supported for dynamic types
697         // </remarks>
698         static Hashtable fields = new Hashtable ();
699         static public bool RegisterFieldValue (FieldBuilder fb, object value)
700         {
701                 if (fields.Contains (fb))
702                         return false;
703
704                 fields.Add (fb, value);
705
706                 return true;
707         }
708
709         static public object GetValue (FieldBuilder fb)
710         {
711                 return fields [fb];
712         }
713
714         static Hashtable fieldbuilders_to_fields = new Hashtable ();
715         static public bool RegisterField (FieldBuilder fb, Field f)
716         {
717                 if (fieldbuilders_to_fields.Contains (fb))
718                         return false;
719
720                 fieldbuilders_to_fields.Add (fb, f);
721                 return true;
722         }
723
724         static public Field GetField (FieldInfo fb)
725         {
726                 return (Field) fieldbuilders_to_fields [fb];
727         }
728         
729         static Hashtable events;
730
731         static public bool RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
732         {
733                 if (events == null)
734                         events = new Hashtable ();
735
736                 if (events.Contains (eb))
737                         return false;
738
739                 events.Add (eb, new Pair (add, remove));
740
741                 return true;
742         }
743
744         static public MethodInfo GetAddMethod (EventInfo ei)
745         {
746                 if (ei is MyEventBuilder) {
747                         Pair pair = (Pair) events [ei];
748
749                         return (MethodInfo) pair.First;
750                 } else
751                         return ei.GetAddMethod ();
752         }
753
754         static public MethodInfo GetRemoveMethod (EventInfo ei)
755         {
756                 if (ei is MyEventBuilder) {
757                         Pair pair = (Pair) events [ei];
758
759                         return (MethodInfo) pair.Second;
760                 } else
761                         return ei.GetAddMethod ();
762         }
763
764         static Hashtable properties;
765         
766         static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
767         {
768                 if (properties == null)
769                         properties = new Hashtable ();
770
771                 if (properties.Contains (pb))
772                         return false;
773
774                 properties.Add (pb, new Pair (get, set));
775
776                 return true;
777         }
778         
779         //
780         // FIXME: we need to return the accessors depending on whether
781         // they are visible or not.
782         //
783         static public MethodInfo [] GetAccessors (PropertyInfo pi)
784         {
785                 MethodInfo [] ret;
786
787                 if (pi is PropertyBuilder){
788                         Pair pair = (Pair) properties [pi];
789
790                         ret = new MethodInfo [2];
791                         ret [0] = (MethodInfo) pair.First;
792                         ret [1] = (MethodInfo) pair.Second;
793
794                         return ret;
795                 } else {
796                         MethodInfo [] mi = new MethodInfo [2];
797
798                         //
799                         // Why this and not pi.GetAccessors?
800                         // Because sometimes index 0 is the getter
801                         // sometimes it is 1
802                         //
803                         mi [0] = pi.GetGetMethod (true);
804                         mi [1] = pi.GetSetMethod (true);
805
806                         return mi;
807                 }
808         }
809
810         static public MethodInfo GetPropertyGetter (PropertyInfo pi)
811         {
812                 if (pi is PropertyBuilder){
813                         Pair de = (Pair) properties [pi];
814
815                         return (MethodInfo) de.Second;
816                 } else
817                         return pi.GetSetMethod ();
818         }
819
820         static public MethodInfo GetPropertySetter (PropertyInfo pi)
821         {
822                 if (pi is PropertyBuilder){
823                         Pair de = (Pair) properties [pi];
824
825                         return (MethodInfo) de.First;
826                 } else
827                         return pi.GetGetMethod ();
828         }
829                                 
830         // <remarks>
831         //  The following is used to check if a given type implements an interface.
832         //  The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
833         // </remarks>
834
835         static Hashtable type_interface_cache;
836         public static bool ImplementsInterface (Type t, Type iface)
837         {
838                 Type [] interfaces;
839
840                 do {
841                         interfaces = t.GetInterfaces ();
842
843                         for (int i = interfaces.Length; i > 0; ){
844                                 i--;
845                                 if (interfaces [i] == iface)
846                                         return true;
847                         }
848                         t = t.BaseType;
849                 } while (t != null);
850                 
851                 return false;
852         }
853
854         //
855         // This is needed, because enumerations from assemblies
856         // do not report their underlyingtype, but they report
857         // themselves
858         //
859         public static Type EnumToUnderlying (Type t)
860         {
861                 t = t.UnderlyingSystemType;
862                 if (!TypeManager.IsEnumType (t))
863                         return t;
864                 
865                 TypeCode tc = Type.GetTypeCode (t);
866
867                 switch (tc){
868                 case TypeCode.Boolean:
869                         return TypeManager.bool_type;
870                 case TypeCode.Byte:
871                         return TypeManager.byte_type;
872                 case TypeCode.SByte:
873                         return TypeManager.sbyte_type;
874                 case TypeCode.Char:
875                         return TypeManager.char_type;
876                 case TypeCode.Int16:
877                         return TypeManager.short_type;
878                 case TypeCode.UInt16:
879                         return TypeManager.ushort_type;
880                 case TypeCode.Int32:
881                         return TypeManager.int32_type;
882                 case TypeCode.UInt32:
883                         return TypeManager.uint32_type;
884                 case TypeCode.Int64:
885                         return TypeManager.int64_type;
886                 case TypeCode.UInt64:
887                         return TypeManager.uint64_type;
888                 }
889                 throw new Exception ("Unhandled typecode in enum" + tc);
890         }
891
892         /// <summary>
893         ///   Utility function that can be used to probe whether a type
894         ///   is managed or not.  
895         /// </summary>
896         public static bool VerifyUnManaged (Type t, Location loc)
897         {
898                 if (t.IsValueType){
899                         //
900                         // FIXME: this is more complex, we actually need to
901                         // make sure that the type does not contain any
902                         // classes itself
903                         //
904                         return true;
905                 }
906
907                 Report.Error (
908                         208, loc,
909                         "Cannot take the address or size of a variable of a managed type ('" +
910                         CSharpName (t) + "')");
911                 return false;   
912         }
913         
914         /// <summary>
915         ///   Returns the name of the indexer in a given type.
916         /// </summary>
917         /// <remarks>
918         ///   The default is not always `Item'.  The user can change this behaviour by
919         ///   using the DefaultMemberAttribute in the class.
920         ///
921         ///   For example, the String class indexer is named `Chars' not `Item' 
922         /// </remarks>
923         public static string IndexerPropertyName (Type t)
924         {
925                 
926                 if (t is TypeBuilder) {
927                         TypeContainer tc = (TypeContainer) builder_to_container [t];
928
929                         Attributes attrs = tc.OptAttributes;
930                         
931                         if (attrs == null || attrs.AttributeSections == null)
932                                 return "Item";
933
934                         foreach (AttributeSection asec in attrs.AttributeSections) {
935
936                                 if (asec.Attributes == null)
937                                         continue;
938
939                                 foreach (Attribute a in asec.Attributes) {
940                                         if (a.Name.IndexOf ("DefaultMember") != -1) {
941                                                 ArrayList pos_args = (ArrayList) a.Arguments [0];
942                                                 Expression e = ((Argument) pos_args [0]).expr;
943
944                                                 if (e is StringConstant)
945                                                         return ((StringConstant) e).Value;
946                                         }
947                                 }
948                         }
949
950                         return "Item";
951                 }
952                 
953                 System.Attribute attr = System.Attribute.GetCustomAttribute (t, TypeManager.default_member_type);
954                 
955                 if (attr != null)
956                 {
957                         DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
958                         
959                         return dma.MemberName;
960                 }
961
962                 return "Item";
963         }
964
965         public static void MakePinned (LocalBuilder builder)
966         {
967                 //
968                 // FIXME: Flag the "LocalBuilder" type as being
969                 // pinned.  Figure out API.
970                 //
971         }
972 }
973
974 }