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