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;
22 namespace Mono.CSharp {
24 public class TypeManager {
26 // A list of core types that the compiler requires or uses
28 static public Type object_type;
29 static public Type value_type;
30 static public Type string_type;
31 static public Type int32_type;
32 static public Type uint32_type;
33 static public Type int64_type;
34 static public Type uint64_type;
35 static public Type float_type;
36 static public Type double_type;
37 static public Type char_type;
38 static public Type char_ptr_type;
39 static public Type short_type;
40 static public Type decimal_type;
41 static public Type bool_type;
42 static public Type sbyte_type;
43 static public Type byte_type;
44 static public Type ushort_type;
45 static public Type enum_type;
46 static public Type delegate_type;
47 static public Type multicast_delegate_type;
48 static public Type void_type;
49 static public Type enumeration_type;
50 static public Type array_type;
51 static public Type runtime_handle_type;
52 static public Type icloneable_type;
53 static public Type type_type;
54 static public Type ienumerator_type;
55 static public Type idisposable_type;
56 static public Type default_member_type;
57 static public Type iasyncresult_type;
58 static public Type asynccallback_type;
59 static public Type intptr_type;
60 static public Type monitor_type;
61 static public Type runtime_field_handle_type;
62 static public Type attribute_type;
63 static public Type attribute_usage_type;
64 static public Type dllimport_type;
65 static public Type unverifiable_code_type;
66 static public Type methodimpl_attr_type;
67 static public Type marshal_as_attr_type;
68 static public Type param_array_type;
69 static public Type void_ptr_type;
70 static public Type indexer_name_type;
71 static public Type trace_type;
72 static public Type debug_type;
74 static public Type [] NoTypes;
77 // Internal, not really used outside
79 static Type runtime_helpers_type;
82 // These methods are called by code generated by the compiler
84 static public MethodInfo string_concat_string_string;
85 static public MethodInfo string_concat_object_object;
86 static public MethodInfo string_isinterneted_string;
87 static public MethodInfo system_type_get_type_from_handle;
88 static public MethodInfo object_getcurrent_void;
89 static public MethodInfo bool_movenext_void;
90 static public MethodInfo void_dispose_void;
91 static public MethodInfo void_monitor_enter_object;
92 static public MethodInfo void_monitor_exit_object;
93 static public MethodInfo void_initializearray_array_fieldhandle;
94 static public MethodInfo int_getlength_int;
95 static public MethodInfo delegate_combine_delegate_delegate;
96 static public MethodInfo delegate_remove_delegate_delegate;
97 static public MethodInfo int_get_offset_to_string_data;
98 static public MethodInfo int_array_get_length;
101 // The attribute constructors.
103 static public ConstructorInfo cons_param_array_attribute;
104 static public ConstructorInfo void_decimal_ctor_five_args;
107 // Holds the Array of Assemblies that have been loaded
108 // (either because it is the default or the user used the
109 // -r command line option)
111 static Assembly [] assemblies;
114 // Keeps a list of module builders. We used this to do lookups
115 // on the modulebuilder using GetType -- needed for arrays
117 static ModuleBuilder [] modules;
120 // This is the type_cache from the assemblies to avoid
121 // hitting System.Reflection on every lookup.
123 static Hashtable types;
126 // This is used to hotld the corresponding TypeContainer objects
127 // since we need this in FindMembers
129 static Hashtable typecontainers;
132 // Keeps track of those types that are defined by the
135 static ArrayList user_types;
138 // Keeps a mapping between TypeBuilders and their TypeContainers
140 static PtrHashtable builder_to_container;
143 // Tracks the interfaces implemented by typebuilders. We only
144 // enter those who do implement or or more interfaces
146 static PtrHashtable builder_to_ifaces;
149 // Maps MethodBase.RuntimeTypeHandle to a Type array that contains
150 // the arguments to the method
152 static Hashtable method_arguments;
155 // Maybe `method_arguments' should be replaced and only
156 // method_internal_params should be kept?
158 static Hashtable method_internal_params;
160 static PtrHashtable builder_to_interface;
163 // Keeps track of delegate types
166 static Hashtable builder_to_delegate;
169 // Keeps track of enum types
172 static Hashtable builder_to_enum;
175 // Keeps track of attribute types
178 static Hashtable builder_to_attr;
186 /// A filter for Findmembers that uses the Signature object to
189 static bool SignatureFilter (MemberInfo mi, object criteria)
191 Signature sig = (Signature) criteria;
193 if (!(mi is MethodBase))
196 if (mi.Name != sig.name)
199 int count = sig.args.Length;
201 if (mi is MethodBuilder || mi is ConstructorBuilder){
202 Type [] candidate_args = GetArgumentTypes ((MethodBase) mi);
204 if (candidate_args.Length != count)
207 for (int i = 0; i < count; i++)
208 if (candidate_args [i] != sig.args [i])
213 ParameterInfo [] pars = ((MethodBase) mi).GetParameters ();
215 if (pars.Length != count)
218 for (int i = 0; i < count; i++)
219 if (pars [i].ParameterType != sig.args [i])
225 // A delegate that points to the filter above.
226 static MemberFilter signature_filter;
228 static TypeManager ()
230 assemblies = new Assembly [0];
232 user_types = new ArrayList ();
234 types = new Hashtable ();
235 typecontainers = new Hashtable ();
237 builder_to_interface = new PtrHashtable ();
238 builder_to_delegate = new PtrHashtable ();
239 builder_to_enum = new PtrHashtable ();
240 builder_to_attr = new PtrHashtable ();
241 method_arguments = new PtrHashtable ();
242 method_internal_params = new PtrHashtable ();
243 builder_to_container = new PtrHashtable ();
244 builder_to_ifaces = new PtrHashtable ();
246 NoTypes = new Type [0];
248 signature_filter = new MemberFilter (SignatureFilter);
251 public static void AddUserType (string name, TypeBuilder t, Type [] ifaces)
256 Type prev = (Type) types [name];
257 TypeContainer tc = (TypeContainer) builder_to_container [prev];
261 // This probably never happens, as we catch this before
263 Report.Error (-17, "The type `" + name + "' has already been defined.");
267 tc = (TypeContainer) builder_to_container [t];
270 1595, "The type `" + name + "' is defined in an existing assembly;"+
271 " Using the new definition from: " + tc.Location);
272 Report.Warning (1595, "Previously defined in: " + prev.Assembly.FullName);
280 builder_to_ifaces [t] = ifaces;
284 // This entry point is used by types that we define under the covers
286 public static void RegisterBuilder (TypeBuilder tb, Type [] ifaces)
289 builder_to_ifaces [tb] = ifaces;
292 public static void AddUserType (string name, TypeBuilder t, TypeContainer tc, Type [] ifaces)
294 builder_to_container.Add (t, tc);
295 typecontainers.Add (name, tc);
296 AddUserType (name, t, ifaces);
299 public static void AddDelegateType (string name, TypeBuilder t, Delegate del)
302 builder_to_delegate.Add (t, del);
305 public static void AddEnumType (string name, TypeBuilder t, Enum en)
308 builder_to_enum.Add (t, en);
311 public static void AddUserInterface (string name, TypeBuilder t, Interface i, Type [] ifaces)
313 AddUserType (name, t, ifaces);
314 builder_to_interface.Add (t, i);
317 public static void RegisterAttrType (Type t, TypeContainer tc)
319 builder_to_attr.Add (t, tc);
323 /// Returns the TypeContainer whose Type is `t' or null if there is no
324 /// TypeContainer for `t' (ie, the Type comes from a library)
326 public static TypeContainer LookupTypeContainer (Type t)
328 return (TypeContainer) builder_to_container [t];
331 public static Interface LookupInterface (Type t)
333 return (Interface) builder_to_interface [t];
336 public static Delegate LookupDelegate (Type t)
338 return (Delegate) builder_to_delegate [t];
341 public static Enum LookupEnum (Type t)
343 return (Enum) builder_to_enum [t];
346 public static TypeContainer LookupAttr (Type t)
348 return (TypeContainer) builder_to_attr [t];
352 /// Registers an assembly to load types from.
354 public static void AddAssembly (Assembly a)
356 int top = assemblies.Length;
357 Assembly [] n = new Assembly [top + 1];
359 assemblies.CopyTo (n, 0);
366 /// Registers a module builder to lookup types from
368 public static void AddModule (ModuleBuilder mb)
370 int top = modules != null ? modules.Length : 0;
371 ModuleBuilder [] n = new ModuleBuilder [top + 1];
374 modules.CopyTo (n, 0);
380 /// Returns the Type associated with @name
382 public static Type LookupType (string name)
387 // First lookup in user defined and cached values
390 t = (Type) types [name];
394 foreach (Assembly a in assemblies){
395 t = a.GetType (name);
403 foreach (ModuleBuilder mb in modules) {
404 t = mb.GetType (name);
415 /// Returns the C# name of a type if possible, or the full type name otherwise
417 static public string CSharpName (Type t)
419 return Regex.Replace (t.FullName,
421 @"(Int32|UInt32|Int16|Uint16|Int64|UInt64|" +
422 @"Single|Double|Char|Decimal|Byte|SByte|Object|" +
423 @"Boolean|String|Void)" +
425 new MatchEvaluator (CSharpNameMatch));
428 static String CSharpNameMatch (Match match)
430 string s = match.Groups [1].Captures [0].Value;
432 Replace ("int32", "int").
433 Replace ("uint32", "uint").
434 Replace ("int16", "short").
435 Replace ("uint16", "ushort").
436 Replace ("int64", "long").
437 Replace ("uint64", "ulong").
438 Replace ("single", "float").
439 Replace ("boolean", "bool")
440 + match.Groups [2].Captures [0].Value;
444 /// Returns the signature of the method
446 static public string CSharpSignature (MethodBase mb)
451 // FIXME: We should really have a single function to do
452 // everything instead of the following 5 line pattern
454 ParameterData iparams = LookupParametersByBuilder (mb);
456 if (iparams == null){
457 ParameterInfo [] pi = mb.GetParameters ();
458 iparams = new ReflectionParameters (pi);
461 for (int i = 0; i < iparams.Count; i++) {
465 sig += iparams.ParameterDesc(i);
469 return mb.DeclaringType.Name + "." + mb.Name + sig;
473 /// Looks up a type, and aborts if it is not found. This is used
474 /// by types required by the compiler
476 static Type CoreLookupType (string name)
478 Type t = LookupType (name);
481 Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
482 Environment.Exit (0);
489 /// Returns the MethodInfo for a method named `name' defined
490 /// in type `t' which takes arguments of types `args'
492 static MethodInfo GetMethod (Type t, string name, Type [] args)
501 t, MemberTypes.Method,
502 instance_and_static | BindingFlags.Public, signature_filter, sig);
503 if (mi == null || mi.Length == 0 || !(mi [0] is MethodInfo)){
504 Report.Error (-19, "Can not find the core function `" + name + "'");
508 return (MethodInfo) mi [0];
512 /// Returns the ConstructorInfo for "args"
514 static ConstructorInfo GetConstructor (Type t, Type [] args)
522 mi = FindMembers (t, MemberTypes.Constructor,
523 instance_and_static | BindingFlags.Public, signature_filter, sig);
524 if (mi == null || mi.Length == 0 || !(mi [0] is ConstructorInfo)){
525 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
529 return (ConstructorInfo) mi [0];
532 public static void InitEnumUnderlyingTypes ()
535 int32_type = CoreLookupType ("System.Int32");
536 int64_type = CoreLookupType ("System.Int64");
537 uint32_type = CoreLookupType ("System.UInt32");
538 uint64_type = CoreLookupType ("System.UInt64");
539 byte_type = CoreLookupType ("System.Byte");
540 sbyte_type = CoreLookupType ("System.SByte");
541 short_type = CoreLookupType ("System.Int16");
542 ushort_type = CoreLookupType ("System.UInt16");
546 /// The types have to be initialized after the initial
547 /// population of the type has happened (for example, to
548 /// bootstrap the corlib.dll
550 public static void InitCoreTypes ()
552 object_type = CoreLookupType ("System.Object");
553 value_type = CoreLookupType ("System.ValueType");
555 InitEnumUnderlyingTypes ();
557 char_type = CoreLookupType ("System.Char");
558 string_type = CoreLookupType ("System.String");
559 float_type = CoreLookupType ("System.Single");
560 double_type = CoreLookupType ("System.Double");
561 char_ptr_type = CoreLookupType ("System.Char*");
562 decimal_type = CoreLookupType ("System.Decimal");
563 bool_type = CoreLookupType ("System.Boolean");
564 enum_type = CoreLookupType ("System.Enum");
566 multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
567 delegate_type = CoreLookupType ("System.Delegate");
569 array_type = CoreLookupType ("System.Array");
570 void_type = CoreLookupType ("System.Void");
571 type_type = CoreLookupType ("System.Type");
573 runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
574 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
575 default_member_type = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
576 runtime_handle_type = CoreLookupType ("System.RuntimeTypeHandle");
577 asynccallback_type = CoreLookupType ("System.AsyncCallback");
578 iasyncresult_type = CoreLookupType ("System.IAsyncResult");
579 ienumerator_type = CoreLookupType ("System.Collections.IEnumerator");
580 idisposable_type = CoreLookupType ("System.IDisposable");
581 icloneable_type = CoreLookupType ("System.ICloneable");
582 monitor_type = CoreLookupType ("System.Threading.Monitor");
583 intptr_type = CoreLookupType ("System.IntPtr");
585 attribute_type = CoreLookupType ("System.Attribute");
586 attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
587 dllimport_type = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute");
588 methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute");
589 marshal_as_attr_type = CoreLookupType ("System.Runtime.InteropServices.MarshalAsAttribute");
590 param_array_type = CoreLookupType ("System.ParamArrayAttribute");
592 unverifiable_code_type= CoreLookupType ("System.Security.UnverifiableCodeAttribute");
594 void_ptr_type = CoreLookupType ("System.Void*");
596 indexer_name_type = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute");
597 if (RootContext.StdLib) {
598 trace_type = CoreLookupType ("System.Diagnostics.Trace");
599 debug_type = CoreLookupType ("System.Diagnostics.Debug");
604 // The helper methods that are used by the compiler
606 public static void InitCodeHelpers ()
609 // Now load the default methods that we use.
611 Type [] string_string = { string_type, string_type };
612 string_concat_string_string = GetMethod (
613 string_type, "Concat", string_string);
615 Type [] object_object = { object_type, object_type };
616 string_concat_object_object = GetMethod (
617 string_type, "Concat", object_object);
619 Type [] string_ = { string_type };
620 string_isinterneted_string = GetMethod (
621 string_type, "IsInterned", string_);
623 Type [] runtime_type_handle = { runtime_handle_type };
624 system_type_get_type_from_handle = GetMethod (
625 type_type, "GetTypeFromHandle", runtime_type_handle);
627 Type [] delegate_delegate = { delegate_type, delegate_type };
628 delegate_combine_delegate_delegate = GetMethod (
629 delegate_type, "Combine", delegate_delegate);
631 delegate_remove_delegate_delegate = GetMethod (
632 delegate_type, "Remove", delegate_delegate);
637 Type [] void_arg = { };
638 object_getcurrent_void = GetMethod (
639 ienumerator_type, "get_Current", void_arg);
640 bool_movenext_void = GetMethod (
641 ienumerator_type, "MoveNext", void_arg);
642 void_dispose_void = GetMethod (
643 idisposable_type, "Dispose", void_arg);
644 int_get_offset_to_string_data = GetMethod (
645 runtime_helpers_type, "get_OffsetToStringData", void_arg);
646 int_array_get_length = GetMethod (
647 array_type, "get_Length", void_arg);
652 Type [] object_arg = { object_type };
653 void_monitor_enter_object = GetMethod (
654 monitor_type, "Enter", object_arg);
655 void_monitor_exit_object = GetMethod (
656 monitor_type, "Exit", object_arg);
658 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
660 void_initializearray_array_fieldhandle = GetMethod (
661 runtime_helpers_type, "InitializeArray", array_field_handle_arg);
666 Type [] int_arg = { int32_type };
667 int_getlength_int = GetMethod (
668 array_type, "GetLength", int_arg);
671 // Decimal constructors
673 Type [] dec_arg = { int32_type, int32_type, int32_type, bool_type, byte_type };
674 void_decimal_ctor_five_args = GetConstructor (
675 decimal_type, dec_arg);
680 cons_param_array_attribute = GetConstructor (
681 param_array_type, void_arg);
685 const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
688 // FIXME: This can be optimized easily. speedup by having a single builder mapping
690 public static MemberInfo [] FindMembers (Type t, MemberTypes mt, BindingFlags bf,
691 MemberFilter filter, object criteria)
694 // We have to take care of arrays specially, because GetType on
695 // a TypeBuilder array will return a Type, not a TypeBuilder,
696 // and we can not call FindMembers on this type.
698 if (t.IsSubclassOf (TypeManager.array_type))
699 return TypeManager.array_type.FindMembers (mt, bf, filter, criteria);
701 if (!(t is TypeBuilder)){
703 // Since FindMembers will not lookup both static and instance
704 // members, we emulate this behaviour here.
706 if ((bf & instance_and_static) == instance_and_static){
707 MemberInfo [] i_members = t.FindMembers (
708 mt, bf & ~BindingFlags.Static, filter, criteria);
710 int i_len = i_members.Length;
712 MemberInfo one = i_members [0];
715 // If any of these are present, we are done!
717 if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
721 MemberInfo [] s_members = t.FindMembers (
722 mt, bf & ~BindingFlags.Instance, filter, criteria);
724 int s_len = s_members.Length;
725 if (i_len > 0 || s_len > 0){
726 MemberInfo [] both = new MemberInfo [i_len + s_len];
728 i_members.CopyTo (both, 0);
729 s_members.CopyTo (both, i_len);
739 return t.FindMembers (mt, bf, filter, criteria);
743 // FIXME: We should not have builder_to_blah everywhere,
744 // we should just have a builder_to_findmemberizable
745 // and have them implement a new ICanFindMembers interface
747 Enum e = (Enum) builder_to_enum [t];
750 return e.FindMembers (mt, bf, filter, criteria);
752 Delegate del = (Delegate) builder_to_delegate [t];
755 return del.FindMembers (mt, bf, filter, criteria);
757 Interface iface = (Interface) builder_to_interface [t];
760 return iface.FindMembers (mt, bf, filter, criteria);
762 TypeContainer tc = (TypeContainer) builder_to_container [t];
765 return tc.FindMembers (mt, bf, filter, criteria);
770 public static bool IsBuiltinType (Type t)
772 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
773 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
774 t == char_type || t == short_type || t == decimal_type || t == bool_type ||
775 t == sbyte_type || t == byte_type || t == ushort_type)
781 public static bool IsDelegateType (Type t)
783 if (t.IsSubclassOf (TypeManager.delegate_type))
789 public static bool IsEnumType (Type t)
791 if (t.IsSubclassOf (TypeManager.enum_type))
797 public static bool IsInterfaceType (Type t)
799 Interface iface = (Interface) builder_to_interface [t];
808 /// Returns the User Defined Types
810 public static ArrayList UserTypes {
816 public static Hashtable TypeContainers {
818 return typecontainers;
822 static Hashtable builder_to_constant;
824 public static void RegisterConstant (FieldBuilder fb, Const c)
826 if (builder_to_constant == null)
827 builder_to_constant = new PtrHashtable ();
829 if (builder_to_constant.Contains (fb))
832 builder_to_constant.Add (fb, c);
835 public static Const LookupConstant (FieldBuilder fb)
837 if (builder_to_constant == null)
840 return (Const) builder_to_constant [fb];
844 /// Gigantic work around for missing features in System.Reflection.Emit follows.
848 /// Since System.Reflection.Emit can not return MethodBase.GetParameters
849 /// for anything which is dynamic, and we need this in a number of places,
850 /// we register this information here, and use it afterwards.
852 static public bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
857 method_arguments.Add (mb, args);
858 method_internal_params.Add (mb, ip);
863 static public InternalParameters LookupParametersByBuilder (MethodBase mb)
865 if (! (mb is ConstructorBuilder || mb is MethodBuilder))
868 if (method_internal_params.Contains (mb))
869 return (InternalParameters) method_internal_params [mb];
871 throw new Exception ("Argument for Method not registered" + mb);
875 /// Returns the argument types for a method based on its methodbase
877 /// For dynamic methods, we use the compiler provided types, for
878 /// methods from existing assemblies we load them from GetParameters,
879 /// and insert them into the cache
881 static public Type [] GetArgumentTypes (MethodBase mb)
883 if (method_arguments.Contains (mb))
884 return (Type []) method_arguments [mb];
886 ParameterInfo [] pi = mb.GetParameters ();
888 Type [] types = new Type [c];
890 for (int i = 0; i < c; i++)
891 types [i] = pi [i].ParameterType;
893 method_arguments.Add (mb, types);
899 // This is a workaround the fact that GetValue is not
900 // supported for dynamic types
902 static Hashtable fields = new Hashtable ();
903 static public bool RegisterFieldValue (FieldBuilder fb, object value)
905 if (fields.Contains (fb))
908 fields.Add (fb, value);
913 static public object GetValue (FieldBuilder fb)
918 static Hashtable fieldbuilders_to_fields = new Hashtable ();
919 static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f)
921 if (fieldbuilders_to_fields.Contains (fb))
924 fieldbuilders_to_fields.Add (fb, f);
928 static public FieldBase GetField (FieldInfo fb)
930 return (FieldBase) fieldbuilders_to_fields [fb];
933 static Hashtable events;
935 static public bool RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
938 events = new Hashtable ();
940 if (events.Contains (eb))
943 events.Add (eb, new Pair (add, remove));
948 static public MethodInfo GetAddMethod (EventInfo ei)
950 if (ei is MyEventBuilder) {
951 Pair pair = (Pair) events [ei];
953 return (MethodInfo) pair.First;
955 return ei.GetAddMethod ();
958 static public MethodInfo GetRemoveMethod (EventInfo ei)
960 if (ei is MyEventBuilder) {
961 Pair pair = (Pair) events [ei];
963 return (MethodInfo) pair.Second;
965 return ei.GetAddMethod ();
968 static Hashtable properties;
970 static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
972 if (properties == null)
973 properties = new Hashtable ();
975 if (properties.Contains (pb))
978 properties.Add (pb, new Pair (get, set));
984 // FIXME: we need to return the accessors depending on whether
985 // they are visible or not.
987 static public MethodInfo [] GetAccessors (PropertyInfo pi)
991 if (pi is PropertyBuilder){
992 Pair pair = (Pair) properties [pi];
994 ret = new MethodInfo [2];
995 ret [0] = (MethodInfo) pair.First;
996 ret [1] = (MethodInfo) pair.Second;
1000 MethodInfo [] mi = new MethodInfo [2];
1003 // Why this and not pi.GetAccessors?
1004 // Because sometimes index 0 is the getter
1005 // sometimes it is 1
1007 mi [0] = pi.GetGetMethod (true);
1008 mi [1] = pi.GetSetMethod (true);
1014 static public MethodInfo GetPropertyGetter (PropertyInfo pi)
1016 if (pi is PropertyBuilder){
1017 Pair de = (Pair) properties [pi];
1019 return (MethodInfo) de.Second;
1021 return pi.GetSetMethod ();
1024 static public MethodInfo GetPropertySetter (PropertyInfo pi)
1026 if (pi is PropertyBuilder){
1027 Pair de = (Pair) properties [pi];
1029 return (MethodInfo) de.First;
1031 return pi.GetGetMethod ();
1035 /// This function returns the interfaces in the type `t'. Works with
1036 /// both types and TypeBuilders.
1038 public static Type [] GetInterfaces (Type t)
1041 // The reason for catching the Array case is that Reflection.Emit
1042 // will not return a TypeBuilder for Array types of TypeBuilder types,
1043 // but will still throw an exception if we try to call GetInterfaces
1046 // Since the array interfaces are always constant, we return those for
1051 t = TypeManager.array_type;
1053 if (t is TypeBuilder)
1054 return (Type []) builder_to_ifaces [t];
1056 return t.GetInterfaces ();
1060 /// The following is used to check if a given type implements an interface.
1061 /// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
1063 public static bool ImplementsInterface (Type t, Type iface)
1068 // FIXME OPTIMIZATION:
1069 // as soon as we hit a non-TypeBuiler in the interface
1070 // chain, we could return, as the `Type.GetInterfaces'
1071 // will return all the interfaces implement by the type
1075 interfaces = GetInterfaces (t);
1077 if (interfaces != null){
1078 foreach (Type i in interfaces){
1085 } while (t != null);
1090 // This is a custom version of Convert.ChangeType() which works
1091 // with the TypeBuilder defined types when compiling corlib.
1092 public static object ChangeType (object value, Type conversionType)
1094 if (!(value is IConvertible))
1095 throw new ArgumentException ();
1097 IConvertible convertValue = (IConvertible) value;
1098 CultureInfo ci = CultureInfo.CurrentCulture;
1099 NumberFormatInfo provider = ci.NumberFormat;
1102 // We must use Type.Equals() here since `conversionType' is
1103 // the TypeBuilder created version of a system type and not
1104 // the system type itself. You cannot use Type.GetTypeCode()
1105 // on such a type - it'd always return TypeCode.Object.
1107 if (conversionType.Equals (typeof (Boolean)))
1108 return (object)(convertValue.ToBoolean (provider));
1109 else if (conversionType.Equals (typeof (Byte)))
1110 return (object)(convertValue.ToByte (provider));
1111 else if (conversionType.Equals (typeof (Char)))
1112 return (object)(convertValue.ToChar (provider));
1113 else if (conversionType.Equals (typeof (DateTime)))
1114 return (object)(convertValue.ToDateTime (provider));
1115 else if (conversionType.Equals (typeof (Decimal)))
1116 return (object)(convertValue.ToDecimal (provider));
1117 else if (conversionType.Equals (typeof (Double)))
1118 return (object)(convertValue.ToDouble (provider));
1119 else if (conversionType.Equals (typeof (Int16)))
1120 return (object)(convertValue.ToInt16 (provider));
1121 else if (conversionType.Equals (typeof (Int32)))
1122 return (object)(convertValue.ToInt32 (provider));
1123 else if (conversionType.Equals (typeof (Int64)))
1124 return (object)(convertValue.ToInt64 (provider));
1125 else if (conversionType.Equals (typeof (SByte)))
1126 return (object)(convertValue.ToSByte (provider));
1127 else if (conversionType.Equals (typeof (Single)))
1128 return (object)(convertValue.ToSingle (provider));
1129 else if (conversionType.Equals (typeof (String)))
1130 return (object)(convertValue.ToString (provider));
1131 else if (conversionType.Equals (typeof (UInt16)))
1132 return (object)(convertValue.ToUInt16 (provider));
1133 else if (conversionType.Equals (typeof (UInt32)))
1134 return (object)(convertValue.ToUInt32 (provider));
1135 else if (conversionType.Equals (typeof (UInt64)))
1136 return (object)(convertValue.ToUInt64 (provider));
1137 else if (conversionType.Equals (typeof (Object)))
1138 return (object)(value);
1140 throw new InvalidCastException ();
1144 // This is needed, because enumerations from assemblies
1145 // do not report their underlyingtype, but they report
1148 public static Type EnumToUnderlying (Type t)
1150 t = t.UnderlyingSystemType;
1151 if (!TypeManager.IsEnumType (t))
1154 TypeCode tc = Type.GetTypeCode (t);
1157 case TypeCode.Boolean:
1158 return TypeManager.bool_type;
1160 return TypeManager.byte_type;
1161 case TypeCode.SByte:
1162 return TypeManager.sbyte_type;
1164 return TypeManager.char_type;
1165 case TypeCode.Int16:
1166 return TypeManager.short_type;
1167 case TypeCode.UInt16:
1168 return TypeManager.ushort_type;
1169 case TypeCode.Int32:
1170 return TypeManager.int32_type;
1171 case TypeCode.UInt32:
1172 return TypeManager.uint32_type;
1173 case TypeCode.Int64:
1174 return TypeManager.int64_type;
1175 case TypeCode.UInt64:
1176 return TypeManager.uint64_type;
1178 throw new Exception ("Unhandled typecode in enum" + tc);
1182 /// Utility function that can be used to probe whether a type
1183 /// is managed or not.
1185 public static bool VerifyUnManaged (Type t, Location loc)
1187 if (t.IsValueType || t.IsPointer){
1189 // FIXME: this is more complex, we actually need to
1190 // make sure that the type does not contain any
1198 "Cannot take the address or size of a variable of a managed type ('" +
1199 CSharpName (t) + "')");
1204 /// Returns the name of the indexer in a given type.
1207 /// The default is not always `Item'. The user can change this behaviour by
1208 /// using the DefaultMemberAttribute in the class.
1210 /// For example, the String class indexer is named `Chars' not `Item'
1212 public static string IndexerPropertyName (Type t)
1215 if (t is TypeBuilder) {
1216 TypeContainer tc = (TypeContainer) builder_to_container [t];
1219 // FIXME: Temporary hack, until we deploy the IndexerName
1220 // property code (and attributes) in the interface code.
1226 return tc.IndexerName;
1229 System.Attribute attr = System.Attribute.GetCustomAttribute (
1230 t, TypeManager.default_member_type);
1232 DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
1233 return dma.MemberName;
1239 public static void MakePinned (LocalBuilder builder)
1242 // FIXME: Flag the "LocalBuilder" type as being
1243 // pinned. Figure out API.
1249 // Returns whether the array of memberinfos contains the given method
1251 static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method)
1253 Type [] new_args = TypeManager.GetArgumentTypes (new_method);
1255 foreach (MethodBase method in array){
1256 if (method.Name != new_method.Name)
1259 Type [] old_args = TypeManager.GetArgumentTypes (method);
1260 int old_count = old_args.Length;
1263 if (new_args.Length != old_count)
1266 for (i = 0; i < old_count; i++){
1267 if (old_args [i] != new_args [i])
1273 if (!(method is MethodInfo && new_method is MethodInfo))
1276 if (((MethodInfo) method).ReturnType == ((MethodInfo) new_method).ReturnType)
1283 // We copy methods from `new_members' into `target_list' if the signature
1284 // for the method from in the new list does not exist in the target_list
1286 // The name is assumed to be the same.
1288 public static ArrayList CopyNewMethods (ArrayList target_list, MemberInfo [] new_members)
1290 if (target_list == null){
1291 target_list = new ArrayList ();
1293 foreach (MemberInfo mi in new_members){
1294 if (mi is MethodBase)
1295 target_list.Add (mi);
1300 MemberInfo [] target_array = new MemberInfo [target_list.Count];
1301 target_list.CopyTo (target_array, 0);
1303 foreach (MemberInfo mi in new_members){
1304 MethodBase new_method = (MethodBase) mi;
1306 if (!ArrayContainsMethod (target_array, new_method))
1307 target_list.Add (new_method);
1312 #region MemberLookup implementation
1315 // Name of the member
1317 static string closure_name;
1320 // Whether we allow private members in the result (since FindMembers
1321 // uses NonPublic for both protected and private), we need to distinguish.
1323 static bool closure_private_ok;
1326 // Who is invoking us and which type is being queried currently.
1328 static Type closure_invocation_type;
1329 static Type closure_queried_type;
1332 // The assembly that defines the type is that is calling us
1334 static Assembly closure_invocation_assembly;
1337 // This filter filters by name + whether it is ok to include private
1338 // members in the search
1340 static internal bool FilterWithClosure (MemberInfo m, object filter_criteria)
1343 // Hack: we know that the filter criteria will always be in the `closure'
1347 if (m.Name != closure_name)
1351 // Ugly: we need to find out the type of `m', and depending
1352 // on this, tell whether we accept or not
1354 if (m is MethodBase){
1355 MethodBase mb = (MethodBase) m;
1356 MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
1358 if (ma == MethodAttributes.Private)
1359 return closure_private_ok;
1362 // FamAndAssem requires that we not only derivate, but we are on the
1365 if (ma == MethodAttributes.FamANDAssem){
1366 if (closure_invocation_assembly != mb.DeclaringType.Assembly)
1370 // FamORAssem, Family and Public:
1374 if (m is FieldInfo){
1375 FieldInfo fi = (FieldInfo) m;
1376 FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
1378 if (fa == FieldAttributes.Private)
1379 return closure_private_ok;
1382 // FamAndAssem requires that we not only derivate, but we are on the
1385 if (fa == FieldAttributes.FamANDAssem){
1386 if (closure_invocation_assembly != fi.DeclaringType.Assembly)
1389 // FamORAssem, Family and Public:
1394 // EventInfos and PropertyInfos, return true
1399 static MemberFilter FilterWithClosure_delegate = new MemberFilter (FilterWithClosure);
1402 // Looks up a member called `name' in the `queried_type'. This lookup
1403 // is done by code that is contained in the definition for `invocation_type'.
1405 // The binding flags are `bf' and the kind of members being looked up are `mt'
1407 // Returns an array of a single element for everything but Methods/Constructors
1408 // that might return multiple matches.
1410 public static MemberInfo [] MemberLookup (Type invocation_type, Type queried_type,
1411 MemberTypes mt, BindingFlags original_bf, string name)
1413 BindingFlags bf = original_bf;
1415 ArrayList method_list = null;
1416 Type current_type = queried_type;
1417 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
1419 bool always_ok_flag = false;
1421 closure_name = name;
1422 closure_invocation_type = invocation_type;
1423 closure_invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
1426 // If we are a nested class, we always have access to our container
1429 if (invocation_type != null){
1430 string invocation_name = invocation_type.FullName;
1431 if (invocation_name.IndexOf ('+') != -1){
1432 string container = queried_type.FullName + "+";
1433 int container_length = container.Length;
1435 if (invocation_name.Length > container_length){
1436 string shared = invocation_name.Substring (0, container_length);
1438 if (shared == container)
1439 always_ok_flag = true;
1448 // `NonPublic' is lame, because it includes both protected and
1449 // private methods, so we need to control this behavior by
1450 // explicitly tracking if a private method is ok or not.
1452 // The possible cases are:
1453 // public, private and protected (internal does not come into the
1456 if (invocation_type != null){
1457 if (invocation_type == current_type){
1460 private_ok = always_ok_flag;
1462 if (private_ok || invocation_type.IsSubclassOf (current_type))
1463 bf = original_bf | BindingFlags.NonPublic;
1466 bf = original_bf & ~BindingFlags.NonPublic;
1469 closure_private_ok = private_ok;
1470 closure_queried_type = current_type;
1472 mi = TypeManager.FindMembers (
1473 current_type, mt, bf | BindingFlags.DeclaredOnly,
1474 FilterWithClosure_delegate, name);
1476 if (current_type == TypeManager.object_type)
1479 current_type = current_type.BaseType;
1482 // This happens with interfaces, they have a null
1483 // basetype. Look members up in the Object class.
1485 if (current_type == null)
1486 current_type = TypeManager.object_type;
1492 int count = mi.Length;
1498 // Events and types are returned by both `static' and `instance'
1499 // searches, which means that our above FindMembers will
1500 // return two copies of the same.
1502 if (count == 1 && !(mi [0] is MethodBase)){
1507 // Multiple properties: we query those just to find out the indexer
1510 if (mi [0] is PropertyInfo)
1514 // We found methods, turn the search into "method scan"
1518 method_list = CopyNewMethods (method_list, mi);
1519 mt &= (MemberTypes.Method | MemberTypes.Constructor);
1520 } while (searching);
1522 if (method_list != null && method_list.Count > 0)
1523 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
1526 // Interfaces do not list members they inherit, so we have to
1529 if (!queried_type.IsInterface)
1532 if (queried_type.IsArray)
1533 queried_type = TypeManager.array_type;
1535 Type [] ifaces = GetInterfaces (queried_type);
1539 foreach (Type itype in ifaces){
1542 x = MemberLookup (null, itype, mt, bf, name);