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