2001-11-22 Ravi Pratap <ravi@ximian.com>
[mono.git] / mcs / mcs / typemanager.cs
1 //
2 // typegen.cs: type generation 
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 short_type;
34         static public Type decimal_type;
35         static public Type bool_type;
36         static public Type sbyte_type;
37         static public Type byte_type;
38         static public Type ushort_type;
39         static public Type enum_type;
40         static public Type delegate_type;
41         static public Type void_type;
42         static public Type enumeration_type;
43         static public Type array_type;
44         static public Type runtime_handle_type;
45         static public Type icloneable_type;
46         static public Type type_type;
47         static public Type ienumerator_type;
48         static public Type idisposable_type;
49         static public Type default_member_type;
50         static public Type iasyncresult_type;
51         static public Type asynccallback_type;
52         static public Type intptr_type;
53         static public Type monitor_type;
54         static public Type runtime_field_handle_type;
55         static public Type attribute_usage_type;
56         static public Type param_array_type;
57         
58         //
59         // Internal, not really used outside
60         //
61         Type runtime_helpers_type;
62         
63         //
64         // These methods are called by code generated by the compiler
65         //
66         static public MethodInfo string_concat_string_string;
67         static public MethodInfo string_concat_object_object;
68         static public MethodInfo system_type_get_type_from_handle;
69         static public MethodInfo object_getcurrent_void;
70         static public MethodInfo bool_movenext_void;
71         static public MethodInfo void_dispose_void;
72         static public MethodInfo void_monitor_enter_object;
73         static public MethodInfo void_monitor_exit_object;
74         static public MethodInfo void_initializearray_array_fieldhandle;
75         static public MethodInfo int_getlength_int;
76         
77         //
78         // The attribute constructors.
79         //
80         static public ConstructorInfo cons_param_array_attribute;
81         
82         // <remarks>
83         //   Holds the Array of Assemblies that have been loaded
84         //   (either because it is the default or the user used the
85         //   -r command line option)
86         // </remarks>
87         ArrayList assemblies;
88
89         // <remarks>
90         //  Keeps a list of module builders. We used this to do lookups
91         //  on the modulebuilder using GetType -- needed for arrays
92         // </remarks>
93         ArrayList modules;
94
95         // <remarks>
96         //   This is the type_cache from the assemblies to avoid
97         //   hitting System.Reflection on every lookup.
98         // </summary>
99         Hashtable types;
100
101         // <remarks>
102         //  This is used to hotld the corresponding TypeContainer objects
103         //  since we need this in FindMembers
104         // </remarks>
105         Hashtable typecontainers;
106
107         // <remarks>
108         //   Keeps track of those types that are defined by the
109         //   user's program
110         // </remarks>
111         ArrayList user_types;
112
113         // <remarks>
114         //   Keeps a mapping between TypeBuilders and their TypeContainers
115         // </remarks>
116         static Hashtable builder_to_container;
117
118         // <remarks>
119         //   Maps MethodBase.RuntimeTypeHandle to a Type array that contains
120         //   the arguments to the method
121         // </remarks>
122         static Hashtable method_arguments;
123
124         static Hashtable builder_to_interface;
125
126         // <remarks>
127         //  Keeps track of delegate types
128         // </remarks>
129
130         static Hashtable builder_to_delegate;
131
132         // <remarks>
133         //  Keeps track of enum types
134         // </remarks>
135
136         static Hashtable builder_to_enum;
137
138         // <remarks>
139         //  Keeps track of attribute types
140         // </remarks>
141
142         static Hashtable builder_to_attr;
143
144         public TypeManager ()
145         {
146                 assemblies = new ArrayList ();
147                 modules = new ArrayList ();
148                 user_types = new ArrayList ();
149                 types = new Hashtable ();
150                 typecontainers = new Hashtable ();
151                 builder_to_interface = new Hashtable ();
152                 builder_to_delegate = new Hashtable ();
153                 builder_to_enum  = new Hashtable ();
154                 builder_to_attr = new Hashtable ();
155         }
156
157         static TypeManager ()
158         {
159                 method_arguments = new Hashtable ();
160                 builder_to_container = new Hashtable ();
161                 type_interface_cache = new Hashtable ();
162         }
163
164         static string MakeKey (Type t)
165         {
166                 return t.FullName + t.GetHashCode ();
167         }
168         
169         public void AddUserType (string name, TypeBuilder t)
170         {
171                 types.Add (name, t);
172                 user_types.Add (t);
173         }
174         
175         public void AddUserType (string name, TypeBuilder t, TypeContainer tc)
176         {
177                 AddUserType (name, t);
178                 builder_to_container.Add (MakeKey (t), tc);
179                 typecontainers.Add (name, tc);
180         }
181
182         public void AddDelegateType (string name, TypeBuilder t, Delegate del)
183         {
184                 types.Add (name, t);
185                 builder_to_delegate.Add (t, del);
186         }
187         
188         public void AddEnumType (string name, TypeBuilder t, Enum en)
189         {
190                 types.Add (name, t);
191                 builder_to_enum.Add (MakeKey (t), en);
192         }
193
194         public void AddUserInterface (string name, TypeBuilder t, Interface i)
195         {
196                 AddUserType (name, t);
197                 builder_to_interface.Add (MakeKey (t), i);
198         }
199
200         public void RegisterAttrType (Type t, TypeContainer tc)
201         {
202                 builder_to_attr.Add (MakeKey (t), tc);
203         }
204                 
205         /// <summary>
206         ///   Returns the TypeContainer whose Type is `t' or null if there is no
207         ///   TypeContainer for `t' (ie, the Type comes from a library)
208         /// </summary>
209         public static TypeContainer LookupTypeContainer (Type t)
210         {
211                 return (TypeContainer) builder_to_container [MakeKey (t)];
212         }
213
214         public Interface LookupInterface (Type t)
215         {
216                 return (Interface) builder_to_interface [MakeKey (t)];
217         }
218
219         public static Delegate LookupDelegate (Type t)
220         {
221                 return (Delegate) builder_to_delegate [t];
222         }
223
224         public static Enum LookupEnum (Type t)
225         {
226                 return (Enum) builder_to_enum [MakeKey (t)];
227         }
228         
229         public static TypeContainer LookupAttr (Type t)
230         {
231                 return (TypeContainer) builder_to_attr [MakeKey (t)];
232         }
233         
234         /// <summary>
235         ///   Registers an assembly to load types from.
236         /// </summary>
237         public void AddAssembly (Assembly a)
238         {
239                 assemblies.Add (a);
240         }
241
242         /// <summary>
243         ///  Registers a module builder to lookup types from
244         /// </summary>
245         public void AddModule (ModuleBuilder mb)
246         {
247                 modules.Add (mb);
248         }
249
250         /// <summary>
251         ///   Returns the Type associated with @name
252         /// </summary>
253         public Type LookupType (string name)
254         {
255                 Type t;
256
257                 //
258                 // First lookup in user defined and cached values
259                 //
260
261                 t = (Type) types [name];
262                 if (t != null)
263                         return t;
264
265                 foreach (Assembly a in assemblies){
266                         t = a.GetType (name);
267                         if (t != null){
268                                 types [name] = t;
269
270                                 return t;
271                         }
272                 }
273
274                 foreach (ModuleBuilder mb in modules) {
275                         t = mb.GetType (name);
276                         if (t != null) {
277                                 types [name] = t;
278                                 return t;
279                         }
280                 }
281
282                 return null;
283         }
284
285         /// <summary>
286         ///   Returns the C# name of a type if possible, or the full type name otherwise
287         /// </summary>
288         static public string CSharpName (Type t)
289         {
290                 if (t == int32_type)
291                         return "int";
292                 else if (t == uint32_type)
293                         return "uint";
294                 else if (t == int64_type)
295                         return "long";
296                 else if (t == uint64_type)
297                         return "ulong";
298                 else if (t == float_type)
299                         return "float";
300                 else if (t == double_type)
301                         return "double";
302                 else if (t == char_type)
303                         return "char";
304                 else if (t == short_type)
305                         return "short";
306                 else if (t == decimal_type)
307                         return "decimal";
308                 else if (t == bool_type)
309                         return "bool";
310                 else if (t == sbyte_type)
311                         return "sbyte";
312                 else if (t == byte_type)
313                         return "byte";
314                 else if (t == short_type)
315                         return "short";
316                 else if (t == ushort_type)
317                         return "ushort";
318                 else if (t == string_type)
319                         return "string";
320                 else if (t == object_type)
321                         return "object";
322                 else
323                         return t.FullName;
324         }
325
326         /// <summary>
327         ///   Looks up a type, and aborts if it is not found.  This is used
328         ///   by types required by the compiler
329         /// </summary>
330         Type CoreLookupType (string name)
331         {
332                 Type t = LookupType (name);
333
334                 if (t == null)
335                         throw new Exception ("Can not find core type " + name);
336
337                 return t;
338         }
339
340         /// <summary>
341         ///   Returns the MethodInfo for a method named `name' defined
342         ///   in type `t' which takes arguments of types `args'
343         /// </summary>
344         MethodInfo GetMethod (Type t, string name, Type [] args)
345         {
346                 MethodInfo mi = t.GetMethod (name, args);
347
348                 if (mi == null)
349                         throw new Exception ("Can not find the core function `" + name + "'");
350
351                 return mi;
352         }
353
354         ConstructorInfo GetConstructor (Type t, Type [] args)
355         {
356                 ConstructorInfo ci = t.GetConstructor (args);
357
358                 if (ci == null)
359                         throw new Exception ("Can not find the core constructor for `" + t.FullName + "'");
360
361                 return ci;
362         }
363         
364         /// <remarks>
365         ///   The types have to be initialized after the initial
366         ///   population of the type has happened (for example, to
367         ///   bootstrap the corlib.dll
368         /// </remarks>
369         public void InitCoreTypes ()
370         {
371                 object_type   = CoreLookupType ("System.Object");
372                 value_type    = CoreLookupType ("System.ValueType");
373                 string_type   = CoreLookupType ("System.String");
374                 int32_type    = CoreLookupType ("System.Int32");
375                 int64_type    = CoreLookupType ("System.Int64");
376                 uint32_type   = CoreLookupType ("System.UInt32"); 
377                 uint64_type   = CoreLookupType ("System.UInt64"); 
378                 float_type    = CoreLookupType ("System.Single");
379                 double_type   = CoreLookupType ("System.Double");
380                 byte_type     = CoreLookupType ("System.Byte");
381                 sbyte_type    = CoreLookupType ("System.SByte");
382                 char_type     = CoreLookupType ("System.Char");
383                 short_type    = CoreLookupType ("System.Int16");
384                 ushort_type   = CoreLookupType ("System.UInt16");
385                 decimal_type  = CoreLookupType ("System.Decimal");
386                 bool_type     = CoreLookupType ("System.Boolean");
387                 enum_type     = CoreLookupType ("System.Enum");
388                 delegate_type = CoreLookupType ("System.MulticastDelegate");
389                 array_type    = CoreLookupType ("System.Array");
390                 void_type     = CoreLookupType ("System.Void");
391                 type_type     = CoreLookupType ("System.Type");
392
393                 runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
394                 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
395                 default_member_type  = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
396                 runtime_handle_type  = CoreLookupType ("System.RuntimeTypeHandle");
397                 asynccallback_type   = CoreLookupType ("System.AsyncCallback");
398                 iasyncresult_type    = CoreLookupType ("System.IAsyncResult");
399                 ienumerator_type     = CoreLookupType ("System.Collections.IEnumerator");
400                 idisposable_type     = CoreLookupType ("System.IDisposable");
401                 icloneable_type      = CoreLookupType ("System.ICloneable");
402                 monitor_type         = CoreLookupType ("System.Threading.Monitor");
403                 intptr_type          = CoreLookupType ("System.IntPtr");
404
405                 attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
406                 param_array_type     = CoreLookupType ("System.ParamArrayAttribute");
407                 
408                 //
409                 // Now load the default methods that we use.
410                 //
411                 Type [] string_string = { string_type, string_type };
412                 string_concat_string_string = GetMethod (
413                         string_type, "Concat", string_string);
414
415                 Type [] object_object = { object_type, object_type };
416                 string_concat_object_object = GetMethod (
417                         string_type, "Concat", object_object);
418
419                 Type [] runtime_type_handle = { runtime_handle_type };
420                 system_type_get_type_from_handle = GetMethod (
421                         type_type, "GetTypeFromHandle", runtime_type_handle);
422
423                 //
424                 // Void arguments
425                 //
426                 Type [] void_arg = {  };
427                 object_getcurrent_void = GetMethod (
428                         ienumerator_type, "get_Current", void_arg);
429                 bool_movenext_void = GetMethod (
430                         ienumerator_type, "MoveNext", void_arg);
431                 void_dispose_void = GetMethod (
432                         idisposable_type, "Dispose", void_arg);
433
434                 //
435                 // object arguments
436                 //
437                 Type [] object_arg = { object_type };
438                 void_monitor_enter_object = GetMethod (
439                         monitor_type, "Enter", object_arg);
440                 void_monitor_exit_object = GetMethod (
441                         monitor_type, "Exit", object_arg);
442
443                 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
444                 
445                 void_initializearray_array_fieldhandle = GetMethod (
446                         runtime_helpers_type, "InitializeArray", array_field_handle_arg);
447
448                 //
449                 // Array functions
450                 //
451                 Type [] int_arg = { int32_type };
452                 int_getlength_int = GetMethod (
453                         array_type, "GetLength", int_arg);
454                 
455                 //
456                 // Attributes
457                 //
458                 cons_param_array_attribute = GetConstructor (
459                         param_array_type, void_arg);
460                 
461         }
462         
463         public MemberInfo [] FindMembers (Type t, MemberTypes mt, BindingFlags bf, MemberFilter filter, object criteria)
464         {
465                 string key = MakeKey (t);
466                 
467                 if (!(t is TypeBuilder))
468                         return t.FindMembers (mt, bf, filter, criteria);
469
470                 Enum e = (Enum) builder_to_enum [key];
471
472                 if (e != null)
473                         return e.FindMembers (mt, bf, filter, criteria);
474                 
475                 Delegate del = (Delegate) builder_to_delegate [t];
476
477                 if (del != null)
478                         return del.FindMembers (mt, bf, filter, criteria);
479
480                 Interface iface = (Interface) builder_to_interface [key];
481
482                 if (iface != null) 
483                         return iface.FindMembers (mt, bf, filter, criteria);
484                 
485                 TypeContainer tc = (TypeContainer) builder_to_container [key];
486
487                 if (tc != null)
488                         return tc.FindMembers (mt, bf, filter, criteria);
489
490                 return null;
491         }
492
493         public static bool IsBuiltinType (Type t)
494         {
495                 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
496                     t == int64_type || t == uint64_type || t == float_type || t == double_type ||
497                     t == char_type || t == short_type || t == decimal_type || t == bool_type ||
498                     t == sbyte_type || t == byte_type || t == ushort_type)
499                         return true;
500                 else
501                         return false;
502         }
503
504         public static bool IsDelegateType (Type t)
505         {
506                 Delegate del = (Delegate) builder_to_delegate [t];
507
508                 if (del != null)
509                         return true;
510                 else
511                         return false;
512         }
513
514         public static bool IsEnumType (Type t)
515         {
516                 Enum en = (Enum) builder_to_enum [t];
517
518                 if (en != null)
519                         return true;
520                 else
521                         return false;
522         }
523
524         public static bool IsInterfaceType (Type t)
525         {
526                 Interface iface = (Interface) builder_to_interface [t];
527
528                 if (iface != null)
529                         return true;
530                 else
531                         return false;
532         }
533
534         /// <summary>
535         ///   Returns the User Defined Types
536         /// </summary>
537         public ArrayList UserTypes {
538                 get {
539                         return user_types;
540                 }
541         }
542
543         public Hashtable TypeContainers {
544                 get {
545                         return typecontainers;
546                 }
547         }
548
549         static string GetSig (MethodBase mb)
550         {
551                 if (mb is MethodBuilder || mb is ConstructorBuilder)
552                         return mb.ReflectedType.FullName + ":" + mb;
553                 else
554                         return mb.MethodHandle.ToString ();
555         }
556         
557         //
558         // Gigantic work around for stupidity in System.Reflection.Emit follows
559         //
560         // Since System.Reflection.Emit can not return MethodBase.GetParameters
561         // for anything which is dynamic, and we need this in a number of places,
562         // we register this information here, and use it afterwards.
563         //
564         static public bool RegisterMethod (MethodBase mb, Type [] args)
565         {
566                 string s;
567                 
568                 s = GetSig (mb);
569
570                 if (method_arguments.Contains (s))
571                         return false;
572                 
573                 method_arguments.Add (s, args);
574                 return true;
575         }
576
577         /// <summary>
578         ///    Returns the argument types for a method based on its methodbase
579         ///
580         ///    For dynamic methods, we use the compiler provided types, for
581         ///    methods from existing assemblies we load them from GetParameters,
582         ///    and insert them into the cache
583         /// </summary>
584         static public Type [] GetArgumentTypes (MethodBase mb)
585         {
586                 string sig = GetSig (mb);
587                 object o = method_arguments [sig];
588
589                 if (method_arguments.Contains (sig))
590                         return (Type []) method_arguments [sig];
591                 else {
592                         ParameterInfo [] pi = mb.GetParameters ();
593                         int c = pi.Length;
594                         Type [] types = new Type [c];
595                         
596                         for (int i = 0; i < c; i++)
597                                 types [i] = pi [i].ParameterType;
598
599                         method_arguments.Add (sig, types);
600                         return types;
601                 }
602         }
603         
604         // <remarks>
605         //  This is a workaround the fact that GetValue is not
606         //  supported for dynamic types
607         // </remarks>
608         static Hashtable fields;
609
610         static public bool RegisterField (FieldBuilder fb, object value)
611         {
612                 if (fields == null)
613                         fields = new Hashtable ();
614
615                 if (fields.Contains (fb))
616                         return false;
617
618                 fields.Add (fb, value);
619
620                 return true;
621         }
622
623         static public object GetValue (FieldBuilder fb)
624         {
625                 return fields [fb];
626         }
627
628
629         static Hashtable properties;
630         
631         static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
632         {
633                 if (properties == null)
634                         properties = new Hashtable ();
635
636                 if (properties.Contains (pb))
637                         return false;
638
639                 properties.Add (pb, new DictionaryEntry (get, set));
640
641                 return true;
642         }
643         
644         static public MethodInfo [] GetAccessors (PropertyInfo pi)
645         {
646                 MethodInfo [] ret;
647                         
648                 if (pi is PropertyBuilder){
649                         DictionaryEntry de = (DictionaryEntry) properties [pi];
650
651                         ret = new MethodInfo [2];
652                         ret [0] = (MethodInfo) de.Key;
653                         ret [1] = (MethodInfo) de.Value;
654
655                         return ret;
656                 } else
657                         return pi.GetAccessors ();
658         }
659
660         // <remarks>
661         //  The following is used to check if a given type implements an interface.
662         //  The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
663         // </remarks>
664
665         static Hashtable type_interface_cache;
666
667         public static bool ImplementsInterface (Type t, Type iface)
668         {
669                 Type [] interfaces = (Type []) type_interface_cache [t];
670
671                 if (interfaces == null) {
672                         if (type_interface_cache.Contains (t))
673                                 return false;
674                         
675                         interfaces = t.GetInterfaces ();
676
677                         type_interface_cache [t] = interfaces;
678                 }
679
680                 if (interfaces == null)
681                         return false;
682
683                 for (int i = interfaces.Length; i > 0; ) {
684                         i--;
685                         if (interfaces [i] == iface)
686                                 return true;
687                 }
688
689                 return false;
690         }
691         
692
693         /// <summary>
694         ///   Returns the name of the indexer in a given type.
695         /// </summary>
696         /// <remarks>
697         ///   The default is not always `Item'.  The user can change this behaviour by
698         ///   using the DefaultMemberAttribute in the class.
699         ///
700         ///   For example, the String class indexer is named `Chars' not `Item' 
701         /// </remarks>
702         public static string IndexerPropertyName (Type t)
703         {
704                 
705                 //
706                 // FIXME: Replace with something that works around S.R.E failure
707                 //
708 #if FIXME
709                 System.Attribute attr;
710
711                 attr = System.Attribute.GetCustomAttribute (t, TypeManager.default_member_type);
712                 
713                 if (attr != null)
714                         {
715                                 DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
716                                 
717                                 return dma.MemberName;
718                         }
719 #endif
720                 return "Item";
721         }
722
723 }
724
725 }