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