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