2002-05-31 Rafael Teixeira <rafaelteixeirabr@hotmail.com>
[mono.git] / mcs / mbas / typemanager.cs
1 //
2 // typemanager.cs: C# type manager
3 //
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 //         Ravi Pratap     (ravi@ximian.com)
6 //
7 // Licensed under the terms of the GNU GPL
8 //
9 // (C) 2001 Ximian, Inc (http://www.ximian.com)
10 //
11 //
12 #define CACHE
13
14 using System;
15 using System.Collections;
16 using System.Reflection;
17 using System.Reflection.Emit;
18 using System.Text.RegularExpressions;
19 using System.Runtime.CompilerServices;
20
21 namespace Mono.CSharp {
22
23 public class TypeManager {
24         //
25         // A list of core types that the compiler requires or uses
26         //
27         static public Type object_type;
28         static public Type value_type;
29         static public Type string_type;
30         static public Type int32_type;
31         static public Type uint32_type;
32         static public Type int64_type;
33         static public Type uint64_type;
34         static public Type float_type;
35         static public Type double_type;
36         static public Type char_type;
37         static public Type char_ptr_type;
38         static public Type short_type;
39         static public Type decimal_type;
40         static public Type bool_type;
41         static public Type sbyte_type;
42         static public Type byte_type;
43         static public Type ushort_type;
44         static public Type enum_type;
45         static public Type delegate_type;
46         static public Type multicast_delegate_type;
47         static public Type void_type;
48         static public Type enumeration_type;
49         static public Type array_type;
50         static public Type runtime_handle_type;
51         static public Type icloneable_type;
52         static public Type type_type;
53         static public Type ienumerator_type;
54         static public Type idisposable_type;
55         static public Type default_member_type;
56         static public Type iasyncresult_type;
57         static public Type asynccallback_type;
58         static public Type intptr_type;
59         static public Type monitor_type;
60         static public Type runtime_field_handle_type;
61         static public Type attribute_type;
62         static public Type attribute_usage_type;
63         static public Type dllimport_type;
64         static public Type unverifiable_code_type;
65         static public Type methodimpl_attr_type;
66         static public Type marshal_as_attr_type;
67         static public Type param_array_type;
68         static public Type void_ptr_type;
69         static public Type indexer_name_type;
70         static public Type trace_type;
71         static public Type debug_type;
72         
73         static public Type [] NoTypes;
74         
75         //
76         // Internal, not really used outside
77         //
78         static Type runtime_helpers_type;
79         
80         //
81         // These methods are called by code generated by the compiler
82         //
83         static public MethodInfo string_concat_string_string;
84         static public MethodInfo string_concat_object_object;
85         static public MethodInfo string_isinterneted_string;
86         static public MethodInfo system_type_get_type_from_handle;
87         static public MethodInfo object_getcurrent_void;
88         static public MethodInfo bool_movenext_void;
89         static public MethodInfo void_dispose_void;
90         static public MethodInfo void_monitor_enter_object;
91         static public MethodInfo void_monitor_exit_object;
92         static public MethodInfo void_initializearray_array_fieldhandle;
93         static public MethodInfo int_getlength_int;
94         static public MethodInfo delegate_combine_delegate_delegate;
95         static public MethodInfo delegate_remove_delegate_delegate;
96         static public MethodInfo int_get_offset_to_string_data;
97         static public MethodInfo int_array_get_length;
98         
99         //
100         // The attribute constructors.
101         //
102         static public ConstructorInfo cons_param_array_attribute;
103         static public ConstructorInfo void_decimal_ctor_five_args;
104         
105         // <remarks>
106         //   Holds the Array of Assemblies that have been loaded
107         //   (either because it is the default or the user used the
108         //   -r command line option)
109         // </remarks>
110         static Assembly [] assemblies;
111
112         // <remarks>
113         //  Keeps a list of module builders. We used this to do lookups
114         //  on the modulebuilder using GetType -- needed for arrays
115         // </remarks>
116         static ModuleBuilder [] modules;
117
118         // <remarks>
119         //   This is the type_cache from the assemblies to avoid
120         //   hitting System.Reflection on every lookup.
121         // </summary>
122         static Hashtable types;
123
124         // <remarks>
125         //  This is used to hotld the corresponding TypeContainer objects
126         //  since we need this in FindMembers
127         // </remarks>
128         static Hashtable typecontainers;
129
130         // <remarks>
131         //   Keeps track of those types that are defined by the
132         //   user's program
133         // </remarks>
134         static ArrayList user_types;
135
136         // <remarks>
137         //   Keeps a mapping between TypeBuilders and their TypeContainers
138         // </remarks>
139         static PtrHashtable builder_to_container;
140
141         // <remarks>
142         //   Tracks the interfaces implemented by typebuilders.  We only
143         //   enter those who do implement or or more interfaces
144         // </remarks>
145         static PtrHashtable builder_to_ifaces;
146
147         // <remarks>
148         //   Maps MethodBase.RuntimeTypeHandle to a Type array that contains
149         //   the arguments to the method
150         // </remarks>
151         static Hashtable method_arguments;
152
153         // <remarks>
154         //   Maybe `method_arguments' should be replaced and only
155         //   method_internal_params should be kept?
156         // <remarks>
157         static Hashtable method_internal_params;
158
159         static PtrHashtable builder_to_interface;
160
161         // <remarks>
162         //  Keeps track of delegate types
163         // </remarks>
164
165         static Hashtable builder_to_delegate;
166
167         // <remarks>
168         //  Keeps track of enum types
169         // </remarks>
170
171         static Hashtable builder_to_enum;
172
173         // <remarks>
174         //  Keeps track of attribute types
175         // </remarks>
176
177         static Hashtable builder_to_attr;
178
179         struct Signature {
180                 public string name;
181                 public Type [] args;
182         }
183
184         /// <summary>
185         ///   A filter for Findmembers that uses the Signature object to
186         ///   extract objects
187         /// </summary>
188         static bool SignatureFilter (MemberInfo mi, object criteria)
189         {
190                 Signature sig = (Signature) criteria;
191
192                 if (!(mi is MethodBase))
193                         return false;
194                 
195                 if (mi.Name != sig.name)
196                         return false;
197
198                 int count = sig.args.Length;
199                 
200                 if (mi is MethodBuilder || mi is ConstructorBuilder){
201                         Type [] candidate_args = GetArgumentTypes ((MethodBase) mi);
202
203                         if (candidate_args.Length != count)
204                                 return false;
205                         
206                         for (int i = 0; i < count; i++)
207                                 if (candidate_args [i] != sig.args [i])
208                                         return false;
209                         
210                         return true;
211                 } else {
212                         ParameterInfo [] pars = ((MethodBase) mi).GetParameters ();
213
214                         if (pars.Length != count)
215                                 return false;
216
217                         for (int i = 0; i < count; i++)
218                                 if (pars [i].ParameterType != sig.args [i])
219                                         return false;
220                         return true;
221                 }
222         }
223
224         // A delegate that points to the filter above.
225         static MemberFilter signature_filter;
226
227         static TypeManager ()
228         {
229                 assemblies = new Assembly [0];
230                 modules = null;
231                 user_types = new ArrayList ();
232                 
233                 types = new Hashtable ();
234                 typecontainers = new Hashtable ();
235                 
236                 builder_to_interface = new PtrHashtable ();
237                 builder_to_delegate = new PtrHashtable ();
238                 builder_to_enum  = new PtrHashtable ();
239                 builder_to_attr = new PtrHashtable ();
240                 method_arguments = new PtrHashtable ();
241                 method_internal_params = new PtrHashtable ();
242                 builder_to_container = new PtrHashtable ();
243                 builder_to_ifaces = new PtrHashtable ();
244                 
245                 NoTypes = new Type [0];
246
247                 signature_filter = new MemberFilter (SignatureFilter);
248         }
249
250         public static void AddUserType (string name, TypeBuilder t, Type [] ifaces)
251         {
252                 try {
253                         types.Add (name, t);
254                 } catch {
255                         Type prev = (Type) types [name];
256                         TypeContainer tc = (TypeContainer) builder_to_container [prev];
257
258                         if (tc != null){
259                                 //
260                                 // This probably never happens, as we catch this before
261                                 //
262                                 Report.Error (-17, "The type `" + name + "' has already been defined.");
263                                 return;
264                         }
265
266                         tc = (TypeContainer) builder_to_container [t];
267                         
268                         Report.Warning (
269                                 1595, "The type `" + name + "' is defined in an existing assembly;"+
270                                 " Using the new definition from: " + tc.Location);
271                         Report.Warning (1595, "Previously defined in: " + prev.Assembly.FullName);
272                         
273                         types.Remove (name);
274                         types.Add (name, t);
275                 }
276                 user_types.Add (t);
277                         
278                 if (ifaces != null)
279                         builder_to_ifaces [t] = ifaces;
280         }
281
282         //
283         // This entry point is used by types that we define under the covers
284         // 
285         public static void RegisterBuilder (TypeBuilder tb, Type [] ifaces)
286         {
287                 if (ifaces != null)
288                         builder_to_ifaces [tb] = ifaces;
289         }
290         
291         public static void AddUserType (string name, TypeBuilder t, TypeContainer tc, Type [] ifaces)
292         {
293                 builder_to_container.Add (t, tc);
294                 typecontainers.Add (name, tc);
295                 AddUserType (name, t, ifaces);
296         }
297
298         public static void AddDelegateType (string name, TypeBuilder t, Delegate del)
299         {
300                 types.Add (name, t);
301                 builder_to_delegate.Add (t, del);
302         }
303         
304         public static void AddEnumType (string name, TypeBuilder t, Enum en)
305         {
306                 types.Add (name, t);
307                 builder_to_enum.Add (t, en);
308         }
309
310         public static void AddUserInterface (string name, TypeBuilder t, Interface i, Type [] ifaces)
311         {
312                 AddUserType (name, t, ifaces);
313                 builder_to_interface.Add (t, i);
314         }
315
316         public static void RegisterAttrType (Type t, TypeContainer tc)
317         {
318                 builder_to_attr.Add (t, tc);
319         }
320                 
321         /// <summary>
322         ///   Returns the TypeContainer whose Type is `t' or null if there is no
323         ///   TypeContainer for `t' (ie, the Type comes from a library)
324         /// </summary>
325         public static TypeContainer LookupTypeContainer (Type t)
326         {
327                 return (TypeContainer) builder_to_container [t];
328         }
329
330         public static Interface LookupInterface (Type t)
331         {
332                 return (Interface) builder_to_interface [t];
333         }
334
335         public static Delegate LookupDelegate (Type t)
336         {
337                 return (Delegate) builder_to_delegate [t];
338         }
339
340         public static Enum LookupEnum (Type t)
341         {
342                 return (Enum) builder_to_enum [t];
343         }
344         
345         public static TypeContainer LookupAttr (Type t)
346         {
347                 return (TypeContainer) builder_to_attr [t];
348         }
349         
350         /// <summary>
351         ///   Registers an assembly to load types from.
352         /// </summary>
353         public static void AddAssembly (Assembly a)
354         {
355                 int top = assemblies.Length;
356                 Assembly [] n = new Assembly [top + 1];
357
358                 assemblies.CopyTo (n, 0);
359                 
360                 n [top] = a;
361                 assemblies = n;
362         }
363
364         /// <summary>
365         ///  Registers a module builder to lookup types from
366         /// </summary>
367         public static void AddModule (ModuleBuilder mb)
368         {
369                 int top = modules != null ? modules.Length : 0;
370                 ModuleBuilder [] n = new ModuleBuilder [top + 1];
371
372                 if (modules != null)
373                         modules.CopyTo (n, 0);
374                 n [top] = mb;
375                 modules = n;
376         }
377
378         /// <summary>
379         ///   Returns the Type associated with @name
380         /// </summary>
381         public static Type LookupType (string name)
382         {
383                 Type t;
384
385                 //
386                 // First lookup in user defined and cached values
387                 //
388
389                 t = (Type) types [name];
390                 if (t != null)
391                         return t;
392
393                 foreach (Assembly a in assemblies){
394                         t = a.GetType (name);
395                         if (t != null){
396                                 types [name] = t;
397
398                                 return t;
399                         }
400                 }
401
402                 foreach (ModuleBuilder mb in modules) {
403                         t = mb.GetType (name);
404                         if (t != null) {
405                                 types [name] = t;
406                                 return t;
407                         }
408                 }
409                 
410                 return null;
411         }
412
413         /// <summary>
414         ///   Returns the C# name of a type if possible, or the full type name otherwise
415         /// </summary>
416         static public string CSharpName (Type t)
417         {
418                 return Regex.Replace (t.FullName, 
419                         @"^System\." +
420                         @"(Int32|UInt32|Int16|Uint16|Int64|UInt64|" +
421                         @"Single|Double|Char|Decimal|Byte|SByte|Object|" +
422                         @"Boolean|String|Void)" +
423                         @"(\W+|\b)", 
424                         new MatchEvaluator (CSharpNameMatch));
425         }       
426         
427         static String CSharpNameMatch (Match match) 
428         {
429                 string s = match.Groups [1].Captures [0].Value;
430                 return s.ToLower ().
431                 Replace ("int32", "int").
432                 Replace ("uint32", "uint").
433                 Replace ("int16", "short").
434                 Replace ("uint16", "ushort").
435                 Replace ("int64", "long").
436                 Replace ("uint64", "ulong").
437                 Replace ("single", "float").
438                 Replace ("boolean", "bool")
439                 + match.Groups [2].Captures [0].Value;
440         }
441
442         /// <summary>
443         ///   Returns the signature of the method
444         /// </summary>
445         static public string CSharpSignature (MethodBase mb)
446         {
447                 string sig = "(";
448
449                 //
450                 // FIXME: We should really have a single function to do
451                 // everything instead of the following 5 line pattern
452                 //
453                 ParameterData iparams = LookupParametersByBuilder (mb);
454
455                 if (iparams == null){
456                         ParameterInfo [] pi = mb.GetParameters ();
457                         iparams = new ReflectionParameters (pi);
458                 }
459                 
460                 for (int i = 0; i < iparams.Count; i++) {
461                         if (i > 0) {
462                                 sig += ", ";
463                         }
464                         sig += iparams.ParameterDesc(i);
465                 }
466                 sig += ")";
467
468                 return mb.DeclaringType.Name + "." + mb.Name + sig;
469         }
470
471         /// <summary>
472         ///   Looks up a type, and aborts if it is not found.  This is used
473         ///   by types required by the compiler
474         /// </summary>
475         static Type CoreLookupType (string name)
476         {
477                 Type t = LookupType (name);
478
479                 if (t == null){
480                         Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
481                         Environment.Exit (0);
482                 }
483
484                 return t;
485         }
486
487         /// <summary>
488         ///   Returns the MethodInfo for a method named `name' defined
489         ///   in type `t' which takes arguments of types `args'
490         /// </summary>
491         static MethodInfo GetMethod (Type t, string name, Type [] args)
492         {
493                 MemberInfo [] mi;
494                 Signature sig;
495
496                 sig.name = name;
497                 sig.args = args;
498                 
499                 mi = FindMembers (
500                         t, MemberTypes.Method,
501                         instance_and_static | BindingFlags.Public, signature_filter, sig);
502                 if (mi == null || mi.Length == 0 || !(mi [0] is MethodInfo)){
503                         Report.Error (-19, "Can not find the core function `" + name + "'");
504                         return null;
505                 }
506
507                 return (MethodInfo) mi [0];
508         }
509
510         /// <summary>
511         ///    Returns the ConstructorInfo for "args"
512         /// </summary>
513         static ConstructorInfo GetConstructor (Type t, Type [] args)
514         {
515                 MemberInfo [] mi;
516                 Signature sig;
517
518                 sig.name = ".ctor";
519                 sig.args = args;
520                 
521                 mi = FindMembers (t, MemberTypes.Constructor,
522                                   instance_and_static | BindingFlags.Public, signature_filter, sig);
523                 if (mi == null || mi.Length == 0 || !(mi [0] is ConstructorInfo)){
524                         Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
525                         return null;
526                 }
527
528                 return (ConstructorInfo) mi [0];
529         }
530
531         public static void InitEnumUnderlyingTypes ()
532         {
533
534                 int32_type    = CoreLookupType ("System.Int32");
535                 int64_type    = CoreLookupType ("System.Int64");
536                 uint32_type   = CoreLookupType ("System.UInt32"); 
537                 uint64_type   = CoreLookupType ("System.UInt64"); 
538                 byte_type     = CoreLookupType ("System.Byte");
539                 sbyte_type    = CoreLookupType ("System.SByte");
540                 short_type    = CoreLookupType ("System.Int16");
541                 ushort_type   = CoreLookupType ("System.UInt16");
542         }
543         
544         /// <remarks>
545         ///   The types have to be initialized after the initial
546         ///   population of the type has happened (for example, to
547         ///   bootstrap the corlib.dll
548         /// </remarks>
549         public static void InitCoreTypes ()
550         {
551                 object_type   = CoreLookupType ("System.Object");
552                 value_type    = CoreLookupType ("System.ValueType");
553
554                 InitEnumUnderlyingTypes ();
555
556                 char_type     = CoreLookupType ("System.Char");
557                 string_type   = CoreLookupType ("System.String");
558                 float_type    = CoreLookupType ("System.Single");
559                 double_type   = CoreLookupType ("System.Double");
560                 char_ptr_type = CoreLookupType ("System.Char*");
561                 decimal_type  = CoreLookupType ("System.Decimal");
562                 bool_type     = CoreLookupType ("System.Boolean");
563                 enum_type     = CoreLookupType ("System.Enum");
564
565                 multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
566                 delegate_type           = CoreLookupType ("System.Delegate");
567
568                 array_type    = CoreLookupType ("System.Array");
569                 void_type     = CoreLookupType ("System.Void");
570                 type_type     = CoreLookupType ("System.Type");
571
572                 runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
573                 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
574                 default_member_type  = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
575                 runtime_handle_type  = CoreLookupType ("System.RuntimeTypeHandle");
576                 asynccallback_type   = CoreLookupType ("System.AsyncCallback");
577                 iasyncresult_type    = CoreLookupType ("System.IAsyncResult");
578                 ienumerator_type     = CoreLookupType ("System.Collections.IEnumerator");
579                 idisposable_type     = CoreLookupType ("System.IDisposable");
580                 icloneable_type      = CoreLookupType ("System.ICloneable");
581                 monitor_type         = CoreLookupType ("System.Threading.Monitor");
582                 intptr_type          = CoreLookupType ("System.IntPtr");
583
584                 attribute_type       = CoreLookupType ("System.Attribute");
585                 attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
586                 dllimport_type       = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute");
587                 methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute");
588                 marshal_as_attr_type  = CoreLookupType ("System.Runtime.InteropServices.MarshalAsAttribute");
589                 param_array_type      = CoreLookupType ("System.ParamArrayAttribute");
590
591                 unverifiable_code_type= CoreLookupType ("System.Security.UnverifiableCodeAttribute");
592
593                 void_ptr_type         = CoreLookupType ("System.Void*");
594
595                 indexer_name_type     = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute");
596                 trace_type            = CoreLookupType ("System.Diagnostics.Trace");
597                 debug_type            = CoreLookupType ("System.Diagnostics.Debug");
598         }
599
600         //
601         // The helper methods that are used by the compiler
602         //
603         public static void InitCodeHelpers ()
604         {
605                 //
606                 // Now load the default methods that we use.
607                 //
608                 Type [] string_string = { string_type, string_type };
609                 string_concat_string_string = GetMethod (
610                         string_type, "Concat", string_string);
611
612                 Type [] object_object = { object_type, object_type };
613                 string_concat_object_object = GetMethod (
614                         string_type, "Concat", object_object);
615
616                 Type [] string_ = { string_type };
617                 string_isinterneted_string = GetMethod (
618                         string_type, "IsInterned", string_);
619                 
620                 Type [] runtime_type_handle = { runtime_handle_type };
621                 system_type_get_type_from_handle = GetMethod (
622                         type_type, "GetTypeFromHandle", runtime_type_handle);
623
624                 Type [] delegate_delegate = { delegate_type, delegate_type };
625                 delegate_combine_delegate_delegate = GetMethod (
626                                 delegate_type, "Combine", delegate_delegate);
627
628                 delegate_remove_delegate_delegate = GetMethod (
629                                 delegate_type, "Remove", delegate_delegate);
630
631                 //
632                 // Void arguments
633                 //
634                 Type [] void_arg = {  };
635                 object_getcurrent_void = GetMethod (
636                         ienumerator_type, "get_Current", void_arg);
637                 bool_movenext_void = GetMethod (
638                         ienumerator_type, "MoveNext", void_arg);
639                 void_dispose_void = GetMethod (
640                         idisposable_type, "Dispose", void_arg);
641                 int_get_offset_to_string_data = GetMethod (
642                         runtime_helpers_type, "get_OffsetToStringData", void_arg);
643                 int_array_get_length = GetMethod (
644                         array_type, "get_Length", void_arg);
645                 
646                 //
647                 // object arguments
648                 //
649                 Type [] object_arg = { object_type };
650                 void_monitor_enter_object = GetMethod (
651                         monitor_type, "Enter", object_arg);
652                 void_monitor_exit_object = GetMethod (
653                         monitor_type, "Exit", object_arg);
654
655                 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
656                 
657                 void_initializearray_array_fieldhandle = GetMethod (
658                         runtime_helpers_type, "InitializeArray", array_field_handle_arg);
659
660                 //
661                 // Array functions
662                 //
663                 Type [] int_arg = { int32_type };
664                 int_getlength_int = GetMethod (
665                         array_type, "GetLength", int_arg);
666
667                 //
668                 // Decimal constructors
669                 //
670                 Type [] dec_arg = { int32_type, int32_type, int32_type, bool_type, byte_type };
671                 void_decimal_ctor_five_args = GetConstructor (
672                         decimal_type, dec_arg);
673                 
674                 //
675                 // Attributes
676                 //
677                 cons_param_array_attribute = GetConstructor (
678                         param_array_type, void_arg);
679                 
680         }
681
682         const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
683
684         //
685         // FIXME: This can be optimized easily.  speedup by having a single builder mapping
686         //
687         public static MemberInfo [] FindMembers (Type t, MemberTypes mt, BindingFlags bf,
688                                                  MemberFilter filter, object criteria)
689         {
690                 //
691                 // We have to take care of arrays specially, because GetType on
692                 // a TypeBuilder array will return a Type, not a TypeBuilder,
693                 // and we can not call FindMembers on this type.
694                 //
695                 if (t.IsSubclassOf (TypeManager.array_type))
696                         return TypeManager.array_type.FindMembers (mt, bf, filter, criteria);
697                 
698                 if (!(t is TypeBuilder)){
699                         //
700                         // Since FindMembers will not lookup both static and instance
701                         // members, we emulate this behaviour here.
702                         //
703                         if ((bf & instance_and_static) == instance_and_static){
704                                 MemberInfo [] i_members = t.FindMembers (
705                                         mt, bf & ~BindingFlags.Static, filter, criteria);
706
707                                 int i_len = i_members.Length;
708                                 if (i_len == 1){
709                                         MemberInfo one = i_members [0];
710
711                                         //
712                                         // If any of these are present, we are done!
713                                         //
714                                         if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
715                                                 return i_members;
716                                 }
717                                 
718                                 MemberInfo [] s_members = t.FindMembers (
719                                         mt, bf & ~BindingFlags.Instance, filter, criteria);
720
721                                 int s_len = s_members.Length;
722                                 if (i_len > 0 || s_len > 0){
723                                         MemberInfo [] both = new MemberInfo [i_len + s_len];
724
725                                         i_members.CopyTo (both, 0);
726                                         s_members.CopyTo (both, i_len);
727
728                                         return both;
729                                 } else {
730                                         if (i_len > 0)
731                                                 return i_members;
732                                         else
733                                                 return s_members;
734                                 }
735                         }
736                         return t.FindMembers (mt, bf, filter, criteria);
737                 }
738
739                 //
740                 // FIXME: We should not have builder_to_blah everywhere,
741                 // we should just have a builder_to_findmemberizable
742                 // and have them implement a new ICanFindMembers interface
743                 //
744                 Enum e = (Enum) builder_to_enum [t];
745
746                 if (e != null)
747                         return e.FindMembers (mt, bf, filter, criteria);
748                 
749                 Delegate del = (Delegate) builder_to_delegate [t];
750
751                 if (del != null)
752                         return del.FindMembers (mt, bf, filter, criteria);
753
754                 Interface iface = (Interface) builder_to_interface [t];
755
756                 if (iface != null) 
757                         return iface.FindMembers (mt, bf, filter, criteria);
758                 
759                 TypeContainer tc = (TypeContainer) builder_to_container [t];
760
761                 if (tc != null)
762                         return tc.FindMembers (mt, bf, filter, criteria);
763
764                 return null;
765         }
766
767         public static bool IsBuiltinType (Type t)
768         {
769                 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
770                     t == int64_type || t == uint64_type || t == float_type || t == double_type ||
771                     t == char_type || t == short_type || t == decimal_type || t == bool_type ||
772                     t == sbyte_type || t == byte_type || t == ushort_type)
773                         return true;
774                 else
775                         return false;
776         }
777
778         public static bool IsDelegateType (Type t)
779         {
780                 if (t.IsSubclassOf (TypeManager.delegate_type))
781                         return true;
782                 else
783                         return false;
784         }
785         
786         public static bool IsEnumType (Type t)
787         {
788                 if (t.IsSubclassOf (TypeManager.enum_type))
789                         return true;
790                 else
791                         return false;
792         }
793         
794         public static bool IsInterfaceType (Type t)
795         {
796                 Interface iface = (Interface) builder_to_interface [t];
797
798                 if (iface != null)
799                         return true;
800                 else
801                         return false;
802         }
803
804         /// <summary>
805         ///   Returns the User Defined Types
806         /// </summary>
807         public static ArrayList UserTypes {
808                 get {
809                         return user_types;
810                 }
811         }
812
813         public static Hashtable TypeContainers {
814                 get {
815                         return typecontainers;
816                 }
817         }
818
819         static Hashtable builder_to_constant;
820
821         public static void RegisterConstant (FieldBuilder fb, Const c)
822         {
823                 if (builder_to_constant == null)
824                         builder_to_constant = new PtrHashtable ();
825
826                 if (builder_to_constant.Contains (fb))
827                         return;
828
829                 builder_to_constant.Add (fb, c);
830         }
831
832         public static Const LookupConstant (FieldBuilder fb)
833         {
834                 if (builder_to_constant == null)
835                         return null;
836                 
837                 return (Const) builder_to_constant [fb];
838         }
839         
840         /// <summary>
841         ///   Gigantic work around for missing features in System.Reflection.Emit follows.
842         /// </summary>
843         ///
844         /// <remarks>
845         ///   Since System.Reflection.Emit can not return MethodBase.GetParameters
846         ///   for anything which is dynamic, and we need this in a number of places,
847         ///   we register this information here, and use it afterwards.
848         /// </remarks>
849         static public bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
850         {
851                 if (args == null)
852                         args = NoTypes;
853                                 
854                 method_arguments.Add (mb, args);
855                 method_internal_params.Add (mb, ip);
856                 
857                 return true;
858         }
859         
860         static public InternalParameters LookupParametersByBuilder (MethodBase mb)
861         {
862                 if (! (mb is ConstructorBuilder || mb is MethodBuilder))
863                         return null;
864                 
865                 if (method_internal_params.Contains (mb))
866                         return (InternalParameters) method_internal_params [mb];
867                 else
868                         throw new Exception ("Argument for Method not registered" + mb);
869         }
870
871         /// <summary>
872         ///    Returns the argument types for a method based on its methodbase
873         ///
874         ///    For dynamic methods, we use the compiler provided types, for
875         ///    methods from existing assemblies we load them from GetParameters,
876         ///    and insert them into the cache
877         /// </summary>
878         static public Type [] GetArgumentTypes (MethodBase mb)
879         {
880                 if (method_arguments.Contains (mb))
881                         return (Type []) method_arguments [mb];
882                 else {
883                         ParameterInfo [] pi = mb.GetParameters ();
884                         int c = pi.Length;
885                         Type [] types = new Type [c];
886                         
887                         for (int i = 0; i < c; i++)
888                                 types [i] = pi [i].ParameterType;
889
890                         method_arguments.Add (mb, types);
891                         return types;
892                 }
893         }
894         
895         // <remarks>
896         //  This is a workaround the fact that GetValue is not
897         //  supported for dynamic types
898         // </remarks>
899         static Hashtable fields = new Hashtable ();
900         static public bool RegisterFieldValue (FieldBuilder fb, object value)
901         {
902                 if (fields.Contains (fb))
903                         return false;
904
905                 fields.Add (fb, value);
906
907                 return true;
908         }
909
910         static public object GetValue (FieldBuilder fb)
911         {
912                 return fields [fb];
913         }
914
915         static Hashtable fieldbuilders_to_fields = new Hashtable ();
916         static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f)
917         {
918                 if (fieldbuilders_to_fields.Contains (fb))
919                         return false;
920
921                 fieldbuilders_to_fields.Add (fb, f);
922                 return true;
923         }
924
925         static public FieldBase GetField (FieldInfo fb)
926         {
927                 return (FieldBase) fieldbuilders_to_fields [fb];
928         }
929         
930         static Hashtable events;
931
932         static public bool RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
933         {
934                 if (events == null)
935                         events = new Hashtable ();
936
937                 if (events.Contains (eb))
938                         return false;
939
940                 events.Add (eb, new Pair (add, remove));
941
942                 return true;
943         }
944
945         static public MethodInfo GetAddMethod (EventInfo ei)
946         {
947                 if (ei is MyEventBuilder) {
948                         Pair pair = (Pair) events [ei];
949
950                         return (MethodInfo) pair.First;
951                 } else
952                         return ei.GetAddMethod ();
953         }
954
955         static public MethodInfo GetRemoveMethod (EventInfo ei)
956         {
957                 if (ei is MyEventBuilder) {
958                         Pair pair = (Pair) events [ei];
959
960                         return (MethodInfo) pair.Second;
961                 } else
962                         return ei.GetAddMethod ();
963         }
964
965         static Hashtable properties;
966         
967         static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
968         {
969                 if (properties == null)
970                         properties = new Hashtable ();
971
972                 if (properties.Contains (pb))
973                         return false;
974
975                 properties.Add (pb, new Pair (get, set));
976
977                 return true;
978         }
979         
980         //
981         // FIXME: we need to return the accessors depending on whether
982         // they are visible or not.
983         //
984         static public MethodInfo [] GetAccessors (PropertyInfo pi)
985         {
986                 MethodInfo [] ret;
987
988                 if (pi is PropertyBuilder){
989                         Pair pair = (Pair) properties [pi];
990
991                         ret = new MethodInfo [2];
992                         ret [0] = (MethodInfo) pair.First;
993                         ret [1] = (MethodInfo) pair.Second;
994
995                         return ret;
996                 } else {
997                         MethodInfo [] mi = new MethodInfo [2];
998
999                         //
1000                         // Why this and not pi.GetAccessors?
1001                         // Because sometimes index 0 is the getter
1002                         // sometimes it is 1
1003                         //
1004                         mi [0] = pi.GetGetMethod (true);
1005                         mi [1] = pi.GetSetMethod (true);
1006
1007                         return mi;
1008                 }
1009         }
1010
1011         static public MethodInfo GetPropertyGetter (PropertyInfo pi)
1012         {
1013                 if (pi is PropertyBuilder){
1014                         Pair de = (Pair) properties [pi];
1015
1016                         return (MethodInfo) de.Second;
1017                 } else
1018                         return pi.GetSetMethod ();
1019         }
1020
1021         static public MethodInfo GetPropertySetter (PropertyInfo pi)
1022         {
1023                 if (pi is PropertyBuilder){
1024                         Pair de = (Pair) properties [pi];
1025
1026                         return (MethodInfo) de.First;
1027                 } else
1028                         return pi.GetGetMethod ();
1029         }
1030
1031         /// <summary>
1032         ///   This function returns the interfaces in the type `t'.  Works with
1033         ///   both types and TypeBuilders.
1034         /// </summary>
1035         public static Type [] GetInterfaces (Type t)
1036         {
1037                 //
1038                 // The reason for catching the Array case is that Reflection.Emit
1039                 // will not return a TypeBuilder for Array types of TypeBuilder types,
1040                 // but will still throw an exception if we try to call GetInterfaces
1041                 // on the type.
1042                 //
1043                 // Since the array interfaces are always constant, we return those for
1044                 // the System.Array
1045                 //
1046                 
1047                 if (t.IsArray)
1048                         t = TypeManager.array_type;
1049                 
1050                 if (t is TypeBuilder)
1051                         return (Type []) builder_to_ifaces [t];
1052                 else
1053                         return t.GetInterfaces ();
1054         }
1055         
1056         /// <remarks>
1057         ///  The following is used to check if a given type implements an interface.
1058         ///  The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
1059         /// </remarks>
1060         public static bool ImplementsInterface (Type t, Type iface)
1061         {
1062                 Type [] interfaces;
1063
1064                 //
1065                 // FIXME OPTIMIZATION:
1066                 // as soon as we hit a non-TypeBuiler in the interface
1067                 // chain, we could return, as the `Type.GetInterfaces'
1068                 // will return all the interfaces implement by the type
1069                 // or its parents.
1070                 //
1071                 do {
1072                         interfaces = GetInterfaces (t);
1073
1074                         if (interfaces != null){
1075                                 foreach (Type i in interfaces){
1076                                         if (i == iface)
1077                                                 return true;
1078                                 }
1079                         }
1080                         
1081                         t = t.BaseType;
1082                 } while (t != null);
1083                 
1084                 return false;
1085         }
1086
1087         //
1088         // This is needed, because enumerations from assemblies
1089         // do not report their underlyingtype, but they report
1090         // themselves
1091         //
1092         public static Type EnumToUnderlying (Type t)
1093         {
1094                 t = t.UnderlyingSystemType;
1095                 if (!TypeManager.IsEnumType (t))
1096                         return t;
1097                 
1098                 TypeCode tc = Type.GetTypeCode (t);
1099
1100                 switch (tc){
1101                 case TypeCode.Boolean:
1102                         return TypeManager.bool_type;
1103                 case TypeCode.Byte:
1104                         return TypeManager.byte_type;
1105                 case TypeCode.SByte:
1106                         return TypeManager.sbyte_type;
1107                 case TypeCode.Char:
1108                         return TypeManager.char_type;
1109                 case TypeCode.Int16:
1110                         return TypeManager.short_type;
1111                 case TypeCode.UInt16:
1112                         return TypeManager.ushort_type;
1113                 case TypeCode.Int32:
1114                         return TypeManager.int32_type;
1115                 case TypeCode.UInt32:
1116                         return TypeManager.uint32_type;
1117                 case TypeCode.Int64:
1118                         return TypeManager.int64_type;
1119                 case TypeCode.UInt64:
1120                         return TypeManager.uint64_type;
1121                 }
1122                 throw new Exception ("Unhandled typecode in enum" + tc);
1123         }
1124
1125         /// <summary>
1126         ///   Utility function that can be used to probe whether a type
1127         ///   is managed or not.  
1128         /// </summary>
1129         public static bool VerifyUnManaged (Type t, Location loc)
1130         {
1131                 if (t.IsValueType){
1132                         //
1133                         // FIXME: this is more complex, we actually need to
1134                         // make sure that the type does not contain any
1135                         // classes itself
1136                         //
1137                         return true;
1138                 }
1139
1140                 Report.Error (
1141                         208, loc,
1142                         "Cannot take the address or size of a variable of a managed type ('" +
1143                         CSharpName (t) + "')");
1144                 return false;   
1145         }
1146         
1147         /// <summary>
1148         ///   Returns the name of the indexer in a given type.
1149         /// </summary>
1150         /// <remarks>
1151         ///   The default is not always `Item'.  The user can change this behaviour by
1152         ///   using the DefaultMemberAttribute in the class.
1153         ///
1154         ///   For example, the String class indexer is named `Chars' not `Item' 
1155         /// </remarks>
1156         public static string IndexerPropertyName (Type t)
1157         {
1158                 
1159                 if (t is TypeBuilder) {
1160                         TypeContainer tc = (TypeContainer) builder_to_container [t];
1161
1162                         //
1163                         // FIXME: Temporary hack, until we deploy the IndexerName
1164                         // property code (and attributes) in the interface code.
1165                         //
1166                         if (tc == null){
1167                                 return "Item";
1168                         }
1169                         
1170                         return tc.IndexerName;
1171                 }
1172                 
1173                 System.Attribute attr = System.Attribute.GetCustomAttribute (
1174                         t, TypeManager.default_member_type);
1175                 if (attr != null){
1176                         DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
1177                         return dma.MemberName;
1178                 }
1179
1180                 return "Item";
1181         }
1182
1183         public static void MakePinned (LocalBuilder builder)
1184         {
1185                 //
1186                 // FIXME: Flag the "LocalBuilder" type as being
1187                 // pinned.  Figure out API.
1188                 //
1189         }
1190
1191
1192         //
1193         // Returns whether the array of memberinfos contains the given method
1194         //
1195         static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method)
1196         {
1197                 Type [] new_args = TypeManager.GetArgumentTypes (new_method);
1198                 
1199                 foreach (MethodBase method in array){
1200                         if (method.Name != new_method.Name)
1201                                 continue;
1202                         
1203                         Type [] old_args = TypeManager.GetArgumentTypes (method);
1204                         int old_count = old_args.Length;
1205                         int i;
1206                         
1207                         if (new_args.Length != old_count)
1208                                 continue;
1209                         
1210                         for (i = 0; i < old_count; i++){
1211                                 if (old_args [i] != new_args [i])
1212                                         break;
1213                         }
1214                         if (i != old_count)
1215                                 continue;
1216                         
1217                         if (!(method is MethodInfo && new_method is MethodInfo))
1218                                 return true;
1219                         
1220                         if (((MethodInfo) method).ReturnType == ((MethodInfo) new_method).ReturnType)
1221                                 return true;
1222                 }
1223                 return false;
1224         }
1225         
1226         //
1227         // We copy methods from `new_members' into `target_list' if the signature
1228         // for the method from in the new list does not exist in the target_list
1229         //
1230         // The name is assumed to be the same.
1231         //
1232         public static ArrayList CopyNewMethods (ArrayList target_list, MemberInfo [] new_members)
1233         {
1234                 if (target_list == null){
1235                         target_list = new ArrayList ();
1236
1237                         foreach (MemberInfo mi in new_members){
1238                                 if (mi is MethodBase)
1239                                         target_list.Add (mi);
1240                         }
1241                         return target_list;
1242                 }
1243                 
1244                 MemberInfo [] target_array = new MemberInfo [target_list.Count];
1245                 target_list.CopyTo (target_array, 0);
1246                 
1247                 foreach (MemberInfo mi in new_members){
1248                         MethodBase new_method = (MethodBase) mi;
1249                         
1250                         if (!ArrayContainsMethod (target_array, new_method))
1251                                 target_list.Add (new_method);
1252                 }
1253                 return target_list;
1254         }
1255
1256 #region MemberLookup implementation
1257         
1258         //
1259         // Name of the member
1260         //
1261         static string   closure_name;
1262
1263         //
1264         // Whether we allow private members in the result (since FindMembers
1265         // uses NonPublic for both protected and private), we need to distinguish.
1266         //
1267         static bool     closure_private_ok;
1268
1269         //
1270         // Who is invoking us and which type is being queried currently.
1271         //
1272         static Type     closure_invocation_type;
1273         static Type     closure_queried_type;
1274
1275         //
1276         // The assembly that defines the type is that is calling us
1277         //
1278         static Assembly closure_invocation_assembly;
1279
1280         //
1281         // This filter filters by name + whether it is ok to include private
1282         // members in the search
1283         //
1284         static internal bool FilterWithClosure (MemberInfo m, object filter_criteria)
1285         {
1286                 //
1287                 // Hack: we know that the filter criteria will always be in the `closure'
1288                 // fields. 
1289                 //
1290
1291                 if (m.Name != closure_name)
1292                         return false;
1293
1294                 //
1295                 // Ugly: we need to find out the type of `m', and depending
1296                 // on this, tell whether we accept or not
1297                 //
1298                 if (m is MethodBase){
1299                         MethodBase mb = (MethodBase) m;
1300                         MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
1301
1302                         if (ma == MethodAttributes.Private)
1303                                 return closure_private_ok;
1304
1305                         //
1306                         // FamAndAssem requires that we not only derivate, but we are on the
1307                         // same assembly.  
1308                         //
1309                         if (ma == MethodAttributes.FamANDAssem){
1310                                 if (closure_invocation_assembly != mb.DeclaringType.Assembly)
1311                                         return false;
1312                         }
1313
1314                         // FamORAssem, Family and Public:
1315                         return true;
1316                 }
1317
1318                 if (m is FieldInfo){
1319                         FieldInfo fi = (FieldInfo) m;
1320                         FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
1321
1322                         if (fa == FieldAttributes.Private)
1323                                 return closure_private_ok;
1324
1325                         //
1326                         // FamAndAssem requires that we not only derivate, but we are on the
1327                         // same assembly.  
1328                         //
1329                         if (fa == FieldAttributes.FamANDAssem){
1330                                 if (closure_invocation_assembly != fi.DeclaringType.Assembly)
1331                                         return false;
1332                         }
1333                         // FamORAssem, Family and Public:
1334                         return true;
1335                 }
1336
1337                 //
1338                 // EventInfos and PropertyInfos, return true
1339                 //
1340                 return true;
1341         }
1342
1343         static MemberFilter FilterWithClosure_delegate = new MemberFilter (FilterWithClosure);
1344         
1345         //
1346         // Looks up a member called `name' in the `queried_type'.  This lookup
1347         // is done by code that is contained in the definition for `invocation_type'.
1348         //
1349         // The binding flags are `bf' and the kind of members being looked up are `mt'
1350         //
1351         // Returns an array of a single element for everything but Methods/Constructors
1352         // that might return multiple matches.
1353         //
1354         public static MemberInfo [] MemberLookup (Type invocation_type, Type queried_type, 
1355                                                   MemberTypes mt, BindingFlags original_bf, string name)
1356         {
1357                 BindingFlags bf = original_bf;
1358                 
1359                 ArrayList method_list = null;
1360                 Type current_type = queried_type;
1361                 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
1362                 bool private_ok;
1363                 bool always_ok_flag = false;
1364
1365                 closure_name = name;
1366                 closure_invocation_type = invocation_type;
1367                 closure_invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
1368
1369                 //
1370                 // If we are a nested class, we always have access to our container
1371                 // type names
1372                 //
1373                 if (invocation_type != null){
1374                         string invocation_name = invocation_type.FullName;
1375                         if (invocation_name.IndexOf ('+') != -1){
1376                                 string container = queried_type.FullName + "+";
1377                                 int container_length = container.Length;
1378                                 
1379                                 if (invocation_name.Length > container_length){
1380                                         string shared = invocation_name.Substring (0, container_length);
1381                                 
1382                                         if (shared == container)
1383                                                 always_ok_flag = true;
1384                                 }
1385                         }
1386                 }
1387                 
1388                 do {
1389                         MemberInfo [] mi;
1390
1391                         //
1392                         // `NonPublic' is lame, because it includes both protected and
1393                         // private methods, so we need to control this behavior by
1394                         // explicitly tracking if a private method is ok or not.
1395                         //
1396                         // The possible cases are:
1397                         //    public, private and protected (internal does not come into the
1398                         //    equation)
1399                         //
1400                         if (invocation_type != null){
1401                                 if (invocation_type == current_type){
1402                                         private_ok = true;
1403                                 } else
1404                                         private_ok = always_ok_flag;
1405                                 
1406                                 if (private_ok || invocation_type.IsSubclassOf (current_type))
1407                                         bf = original_bf | BindingFlags.NonPublic;
1408                         } else {
1409                                 private_ok = false;
1410                                 bf = original_bf & ~BindingFlags.NonPublic;
1411                         }
1412
1413                         closure_private_ok = private_ok;
1414                         closure_queried_type = current_type;
1415                         
1416                         mi = TypeManager.FindMembers (
1417                                 current_type, mt, bf | BindingFlags.DeclaredOnly,
1418                                 FilterWithClosure_delegate, name);
1419                         
1420                         if (current_type == TypeManager.object_type)
1421                                 searching = false;
1422                         else {
1423                                 current_type = current_type.BaseType;
1424                                 
1425                                 //
1426                                 // This happens with interfaces, they have a null
1427                                 // basetype.  Look members up in the Object class.
1428                                 //
1429                                 if (current_type == null)
1430                                         current_type = TypeManager.object_type;
1431                         }
1432                         
1433                         if (mi == null)
1434                                 continue;
1435                         
1436                         int count = mi.Length;
1437                         
1438                         if (count == 0)
1439                                 continue;
1440                         
1441                         //
1442                         // Events and types are returned by both `static' and `instance'
1443                         // searches, which means that our above FindMembers will
1444                         // return two copies of the same.
1445                         //
1446                         if (count == 1 && !(mi [0] is MethodBase)){
1447                                 return mi;
1448                         }
1449
1450                         //
1451                         // Multiple properties: we query those just to find out the indexer
1452                         // name
1453                         //
1454                         if (mi [0] is PropertyInfo)
1455                                 return mi;
1456                         
1457                         //
1458                         // We found methods, turn the search into "method scan"
1459                         // mode.
1460                         //
1461                         
1462                         method_list = CopyNewMethods (method_list, mi);
1463                         mt &= (MemberTypes.Method | MemberTypes.Constructor);
1464                 } while (searching);
1465
1466                 if (method_list != null && method_list.Count > 0)
1467                         return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
1468         
1469                 //
1470                 // Interfaces do not list members they inherit, so we have to
1471                 // scan those.
1472                 // 
1473                 if (!queried_type.IsInterface)
1474                         return null;
1475
1476                 if (queried_type.IsArray)
1477                         queried_type = TypeManager.array_type;
1478                 
1479                 Type [] ifaces = GetInterfaces (queried_type);
1480                 if (ifaces == null)
1481                         return null;
1482                 
1483                 foreach (Type itype in ifaces){
1484                         MemberInfo [] x;
1485
1486                         x = MemberLookup (null, itype, mt, bf, name);
1487                         if (x != null)
1488                                 return x;
1489                 }
1490                                         
1491                 return null;
1492         }
1493 #endregion
1494         
1495 }
1496
1497 }