2 // typemanager.cs: C# type manager
4 // Author: Miguel de Icaza (miguel@gnu.org)
5 // Ravi Pratap (ravi@ximian.com)
7 // Licensed under the terms of the GNU GPL
9 // (C) 2001 Ximian, Inc (http://www.ximian.com)
15 using System.Globalization;
16 using System.Collections;
17 using System.Reflection;
18 using System.Reflection.Emit;
19 using System.Text.RegularExpressions;
20 using System.Runtime.CompilerServices;
21 using System.Diagnostics;
23 namespace Mono.CSharp {
25 public class TypeManager {
27 // A list of core types that the compiler requires or uses
29 static public Type object_type;
30 static public Type value_type;
31 static public Type string_type;
32 static public Type int32_type;
33 static public Type uint32_type;
34 static public Type int64_type;
35 static public Type uint64_type;
36 static public Type float_type;
37 static public Type double_type;
38 static public Type char_type;
39 static public Type char_ptr_type;
40 static public Type short_type;
41 static public Type decimal_type;
42 static public Type bool_type;
43 static public Type sbyte_type;
44 static public Type byte_type;
45 static public Type ushort_type;
46 static public Type enum_type;
47 static public Type delegate_type;
48 static public Type multicast_delegate_type;
49 static public Type void_type;
50 static public Type enumeration_type;
51 static public Type array_type;
52 static public Type runtime_handle_type;
53 static public Type icloneable_type;
54 static public Type type_type;
55 static public Type ienumerator_type;
56 static public Type idisposable_type;
57 static public Type default_member_type;
58 static public Type iasyncresult_type;
59 static public Type asynccallback_type;
60 static public Type intptr_type;
61 static public Type monitor_type;
62 static public Type runtime_field_handle_type;
63 static public Type attribute_type;
64 static public Type attribute_usage_type;
65 static public Type dllimport_type;
66 static public Type unverifiable_code_type;
67 static public Type methodimpl_attr_type;
68 static public Type marshal_as_attr_type;
69 static public Type param_array_type;
70 static public Type void_ptr_type;
71 static public Type indexer_name_type;
72 static public object obsolete_attribute_type;
73 static public object conditional_attribute_type;
75 static public Type [] NoTypes;
78 // This is only used when compiling corlib
80 static public Type system_int32_type;
81 static public Type system_array_type;
82 static public Type system_type_type;
83 static public Type system_assemblybuilder_type;
84 static public MethodInfo system_int_array_get_length;
85 static public MethodInfo system_int_array_get_rank;
86 static public MethodInfo system_object_array_clone;
87 static public MethodInfo system_int_array_get_length_int;
88 static public MethodInfo system_int_array_get_lower_bound_int;
89 static public MethodInfo system_int_array_get_upper_bound_int;
90 static public MethodInfo system_void_array_copyto_array_int;
91 static public MethodInfo system_void_set_corlib_type_builders;
95 // Internal, not really used outside
97 static Type runtime_helpers_type;
100 // These methods are called by code generated by the compiler
102 static public MethodInfo string_concat_string_string;
103 static public MethodInfo string_concat_object_object;
104 static public MethodInfo string_isinterneted_string;
105 static public MethodInfo system_type_get_type_from_handle;
106 static public MethodInfo object_getcurrent_void;
107 static public MethodInfo bool_movenext_void;
108 static public MethodInfo void_dispose_void;
109 static public MethodInfo void_monitor_enter_object;
110 static public MethodInfo void_monitor_exit_object;
111 static public MethodInfo void_initializearray_array_fieldhandle;
112 static public MethodInfo int_getlength_int;
113 static public MethodInfo delegate_combine_delegate_delegate;
114 static public MethodInfo delegate_remove_delegate_delegate;
115 static public MethodInfo int_get_offset_to_string_data;
116 static public MethodInfo int_array_get_length;
117 static public MethodInfo int_array_get_rank;
118 static public MethodInfo object_array_clone;
119 static public MethodInfo int_array_get_length_int;
120 static public MethodInfo int_array_get_lower_bound_int;
121 static public MethodInfo int_array_get_upper_bound_int;
122 static public MethodInfo void_array_copyto_array_int;
125 // The attribute constructors.
127 static public ConstructorInfo cons_param_array_attribute;
128 static public ConstructorInfo void_decimal_ctor_five_args;
129 static public ConstructorInfo unverifiable_code_ctor;
132 // Holds the Array of Assemblies that have been loaded
133 // (either because it is the default or the user used the
134 // -r command line option)
136 static Assembly [] assemblies;
139 // Keeps a list of module builders. We used this to do lookups
140 // on the modulebuilder using GetType -- needed for arrays
142 static ModuleBuilder [] modules;
145 // This is the type_cache from the assemblies to avoid
146 // hitting System.Reflection on every lookup.
148 static Hashtable types;
151 // This is used to hotld the corresponding TypeContainer objects
152 // since we need this in FindMembers
154 static Hashtable typecontainers;
157 // Keeps track of those types that are defined by the
160 static ArrayList user_types;
163 // Keeps a mapping between TypeBuilders and their TypeContainers
165 static PtrHashtable builder_to_container;
168 // Tracks the interfaces implemented by typebuilders. We only
169 // enter those who do implement or or more interfaces
171 static PtrHashtable builder_to_ifaces;
174 // Maps MethodBase.RuntimeTypeHandle to a Type array that contains
175 // the arguments to the method
177 static Hashtable method_arguments;
180 // Maybe `method_arguments' should be replaced and only
181 // method_internal_params should be kept?
183 static Hashtable method_internal_params;
185 static PtrHashtable builder_to_interface;
188 // Keeps track of delegate types
191 static Hashtable builder_to_delegate;
194 // Keeps track of enum types
197 static Hashtable builder_to_enum;
200 // Keeps track of attribute types
203 static Hashtable builder_to_attr;
211 /// A filter for Findmembers that uses the Signature object to
214 static bool SignatureFilter (MemberInfo mi, object criteria)
216 Signature sig = (Signature) criteria;
218 if (!(mi is MethodBase))
221 if (mi.Name != sig.name)
224 int count = sig.args.Length;
226 if (mi is MethodBuilder || mi is ConstructorBuilder){
227 Type [] candidate_args = GetArgumentTypes ((MethodBase) mi);
229 if (candidate_args.Length != count)
232 for (int i = 0; i < count; i++)
233 if (candidate_args [i] != sig.args [i])
238 ParameterInfo [] pars = ((MethodBase) mi).GetParameters ();
240 if (pars.Length != count)
243 for (int i = 0; i < count; i++)
244 if (pars [i].ParameterType != sig.args [i])
250 // A delegate that points to the filter above.
251 static MemberFilter signature_filter;
253 static TypeManager ()
255 assemblies = new Assembly [0];
257 user_types = new ArrayList ();
259 types = new Hashtable ();
260 typecontainers = new Hashtable ();
262 builder_to_interface = new PtrHashtable ();
263 builder_to_delegate = new PtrHashtable ();
264 builder_to_enum = new PtrHashtable ();
265 builder_to_attr = new PtrHashtable ();
266 method_arguments = new PtrHashtable ();
267 method_internal_params = new PtrHashtable ();
268 builder_to_container = new PtrHashtable ();
269 builder_to_ifaces = new PtrHashtable ();
271 NoTypes = new Type [0];
273 signature_filter = new MemberFilter (SignatureFilter);
276 public static void AddUserType (string name, TypeBuilder t, Type [] ifaces)
281 Type prev = (Type) types [name];
282 TypeContainer tc = (TypeContainer) builder_to_container [prev];
286 // This probably never happens, as we catch this before
288 Report.Error (-17, "The type `" + name + "' has already been defined.");
292 tc = (TypeContainer) builder_to_container [t];
295 1595, "The type `" + name + "' is defined in an existing assembly;"+
296 " Using the new definition from: " + tc.Location);
297 Report.Warning (1595, "Previously defined in: " + prev.Assembly.FullName);
305 builder_to_ifaces [t] = ifaces;
309 // This entry point is used by types that we define under the covers
311 public static void RegisterBuilder (TypeBuilder tb, Type [] ifaces)
314 builder_to_ifaces [tb] = ifaces;
317 public static void AddUserType (string name, TypeBuilder t, TypeContainer tc, Type [] ifaces)
319 builder_to_container.Add (t, tc);
320 typecontainers.Add (name, tc);
321 AddUserType (name, t, ifaces);
324 public static void AddDelegateType (string name, TypeBuilder t, Delegate del)
327 builder_to_delegate.Add (t, del);
330 public static void AddEnumType (string name, TypeBuilder t, Enum en)
333 builder_to_enum.Add (t, en);
336 public static void AddUserInterface (string name, TypeBuilder t, Interface i, Type [] ifaces)
338 AddUserType (name, t, ifaces);
339 builder_to_interface.Add (t, i);
342 public static void RegisterAttrType (Type t, TypeContainer tc)
344 builder_to_attr.Add (t, tc);
348 /// Returns the TypeContainer whose Type is `t' or null if there is no
349 /// TypeContainer for `t' (ie, the Type comes from a library)
351 public static TypeContainer LookupTypeContainer (Type t)
353 return (TypeContainer) builder_to_container [t];
356 public static Interface LookupInterface (Type t)
358 return (Interface) builder_to_interface [t];
361 public static Delegate LookupDelegate (Type t)
363 return (Delegate) builder_to_delegate [t];
366 public static Enum LookupEnum (Type t)
368 return (Enum) builder_to_enum [t];
371 public static TypeContainer LookupAttr (Type t)
373 return (TypeContainer) builder_to_attr [t];
377 /// Registers an assembly to load types from.
379 public static void AddAssembly (Assembly a)
381 int top = assemblies.Length;
382 Assembly [] n = new Assembly [top + 1];
384 assemblies.CopyTo (n, 0);
391 /// Registers a module builder to lookup types from
393 public static void AddModule (ModuleBuilder mb)
395 int top = modules != null ? modules.Length : 0;
396 ModuleBuilder [] n = new ModuleBuilder [top + 1];
399 modules.CopyTo (n, 0);
405 /// Returns the Type associated with @name
407 public static Type LookupType (string name)
412 // First lookup in user defined and cached values
415 t = (Type) types [name];
419 foreach (Assembly a in assemblies){
420 t = a.GetType (name);
428 foreach (ModuleBuilder mb in modules) {
429 t = mb.GetType (name);
440 /// Returns the C# name of a type if possible, or the full type name otherwise
442 static public string CSharpName (Type t)
444 return Regex.Replace (t.FullName,
446 @"(Int32|UInt32|Int16|Uint16|Int64|UInt64|" +
447 @"Single|Double|Char|Decimal|Byte|SByte|Object|" +
448 @"Boolean|String|Void)" +
450 new MatchEvaluator (CSharpNameMatch));
453 static String CSharpNameMatch (Match match)
455 string s = match.Groups [1].Captures [0].Value;
457 Replace ("int32", "int").
458 Replace ("uint32", "uint").
459 Replace ("int16", "short").
460 Replace ("uint16", "ushort").
461 Replace ("int64", "long").
462 Replace ("uint64", "ulong").
463 Replace ("single", "float").
464 Replace ("boolean", "bool")
465 + match.Groups [2].Captures [0].Value;
469 /// Returns the signature of the method
471 static public string CSharpSignature (MethodBase mb)
476 // FIXME: We should really have a single function to do
477 // everything instead of the following 5 line pattern
479 ParameterData iparams = LookupParametersByBuilder (mb);
481 if (iparams == null){
482 ParameterInfo [] pi = mb.GetParameters ();
483 iparams = new ReflectionParameters (pi);
486 for (int i = 0; i < iparams.Count; i++) {
490 sig += iparams.ParameterDesc(i);
494 return mb.DeclaringType.Name + "." + mb.Name + sig;
498 /// Looks up a type, and aborts if it is not found. This is used
499 /// by types required by the compiler
501 static Type CoreLookupType (string name)
503 Type t = LookupType (name);
506 Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
507 Environment.Exit (0);
514 /// Returns the MethodInfo for a method named `name' defined
515 /// in type `t' which takes arguments of types `args'
517 static MethodInfo GetMethod (Type t, string name, Type [] args)
526 t, MemberTypes.Method,
527 instance_and_static | BindingFlags.Public, signature_filter, sig);
528 if (mi == null || mi.Length == 0 || !(mi [0] is MethodInfo)){
529 Report.Error (-19, "Can not find the core function `" + name + "'");
533 return (MethodInfo) mi [0];
537 /// Returns the ConstructorInfo for "args"
539 static ConstructorInfo GetConstructor (Type t, Type [] args)
547 mi = FindMembers (t, MemberTypes.Constructor,
548 instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly, signature_filter, sig);
549 if (mi == null || mi.Length == 0 || !(mi [0] is ConstructorInfo)){
550 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
554 return (ConstructorInfo) mi [0];
557 public static void InitEnumUnderlyingTypes ()
560 int32_type = CoreLookupType ("System.Int32");
561 int64_type = CoreLookupType ("System.Int64");
562 uint32_type = CoreLookupType ("System.UInt32");
563 uint64_type = CoreLookupType ("System.UInt64");
564 byte_type = CoreLookupType ("System.Byte");
565 sbyte_type = CoreLookupType ("System.SByte");
566 short_type = CoreLookupType ("System.Int16");
567 ushort_type = CoreLookupType ("System.UInt16");
571 /// The types have to be initialized after the initial
572 /// population of the type has happened (for example, to
573 /// bootstrap the corlib.dll
575 public static void InitCoreTypes ()
577 object_type = CoreLookupType ("System.Object");
578 value_type = CoreLookupType ("System.ValueType");
580 InitEnumUnderlyingTypes ();
582 char_type = CoreLookupType ("System.Char");
583 string_type = CoreLookupType ("System.String");
584 float_type = CoreLookupType ("System.Single");
585 double_type = CoreLookupType ("System.Double");
586 char_ptr_type = CoreLookupType ("System.Char*");
587 decimal_type = CoreLookupType ("System.Decimal");
588 bool_type = CoreLookupType ("System.Boolean");
589 enum_type = CoreLookupType ("System.Enum");
591 multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
592 delegate_type = CoreLookupType ("System.Delegate");
594 array_type = CoreLookupType ("System.Array");
595 void_type = CoreLookupType ("System.Void");
596 type_type = CoreLookupType ("System.Type");
598 runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
599 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
600 default_member_type = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
601 runtime_handle_type = CoreLookupType ("System.RuntimeTypeHandle");
602 asynccallback_type = CoreLookupType ("System.AsyncCallback");
603 iasyncresult_type = CoreLookupType ("System.IAsyncResult");
604 ienumerator_type = CoreLookupType ("System.Collections.IEnumerator");
605 idisposable_type = CoreLookupType ("System.IDisposable");
606 icloneable_type = CoreLookupType ("System.ICloneable");
607 monitor_type = CoreLookupType ("System.Threading.Monitor");
608 intptr_type = CoreLookupType ("System.IntPtr");
610 attribute_type = CoreLookupType ("System.Attribute");
611 attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
612 dllimport_type = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute");
613 methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute");
614 marshal_as_attr_type = CoreLookupType ("System.Runtime.InteropServices.MarshalAsAttribute");
615 param_array_type = CoreLookupType ("System.ParamArrayAttribute");
617 unverifiable_code_type= CoreLookupType ("System.Security.UnverifiableCodeAttribute");
619 void_ptr_type = CoreLookupType ("System.Void*");
621 indexer_name_type = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute");
626 obsolete_attribute_type = CoreLookupType ("System.ObsoleteAttribute");
627 conditional_attribute_type = CoreLookupType ("System.Diagnostics.ConditionalAttribute");
630 // When compiling corlib, store the "real" types here.
632 if (!RootContext.StdLib) {
633 system_int32_type = typeof (System.Int32);
634 system_array_type = typeof (System.Array);
635 system_type_type = typeof (System.Type);
636 system_assemblybuilder_type = typeof (System.Reflection.Emit.AssemblyBuilder);
638 Type [] void_arg = { };
639 system_int_array_get_length = GetMethod (
640 system_array_type, "get_Length", void_arg);
641 system_int_array_get_rank = GetMethod (
642 system_array_type, "get_Rank", void_arg);
643 system_object_array_clone = GetMethod (
644 system_array_type, "Clone", void_arg);
646 Type [] system_int_arg = { system_int32_type };
647 system_int_array_get_length_int = GetMethod (
648 system_array_type, "GetLength", system_int_arg);
649 system_int_array_get_upper_bound_int = GetMethod (
650 system_array_type, "GetUpperBound", system_int_arg);
651 system_int_array_get_lower_bound_int = GetMethod (
652 system_array_type, "GetLowerBound", system_int_arg);
654 Type [] system_array_int_arg = { system_array_type, system_int32_type };
655 system_void_array_copyto_array_int = GetMethod (
656 system_array_type, "CopyTo", system_array_int_arg);
658 Type [] system_type_type_arg = { system_type_type, system_type_type, system_type_type };
659 system_void_set_corlib_type_builders = GetMethod (
660 system_assemblybuilder_type, "SetCorlibTypeBuilders",
661 system_type_type_arg);
663 object[] args = new object [3];
664 args [0] = object_type;
665 args [1] = value_type;
666 args [2] = enum_type;
668 system_void_set_corlib_type_builders.Invoke (CodeGen.AssemblyBuilder, args);
673 // The helper methods that are used by the compiler
675 public static void InitCodeHelpers ()
678 // Now load the default methods that we use.
680 Type [] string_string = { string_type, string_type };
681 string_concat_string_string = GetMethod (
682 string_type, "Concat", string_string);
684 Type [] object_object = { object_type, object_type };
685 string_concat_object_object = GetMethod (
686 string_type, "Concat", object_object);
688 Type [] string_ = { string_type };
689 string_isinterneted_string = GetMethod (
690 string_type, "IsInterned", string_);
692 Type [] runtime_type_handle = { runtime_handle_type };
693 system_type_get_type_from_handle = GetMethod (
694 type_type, "GetTypeFromHandle", runtime_type_handle);
696 Type [] delegate_delegate = { delegate_type, delegate_type };
697 delegate_combine_delegate_delegate = GetMethod (
698 delegate_type, "Combine", delegate_delegate);
700 delegate_remove_delegate_delegate = GetMethod (
701 delegate_type, "Remove", delegate_delegate);
706 Type [] void_arg = { };
707 object_getcurrent_void = GetMethod (
708 ienumerator_type, "get_Current", void_arg);
709 bool_movenext_void = GetMethod (
710 ienumerator_type, "MoveNext", void_arg);
711 void_dispose_void = GetMethod (
712 idisposable_type, "Dispose", void_arg);
713 int_get_offset_to_string_data = GetMethod (
714 runtime_helpers_type, "get_OffsetToStringData", void_arg);
715 int_array_get_length = GetMethod (
716 array_type, "get_Length", void_arg);
717 int_array_get_rank = GetMethod (
718 array_type, "get_Rank", void_arg);
723 Type [] int_arg = { int32_type };
724 int_array_get_length_int = GetMethod (
725 array_type, "GetLength", int_arg);
726 int_array_get_upper_bound_int = GetMethod (
727 array_type, "GetUpperBound", int_arg);
728 int_array_get_lower_bound_int = GetMethod (
729 array_type, "GetLowerBound", int_arg);
732 // System.Array methods
734 object_array_clone = GetMethod (
735 array_type, "Clone", void_arg);
736 Type [] array_int_arg = { array_type, int32_type };
737 void_array_copyto_array_int = GetMethod (
738 array_type, "CopyTo", array_int_arg);
743 Type [] object_arg = { object_type };
744 void_monitor_enter_object = GetMethod (
745 monitor_type, "Enter", object_arg);
746 void_monitor_exit_object = GetMethod (
747 monitor_type, "Exit", object_arg);
749 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
751 void_initializearray_array_fieldhandle = GetMethod (
752 runtime_helpers_type, "InitializeArray", array_field_handle_arg);
757 int_getlength_int = GetMethod (
758 array_type, "GetLength", int_arg);
761 // Decimal constructors
763 Type [] dec_arg = { int32_type, int32_type, int32_type, bool_type, byte_type };
764 void_decimal_ctor_five_args = GetConstructor (
765 decimal_type, dec_arg);
770 cons_param_array_attribute = GetConstructor (
771 param_array_type, void_arg);
773 unverifiable_code_ctor = GetConstructor (
774 unverifiable_code_type, void_arg);
778 const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
781 // FIXME: This can be optimized easily. speedup by having a single builder mapping
783 public static MemberInfo [] FindMembers (Type t, MemberTypes mt, BindingFlags bf,
784 MemberFilter filter, object criteria)
787 // We have to take care of arrays specially, because GetType on
788 // a TypeBuilder array will return a Type, not a TypeBuilder,
789 // and we can not call FindMembers on this type.
791 if (t.IsSubclassOf (TypeManager.array_type))
792 return TypeManager.array_type.FindMembers (mt, bf, filter, criteria);
794 if (!(t is TypeBuilder)){
796 // Since FindMembers will not lookup both static and instance
797 // members, we emulate this behaviour here.
799 if ((bf & instance_and_static) == instance_and_static){
800 MemberInfo [] i_members = t.FindMembers (
801 mt, bf & ~BindingFlags.Static, filter, criteria);
803 int i_len = i_members.Length;
805 MemberInfo one = i_members [0];
808 // If any of these are present, we are done!
810 if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
814 MemberInfo [] s_members = t.FindMembers (
815 mt, bf & ~BindingFlags.Instance, filter, criteria);
817 int s_len = s_members.Length;
818 if (i_len > 0 || s_len > 0){
819 MemberInfo [] both = new MemberInfo [i_len + s_len];
821 i_members.CopyTo (both, 0);
822 s_members.CopyTo (both, i_len);
832 return t.FindMembers (mt, bf, filter, criteria);
836 // FIXME: We should not have builder_to_blah everywhere,
837 // we should just have a builder_to_findmemberizable
838 // and have them implement a new ICanFindMembers interface
840 Enum e = (Enum) builder_to_enum [t];
843 return e.FindMembers (mt, bf, filter, criteria);
845 Delegate del = (Delegate) builder_to_delegate [t];
848 return del.FindMembers (mt, bf, filter, criteria);
850 Interface iface = (Interface) builder_to_interface [t];
853 return iface.FindMembers (mt, bf, filter, criteria);
855 TypeContainer tc = (TypeContainer) builder_to_container [t];
858 return tc.FindMembers (mt, bf, filter, criteria);
863 public static bool IsBuiltinType (Type t)
865 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
866 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
867 t == char_type || t == short_type || t == decimal_type || t == bool_type ||
868 t == sbyte_type || t == byte_type || t == ushort_type)
874 public static bool IsDelegateType (Type t)
876 if (t.IsSubclassOf (TypeManager.delegate_type))
882 public static bool IsEnumType (Type t)
884 if (t.IsSubclassOf (TypeManager.enum_type))
890 public static bool IsInterfaceType (Type t)
892 Interface iface = (Interface) builder_to_interface [t];
901 /// Returns the User Defined Types
903 public static ArrayList UserTypes {
909 public static Hashtable TypeContainers {
911 return typecontainers;
915 static Hashtable builder_to_constant;
917 public static void RegisterConstant (FieldBuilder fb, Const c)
919 if (builder_to_constant == null)
920 builder_to_constant = new PtrHashtable ();
922 if (builder_to_constant.Contains (fb))
925 builder_to_constant.Add (fb, c);
928 public static Const LookupConstant (FieldBuilder fb)
930 if (builder_to_constant == null)
933 return (Const) builder_to_constant [fb];
937 /// Gigantic work around for missing features in System.Reflection.Emit follows.
941 /// Since System.Reflection.Emit can not return MethodBase.GetParameters
942 /// for anything which is dynamic, and we need this in a number of places,
943 /// we register this information here, and use it afterwards.
945 static public bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
950 method_arguments.Add (mb, args);
951 method_internal_params.Add (mb, ip);
956 static public InternalParameters LookupParametersByBuilder (MethodBase mb)
958 if (! (mb is ConstructorBuilder || mb is MethodBuilder))
961 if (method_internal_params.Contains (mb))
962 return (InternalParameters) method_internal_params [mb];
964 throw new Exception ("Argument for Method not registered" + mb);
968 /// Returns the argument types for a method based on its methodbase
970 /// For dynamic methods, we use the compiler provided types, for
971 /// methods from existing assemblies we load them from GetParameters,
972 /// and insert them into the cache
974 static public Type [] GetArgumentTypes (MethodBase mb)
976 if (method_arguments.Contains (mb))
977 return (Type []) method_arguments [mb];
979 ParameterInfo [] pi = mb.GetParameters ();
981 Type [] types = new Type [c];
983 for (int i = 0; i < c; i++)
984 types [i] = pi [i].ParameterType;
986 method_arguments.Add (mb, types);
992 // This is a workaround the fact that GetValue is not
993 // supported for dynamic types
995 static Hashtable fields = new Hashtable ();
996 static public bool RegisterFieldValue (FieldBuilder fb, object value)
998 if (fields.Contains (fb))
1001 fields.Add (fb, value);
1006 static public object GetValue (FieldBuilder fb)
1011 static Hashtable fieldbuilders_to_fields = new Hashtable ();
1012 static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f)
1014 if (fieldbuilders_to_fields.Contains (fb))
1017 fieldbuilders_to_fields.Add (fb, f);
1021 static public FieldBase GetField (FieldInfo fb)
1023 return (FieldBase) fieldbuilders_to_fields [fb];
1026 static Hashtable events;
1028 static public bool RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
1031 events = new Hashtable ();
1033 if (events.Contains (eb))
1036 events.Add (eb, new Pair (add, remove));
1041 static public MethodInfo GetAddMethod (EventInfo ei)
1043 if (ei is MyEventBuilder) {
1044 Pair pair = (Pair) events [ei];
1046 return (MethodInfo) pair.First;
1048 return ei.GetAddMethod ();
1051 static public MethodInfo GetRemoveMethod (EventInfo ei)
1053 if (ei is MyEventBuilder) {
1054 Pair pair = (Pair) events [ei];
1056 return (MethodInfo) pair.Second;
1058 return ei.GetAddMethod ();
1061 static Hashtable priv_fields_events;
1063 static public bool RegisterPrivateFieldOfEvent (EventInfo einfo, FieldBuilder builder)
1065 if (priv_fields_events == null)
1066 priv_fields_events = new Hashtable ();
1068 if (priv_fields_events.Contains (einfo))
1071 priv_fields_events.Add (einfo, builder);
1076 static public MemberInfo GetPrivateFieldOfEvent (EventInfo ei)
1078 return (MemberInfo) priv_fields_events [ei];
1081 static Hashtable properties;
1083 static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
1085 if (properties == null)
1086 properties = new Hashtable ();
1088 if (properties.Contains (pb))
1091 properties.Add (pb, new Pair (get, set));
1097 // FIXME: we need to return the accessors depending on whether
1098 // they are visible or not.
1100 static public MethodInfo [] GetAccessors (PropertyInfo pi)
1104 if (pi is PropertyBuilder){
1105 Pair pair = (Pair) properties [pi];
1107 ret = new MethodInfo [2];
1108 ret [0] = (MethodInfo) pair.First;
1109 ret [1] = (MethodInfo) pair.Second;
1113 MethodInfo [] mi = new MethodInfo [2];
1116 // Why this and not pi.GetAccessors?
1117 // Because sometimes index 0 is the getter
1118 // sometimes it is 1
1120 mi [0] = pi.GetGetMethod (true);
1121 mi [1] = pi.GetSetMethod (true);
1127 static public MethodInfo GetPropertyGetter (PropertyInfo pi)
1129 if (pi is PropertyBuilder){
1130 Pair de = (Pair) properties [pi];
1132 return (MethodInfo) de.Second;
1134 return pi.GetSetMethod ();
1137 static public MethodInfo GetPropertySetter (PropertyInfo pi)
1139 if (pi is PropertyBuilder){
1140 Pair de = (Pair) properties [pi];
1142 return (MethodInfo) de.First;
1144 return pi.GetGetMethod ();
1148 /// Given an array of interface types, expand and eliminate repeated ocurrences
1149 /// of an interface.
1153 /// This expands in context like: IA; IB : IA; IC : IA, IB; the interface "IC" to
1156 public static Type [] ExpandInterfaces (Type [] base_interfaces)
1158 ArrayList new_ifaces = new ArrayList ();
1160 foreach (Type iface in base_interfaces){
1161 if (!new_ifaces.Contains (iface))
1162 new_ifaces.Add (iface);
1164 Type [] implementing = TypeManager.GetInterfaces (iface);
1166 foreach (Type imp in implementing){
1167 if (!new_ifaces.Contains (imp))
1168 new_ifaces.Add (imp);
1171 Type [] ret = new Type [new_ifaces.Count];
1172 new_ifaces.CopyTo (ret, 0);
1177 /// This function returns the interfaces in the type `t'. Works with
1178 /// both types and TypeBuilders.
1180 public static Type [] GetInterfaces (Type t)
1183 // The reason for catching the Array case is that Reflection.Emit
1184 // will not return a TypeBuilder for Array types of TypeBuilder types,
1185 // but will still throw an exception if we try to call GetInterfaces
1188 // Since the array interfaces are always constant, we return those for
1193 t = TypeManager.array_type;
1195 if (t is TypeBuilder){
1196 Type [] parent_ifaces;
1198 if (t.BaseType == null)
1199 parent_ifaces = NoTypes;
1201 parent_ifaces = GetInterfaces (t.BaseType);
1202 Type [] type_ifaces = (Type []) builder_to_ifaces [t];
1203 if (type_ifaces == null)
1204 type_ifaces = NoTypes;
1206 int parent_count = parent_ifaces.Length;
1207 Type [] result = new Type [parent_count + type_ifaces.Length];
1208 parent_ifaces.CopyTo (result, 0);
1209 type_ifaces.CopyTo (result, parent_count);
1213 return t.GetInterfaces ();
1217 /// The following is used to check if a given type implements an interface.
1218 /// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
1220 public static bool ImplementsInterface (Type t, Type iface)
1225 // FIXME OPTIMIZATION:
1226 // as soon as we hit a non-TypeBuiler in the interface
1227 // chain, we could return, as the `Type.GetInterfaces'
1228 // will return all the interfaces implement by the type
1232 interfaces = GetInterfaces (t);
1234 if (interfaces != null){
1235 foreach (Type i in interfaces){
1242 } while (t != null);
1247 // This is a custom version of Convert.ChangeType() which works
1248 // with the TypeBuilder defined types when compiling corlib.
1249 public static object ChangeType (object value, Type conversionType)
1251 if (!(value is IConvertible))
1252 throw new ArgumentException ();
1254 IConvertible convertValue = (IConvertible) value;
1255 CultureInfo ci = CultureInfo.CurrentCulture;
1256 NumberFormatInfo provider = ci.NumberFormat;
1259 // We must use Type.Equals() here since `conversionType' is
1260 // the TypeBuilder created version of a system type and not
1261 // the system type itself. You cannot use Type.GetTypeCode()
1262 // on such a type - it'd always return TypeCode.Object.
1264 if (conversionType.Equals (typeof (Boolean)))
1265 return (object)(convertValue.ToBoolean (provider));
1266 else if (conversionType.Equals (typeof (Byte)))
1267 return (object)(convertValue.ToByte (provider));
1268 else if (conversionType.Equals (typeof (Char)))
1269 return (object)(convertValue.ToChar (provider));
1270 else if (conversionType.Equals (typeof (DateTime)))
1271 return (object)(convertValue.ToDateTime (provider));
1272 else if (conversionType.Equals (typeof (Decimal)))
1273 return (object)(convertValue.ToDecimal (provider));
1274 else if (conversionType.Equals (typeof (Double)))
1275 return (object)(convertValue.ToDouble (provider));
1276 else if (conversionType.Equals (typeof (Int16)))
1277 return (object)(convertValue.ToInt16 (provider));
1278 else if (conversionType.Equals (typeof (Int32)))
1279 return (object)(convertValue.ToInt32 (provider));
1280 else if (conversionType.Equals (typeof (Int64)))
1281 return (object)(convertValue.ToInt64 (provider));
1282 else if (conversionType.Equals (typeof (SByte)))
1283 return (object)(convertValue.ToSByte (provider));
1284 else if (conversionType.Equals (typeof (Single)))
1285 return (object)(convertValue.ToSingle (provider));
1286 else if (conversionType.Equals (typeof (String)))
1287 return (object)(convertValue.ToString (provider));
1288 else if (conversionType.Equals (typeof (UInt16)))
1289 return (object)(convertValue.ToUInt16 (provider));
1290 else if (conversionType.Equals (typeof (UInt32)))
1291 return (object)(convertValue.ToUInt32 (provider));
1292 else if (conversionType.Equals (typeof (UInt64)))
1293 return (object)(convertValue.ToUInt64 (provider));
1294 else if (conversionType.Equals (typeof (Object)))
1295 return (object)(value);
1297 throw new InvalidCastException ();
1301 // This is needed, because enumerations from assemblies
1302 // do not report their underlyingtype, but they report
1305 public static Type EnumToUnderlying (Type t)
1307 if (t == TypeManager.enum_type)
1310 t = t.UnderlyingSystemType;
1311 if (!TypeManager.IsEnumType (t))
1314 if (t is TypeBuilder) {
1315 // slow path needed to compile corlib
1316 if (t == TypeManager.bool_type ||
1317 t == TypeManager.byte_type ||
1318 t == TypeManager.sbyte_type ||
1319 t == TypeManager.char_type ||
1320 t == TypeManager.short_type ||
1321 t == TypeManager.ushort_type ||
1322 t == TypeManager.int32_type ||
1323 t == TypeManager.uint32_type ||
1324 t == TypeManager.int64_type ||
1325 t == TypeManager.uint64_type)
1327 throw new Exception ("Unhandled typecode in enum " + " from " + t.AssemblyQualifiedName);
1329 TypeCode tc = Type.GetTypeCode (t);
1332 case TypeCode.Boolean:
1333 return TypeManager.bool_type;
1335 return TypeManager.byte_type;
1336 case TypeCode.SByte:
1337 return TypeManager.sbyte_type;
1339 return TypeManager.char_type;
1340 case TypeCode.Int16:
1341 return TypeManager.short_type;
1342 case TypeCode.UInt16:
1343 return TypeManager.ushort_type;
1344 case TypeCode.Int32:
1345 return TypeManager.int32_type;
1346 case TypeCode.UInt32:
1347 return TypeManager.uint32_type;
1348 case TypeCode.Int64:
1349 return TypeManager.int64_type;
1350 case TypeCode.UInt64:
1351 return TypeManager.uint64_type;
1353 throw new Exception ("Unhandled typecode in enum " + tc + " from " + t.AssemblyQualifiedName);
1357 // When compiling corlib and called with one of the core types, return
1358 // the corresponding typebuilder for that type.
1360 public static Type TypeToCoreType (Type t)
1362 if (RootContext.StdLib || (t is TypeBuilder))
1365 TypeCode tc = Type.GetTypeCode (t);
1368 case TypeCode.Boolean:
1369 return TypeManager.bool_type;
1371 return TypeManager.byte_type;
1372 case TypeCode.SByte:
1373 return TypeManager.sbyte_type;
1375 return TypeManager.char_type;
1376 case TypeCode.Int16:
1377 return TypeManager.short_type;
1378 case TypeCode.UInt16:
1379 return TypeManager.ushort_type;
1380 case TypeCode.Int32:
1381 return TypeManager.int32_type;
1382 case TypeCode.UInt32:
1383 return TypeManager.uint32_type;
1384 case TypeCode.Int64:
1385 return TypeManager.int64_type;
1386 case TypeCode.UInt64:
1387 return TypeManager.uint64_type;
1388 case TypeCode.String:
1389 return TypeManager.string_type;
1391 if (t == typeof (void))
1392 return TypeManager.void_type;
1393 if (t == typeof (object))
1394 return TypeManager.object_type;
1400 /// Utility function that can be used to probe whether a type
1401 /// is managed or not.
1403 public static bool VerifyUnManaged (Type t, Location loc)
1405 if (t.IsValueType || t.IsPointer){
1407 // FIXME: this is more complex, we actually need to
1408 // make sure that the type does not contain any
1414 if (!RootContext.StdLib && (t == TypeManager.decimal_type))
1415 // We need this explicit check here to make it work when
1416 // compiling corlib.
1421 "Cannot take the address or size of a variable of a managed type ('" +
1422 CSharpName (t) + "')");
1427 /// Returns the name of the indexer in a given type.
1430 /// The default is not always `Item'. The user can change this behaviour by
1431 /// using the DefaultMemberAttribute in the class.
1433 /// For example, the String class indexer is named `Chars' not `Item'
1435 public static string IndexerPropertyName (Type t)
1438 if (t is TypeBuilder) {
1439 TypeContainer tc = (TypeContainer) builder_to_container [t];
1442 // FIXME: Temporary hack, until we deploy the IndexerName
1443 // property code (and attributes) in the interface code.
1449 return tc.IndexerName;
1452 System.Attribute attr = System.Attribute.GetCustomAttribute (
1453 t, TypeManager.default_member_type);
1455 DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
1456 return dma.MemberName;
1462 public static void MakePinned (LocalBuilder builder)
1465 // FIXME: Flag the "LocalBuilder" type as being
1466 // pinned. Figure out API.
1472 // Returns whether the array of memberinfos contains the given method
1474 static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method)
1476 Type [] new_args = TypeManager.GetArgumentTypes (new_method);
1478 foreach (MethodBase method in array){
1479 if (method.Name != new_method.Name)
1482 Type [] old_args = TypeManager.GetArgumentTypes (method);
1483 int old_count = old_args.Length;
1486 if (new_args.Length != old_count)
1489 for (i = 0; i < old_count; i++){
1490 if (old_args [i] != new_args [i])
1496 if (!(method is MethodInfo && new_method is MethodInfo))
1499 if (((MethodInfo) method).ReturnType == ((MethodInfo) new_method).ReturnType)
1506 // We copy methods from `new_members' into `target_list' if the signature
1507 // for the method from in the new list does not exist in the target_list
1509 // The name is assumed to be the same.
1511 public static ArrayList CopyNewMethods (ArrayList target_list, MemberInfo [] new_members)
1513 if (target_list == null){
1514 target_list = new ArrayList ();
1516 foreach (MemberInfo mi in new_members){
1517 if (mi is MethodBase)
1518 target_list.Add (mi);
1523 MemberInfo [] target_array = new MemberInfo [target_list.Count];
1524 target_list.CopyTo (target_array, 0);
1526 foreach (MemberInfo mi in new_members){
1527 MethodBase new_method = (MethodBase) mi;
1529 if (!ArrayContainsMethod (target_array, new_method))
1530 target_list.Add (new_method);
1536 public enum MethodFlags {
1541 static public MethodFlags GetMethodFlags (MethodBase mb)
1543 MethodFlags flags = 0;
1545 if (mb.DeclaringType is TypeBuilder){
1547 // FIXME: Support lookups of Obsolete and ConditionalAttribute
1548 // on MethodBuilders.
1553 object [] attrs = mb.GetCustomAttributes (false);
1554 foreach (object ta in attrs){
1555 if (!(ta is System.Attribute)){
1556 Console.WriteLine ("Unknown type in GetMethodFlags: " + ta);
1559 System.Attribute a = (System.Attribute) ta;
1560 if (a.TypeId == TypeManager.obsolete_attribute_type){
1561 flags |= MethodFlags.IsObsolete;
1566 // Skip over conditional code.
1568 if (a.TypeId == TypeManager.conditional_attribute_type){
1569 ConditionalAttribute ca = (ConditionalAttribute) a;
1571 if (RootContext.AllDefines [ca.ConditionString] == null)
1572 flags |= MethodFlags.ShouldIgnore;
1579 #region MemberLookup implementation
1582 // Name of the member
1584 static string closure_name;
1587 // Whether we allow private members in the result (since FindMembers
1588 // uses NonPublic for both protected and private), we need to distinguish.
1590 static bool closure_private_ok;
1593 // Who is invoking us and which type is being queried currently.
1595 static Type closure_invocation_type;
1596 static Type closure_queried_type;
1599 // The assembly that defines the type is that is calling us
1601 static Assembly closure_invocation_assembly;
1604 // This filter filters by name + whether it is ok to include private
1605 // members in the search
1607 static internal bool FilterWithClosure (MemberInfo m, object filter_criteria)
1610 // Hack: we know that the filter criteria will always be in the `closure'
1614 if (m.Name != closure_name)
1618 // Ugly: we need to find out the type of `m', and depending
1619 // on this, tell whether we accept or not
1621 if (m is MethodBase){
1622 MethodBase mb = (MethodBase) m;
1623 MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
1625 if (ma == MethodAttributes.Private)
1626 return closure_private_ok;
1629 // FamAndAssem requires that we not only derivate, but we are on the
1632 if (ma == MethodAttributes.FamANDAssem){
1633 if (closure_invocation_assembly != mb.DeclaringType.Assembly)
1637 // FamORAssem, Family and Public:
1641 if (m is FieldInfo){
1642 FieldInfo fi = (FieldInfo) m;
1643 FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
1645 if (fa == FieldAttributes.Private)
1646 return closure_private_ok;
1649 // FamAndAssem requires that we not only derivate, but we are on the
1652 if (fa == FieldAttributes.FamANDAssem){
1653 if (closure_invocation_assembly != fi.DeclaringType.Assembly)
1656 // FamORAssem, Family and Public:
1661 // EventInfos and PropertyInfos, return true
1666 static MemberFilter FilterWithClosure_delegate = new MemberFilter (FilterWithClosure);
1669 // Looks up a member called `name' in the `queried_type'. This lookup
1670 // is done by code that is contained in the definition for `invocation_type'.
1672 // The binding flags are `bf' and the kind of members being looked up are `mt'
1674 // Returns an array of a single element for everything but Methods/Constructors
1675 // that might return multiple matches.
1677 public static MemberInfo [] MemberLookup (Type invocation_type, Type queried_type,
1678 MemberTypes mt, BindingFlags original_bf, string name)
1680 BindingFlags bf = original_bf;
1682 ArrayList method_list = null;
1683 Type current_type = queried_type;
1684 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
1686 bool always_ok_flag = false;
1688 closure_name = name;
1689 closure_invocation_type = invocation_type;
1690 closure_invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
1693 // If we are a nested class, we always have access to our container
1696 if (invocation_type != null){
1697 string invocation_name = invocation_type.FullName;
1698 if (invocation_name.IndexOf ('+') != -1){
1699 string container = queried_type.FullName + "+";
1700 int container_length = container.Length;
1702 if (invocation_name.Length > container_length){
1703 string shared = invocation_name.Substring (0, container_length);
1705 if (shared == container)
1706 always_ok_flag = true;
1715 // `NonPublic' is lame, because it includes both protected and
1716 // private methods, so we need to control this behavior by
1717 // explicitly tracking if a private method is ok or not.
1719 // The possible cases are:
1720 // public, private and protected (internal does not come into the
1723 if (invocation_type != null){
1724 if (invocation_type == current_type){
1727 private_ok = always_ok_flag;
1729 if (private_ok || invocation_type.IsSubclassOf (current_type))
1730 bf = original_bf | BindingFlags.NonPublic;
1733 bf = original_bf & ~BindingFlags.NonPublic;
1736 closure_private_ok = private_ok;
1737 closure_queried_type = current_type;
1739 mi = TypeManager.FindMembers (
1740 current_type, mt, bf | BindingFlags.DeclaredOnly,
1741 FilterWithClosure_delegate, name);
1743 if (current_type == TypeManager.object_type)
1746 current_type = current_type.BaseType;
1749 // This happens with interfaces, they have a null
1750 // basetype. Look members up in the Object class.
1752 if (current_type == null)
1753 current_type = TypeManager.object_type;
1759 int count = mi.Length;
1765 // Events and types are returned by both `static' and `instance'
1766 // searches, which means that our above FindMembers will
1767 // return two copies of the same.
1769 if (count == 1 && !(mi [0] is MethodBase)){
1774 // Multiple properties: we query those just to find out the indexer
1777 if (mi [0] is PropertyInfo)
1781 // We found methods, turn the search into "method scan"
1785 method_list = CopyNewMethods (method_list, mi);
1786 mt &= (MemberTypes.Method | MemberTypes.Constructor);
1787 } while (searching);
1789 if (method_list != null && method_list.Count > 0)
1790 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
1793 // Interfaces do not list members they inherit, so we have to
1796 if (!queried_type.IsInterface)
1799 if (queried_type.IsArray)
1800 queried_type = TypeManager.array_type;
1802 Type [] ifaces = GetInterfaces (queried_type);
1806 foreach (Type itype in ifaces){
1809 x = MemberLookup (null, itype, mt, bf, name);