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.Collections;
16 using System.Reflection;
17 using System.Reflection.Emit;
18 using System.Text.RegularExpressions;
19 using System.Runtime.CompilerServices;
21 namespace Mono.CSharp {
23 public class TypeManager {
25 // A list of core types that the compiler requires or uses
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;
73 static public Type [] NoTypes;
76 // Internal, not really used outside
78 static Type runtime_helpers_type;
81 // These methods are called by code generated by the compiler
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;
100 // The attribute constructors.
102 static public ConstructorInfo cons_param_array_attribute;
103 static public ConstructorInfo void_decimal_ctor_five_args;
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)
110 static Assembly [] assemblies;
113 // Keeps a list of module builders. We used this to do lookups
114 // on the modulebuilder using GetType -- needed for arrays
116 static ModuleBuilder [] modules;
119 // This is the type_cache from the assemblies to avoid
120 // hitting System.Reflection on every lookup.
122 static Hashtable types;
125 // This is used to hotld the corresponding TypeContainer objects
126 // since we need this in FindMembers
128 static Hashtable typecontainers;
131 // Keeps track of those types that are defined by the
134 static ArrayList user_types;
137 // Keeps a mapping between TypeBuilders and their TypeContainers
139 static PtrHashtable builder_to_container;
142 // Tracks the interfaces implemented by typebuilders. We only
143 // enter those who do implement or or more interfaces
145 static PtrHashtable builder_to_ifaces;
148 // Maps MethodBase.RuntimeTypeHandle to a Type array that contains
149 // the arguments to the method
151 static Hashtable method_arguments;
154 // Maybe `method_arguments' should be replaced and only
155 // method_internal_params should be kept?
157 static Hashtable method_internal_params;
159 static PtrHashtable builder_to_interface;
162 // Keeps track of delegate types
165 static Hashtable builder_to_delegate;
168 // Keeps track of enum types
171 static Hashtable builder_to_enum;
174 // Keeps track of attribute types
177 static Hashtable builder_to_attr;
185 /// A filter for Findmembers that uses the Signature object to
188 static bool SignatureFilter (MemberInfo mi, object criteria)
190 Signature sig = (Signature) criteria;
192 if (!(mi is MethodBase))
195 if (mi.Name != sig.name)
198 int count = sig.args.Length;
200 if (mi is MethodBuilder || mi is ConstructorBuilder){
201 Type [] candidate_args = GetArgumentTypes ((MethodBase) mi);
203 if (candidate_args.Length != count)
206 for (int i = 0; i < count; i++)
207 if (candidate_args [i] != sig.args [i])
212 ParameterInfo [] pars = ((MethodBase) mi).GetParameters ();
214 if (pars.Length != count)
217 for (int i = 0; i < count; i++)
218 if (pars [i].ParameterType != sig.args [i])
224 // A delegate that points to the filter above.
225 static MemberFilter signature_filter;
227 static TypeManager ()
229 assemblies = new Assembly [0];
231 user_types = new ArrayList ();
233 types = new Hashtable ();
234 typecontainers = new Hashtable ();
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 ();
245 NoTypes = new Type [0];
247 signature_filter = new MemberFilter (SignatureFilter);
250 public static void AddUserType (string name, TypeBuilder t, Type [] ifaces)
255 Type prev = (Type) types [name];
256 TypeContainer tc = (TypeContainer) builder_to_container [prev];
260 // This probably never happens, as we catch this before
262 Report.Error (-17, "The type `" + name + "' has already been defined.");
266 tc = (TypeContainer) builder_to_container [t];
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);
279 builder_to_ifaces [t] = ifaces;
283 // This entry point is used by types that we define under the covers
285 public static void RegisterBuilder (TypeBuilder tb, Type [] ifaces)
288 builder_to_ifaces [tb] = ifaces;
291 public static void AddUserType (string name, TypeBuilder t, TypeContainer tc, Type [] ifaces)
293 builder_to_container.Add (t, tc);
294 typecontainers.Add (name, tc);
295 AddUserType (name, t, ifaces);
298 public static void AddDelegateType (string name, TypeBuilder t, Delegate del)
301 builder_to_delegate.Add (t, del);
304 public static void AddEnumType (string name, TypeBuilder t, Enum en)
307 builder_to_enum.Add (t, en);
310 public static void AddUserInterface (string name, TypeBuilder t, Interface i, Type [] ifaces)
312 AddUserType (name, t, ifaces);
313 builder_to_interface.Add (t, i);
316 public static void RegisterAttrType (Type t, TypeContainer tc)
318 builder_to_attr.Add (t, tc);
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)
325 public static TypeContainer LookupTypeContainer (Type t)
327 return (TypeContainer) builder_to_container [t];
330 public static Interface LookupInterface (Type t)
332 return (Interface) builder_to_interface [t];
335 public static Delegate LookupDelegate (Type t)
337 return (Delegate) builder_to_delegate [t];
340 public static Enum LookupEnum (Type t)
342 return (Enum) builder_to_enum [t];
345 public static TypeContainer LookupAttr (Type t)
347 return (TypeContainer) builder_to_attr [t];
351 /// Registers an assembly to load types from.
353 public static void AddAssembly (Assembly a)
355 int top = assemblies.Length;
356 Assembly [] n = new Assembly [top + 1];
358 assemblies.CopyTo (n, 0);
365 /// Registers a module builder to lookup types from
367 public static void AddModule (ModuleBuilder mb)
369 int top = modules != null ? modules.Length : 0;
370 ModuleBuilder [] n = new ModuleBuilder [top + 1];
373 modules.CopyTo (n, 0);
379 /// Returns the Type associated with @name
381 public static Type LookupType (string name)
386 // First lookup in user defined and cached values
389 t = (Type) types [name];
393 foreach (Assembly a in assemblies){
394 t = a.GetType (name);
402 foreach (ModuleBuilder mb in modules) {
403 t = mb.GetType (name);
414 /// Returns the C# name of a type if possible, or the full type name otherwise
416 static public string CSharpName (Type t)
418 return Regex.Replace (t.FullName,
420 @"(Int32|UInt32|Int16|Uint16|Int64|UInt64|" +
421 @"Single|Double|Char|Decimal|Byte|SByte|Object|" +
422 @"Boolean|String|Void)" +
424 new MatchEvaluator (CSharpNameMatch));
427 static String CSharpNameMatch (Match match)
429 string s = match.Groups [1].Captures [0].Value;
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;
443 /// Returns the signature of the method
445 static public string CSharpSignature (MethodBase mb)
450 // FIXME: We should really have a single function to do
451 // everything instead of the following 5 line pattern
453 ParameterData iparams = LookupParametersByBuilder (mb);
455 if (iparams == null){
456 ParameterInfo [] pi = mb.GetParameters ();
457 iparams = new ReflectionParameters (pi);
460 for (int i = 0; i < iparams.Count; i++) {
464 sig += iparams.ParameterDesc(i);
468 return mb.DeclaringType.Name + "." + mb.Name + sig;
472 /// Looks up a type, and aborts if it is not found. This is used
473 /// by types required by the compiler
475 static Type CoreLookupType (string name)
477 Type t = LookupType (name);
480 Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
481 Environment.Exit (0);
488 /// Returns the MethodInfo for a method named `name' defined
489 /// in type `t' which takes arguments of types `args'
491 static MethodInfo GetMethod (Type t, string name, Type [] args)
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 + "'");
507 return (MethodInfo) mi [0];
511 /// Returns the ConstructorInfo for "args"
513 static ConstructorInfo GetConstructor (Type t, Type [] args)
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 + "'");
528 return (ConstructorInfo) mi [0];
531 public static void InitEnumUnderlyingTypes ()
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");
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
549 public static void InitCoreTypes ()
551 object_type = CoreLookupType ("System.Object");
552 value_type = CoreLookupType ("System.ValueType");
554 InitEnumUnderlyingTypes ();
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");
565 multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
566 delegate_type = CoreLookupType ("System.Delegate");
568 array_type = CoreLookupType ("System.Array");
569 void_type = CoreLookupType ("System.Void");
570 type_type = CoreLookupType ("System.Type");
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");
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");
591 unverifiable_code_type= CoreLookupType ("System.Security.UnverifiableCodeAttribute");
593 void_ptr_type = CoreLookupType ("System.Void*");
595 indexer_name_type = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute");
596 trace_type = CoreLookupType ("System.Diagnostics.Trace");
597 debug_type = CoreLookupType ("System.Diagnostics.Debug");
601 // The helper methods that are used by the compiler
603 public static void InitCodeHelpers ()
606 // Now load the default methods that we use.
608 Type [] string_string = { string_type, string_type };
609 string_concat_string_string = GetMethod (
610 string_type, "Concat", string_string);
612 Type [] object_object = { object_type, object_type };
613 string_concat_object_object = GetMethod (
614 string_type, "Concat", object_object);
616 Type [] string_ = { string_type };
617 string_isinterneted_string = GetMethod (
618 string_type, "IsInterned", string_);
620 Type [] runtime_type_handle = { runtime_handle_type };
621 system_type_get_type_from_handle = GetMethod (
622 type_type, "GetTypeFromHandle", runtime_type_handle);
624 Type [] delegate_delegate = { delegate_type, delegate_type };
625 delegate_combine_delegate_delegate = GetMethod (
626 delegate_type, "Combine", delegate_delegate);
628 delegate_remove_delegate_delegate = GetMethod (
629 delegate_type, "Remove", delegate_delegate);
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);
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);
655 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
657 void_initializearray_array_fieldhandle = GetMethod (
658 runtime_helpers_type, "InitializeArray", array_field_handle_arg);
663 Type [] int_arg = { int32_type };
664 int_getlength_int = GetMethod (
665 array_type, "GetLength", int_arg);
668 // Decimal constructors
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);
677 cons_param_array_attribute = GetConstructor (
678 param_array_type, void_arg);
682 const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
685 // FIXME: This can be optimized easily. speedup by having a single builder mapping
687 public static MemberInfo [] FindMembers (Type t, MemberTypes mt, BindingFlags bf,
688 MemberFilter filter, object criteria)
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.
695 if (t.IsSubclassOf (TypeManager.array_type))
696 return TypeManager.array_type.FindMembers (mt, bf, filter, criteria);
698 if (!(t is TypeBuilder)){
700 // Since FindMembers will not lookup both static and instance
701 // members, we emulate this behaviour here.
703 if ((bf & instance_and_static) == instance_and_static){
704 MemberInfo [] i_members = t.FindMembers (
705 mt, bf & ~BindingFlags.Static, filter, criteria);
707 int i_len = i_members.Length;
709 MemberInfo one = i_members [0];
712 // If any of these are present, we are done!
714 if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
718 MemberInfo [] s_members = t.FindMembers (
719 mt, bf & ~BindingFlags.Instance, filter, criteria);
721 int s_len = s_members.Length;
722 if (i_len > 0 || s_len > 0){
723 MemberInfo [] both = new MemberInfo [i_len + s_len];
725 i_members.CopyTo (both, 0);
726 s_members.CopyTo (both, i_len);
736 return t.FindMembers (mt, bf, filter, criteria);
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
744 Enum e = (Enum) builder_to_enum [t];
747 return e.FindMembers (mt, bf, filter, criteria);
749 Delegate del = (Delegate) builder_to_delegate [t];
752 return del.FindMembers (mt, bf, filter, criteria);
754 Interface iface = (Interface) builder_to_interface [t];
757 return iface.FindMembers (mt, bf, filter, criteria);
759 TypeContainer tc = (TypeContainer) builder_to_container [t];
762 return tc.FindMembers (mt, bf, filter, criteria);
767 public static bool IsBuiltinType (Type t)
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)
778 public static bool IsDelegateType (Type t)
780 if (t.IsSubclassOf (TypeManager.delegate_type))
786 public static bool IsEnumType (Type t)
788 if (t.IsSubclassOf (TypeManager.enum_type))
794 public static bool IsInterfaceType (Type t)
796 Interface iface = (Interface) builder_to_interface [t];
805 /// Returns the User Defined Types
807 public static ArrayList UserTypes {
813 public static Hashtable TypeContainers {
815 return typecontainers;
819 static Hashtable builder_to_constant;
821 public static void RegisterConstant (FieldBuilder fb, Const c)
823 if (builder_to_constant == null)
824 builder_to_constant = new PtrHashtable ();
826 if (builder_to_constant.Contains (fb))
829 builder_to_constant.Add (fb, c);
832 public static Const LookupConstant (FieldBuilder fb)
834 if (builder_to_constant == null)
837 return (Const) builder_to_constant [fb];
841 /// Gigantic work around for missing features in System.Reflection.Emit follows.
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.
849 static public bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
854 method_arguments.Add (mb, args);
855 method_internal_params.Add (mb, ip);
860 static public InternalParameters LookupParametersByBuilder (MethodBase mb)
862 if (! (mb is ConstructorBuilder || mb is MethodBuilder))
865 if (method_internal_params.Contains (mb))
866 return (InternalParameters) method_internal_params [mb];
868 throw new Exception ("Argument for Method not registered" + mb);
872 /// Returns the argument types for a method based on its methodbase
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
878 static public Type [] GetArgumentTypes (MethodBase mb)
880 if (method_arguments.Contains (mb))
881 return (Type []) method_arguments [mb];
883 ParameterInfo [] pi = mb.GetParameters ();
885 Type [] types = new Type [c];
887 for (int i = 0; i < c; i++)
888 types [i] = pi [i].ParameterType;
890 method_arguments.Add (mb, types);
896 // This is a workaround the fact that GetValue is not
897 // supported for dynamic types
899 static Hashtable fields = new Hashtable ();
900 static public bool RegisterFieldValue (FieldBuilder fb, object value)
902 if (fields.Contains (fb))
905 fields.Add (fb, value);
910 static public object GetValue (FieldBuilder fb)
915 static Hashtable fieldbuilders_to_fields = new Hashtable ();
916 static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f)
918 if (fieldbuilders_to_fields.Contains (fb))
921 fieldbuilders_to_fields.Add (fb, f);
925 static public FieldBase GetField (FieldInfo fb)
927 return (FieldBase) fieldbuilders_to_fields [fb];
930 static Hashtable events;
932 static public bool RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
935 events = new Hashtable ();
937 if (events.Contains (eb))
940 events.Add (eb, new Pair (add, remove));
945 static public MethodInfo GetAddMethod (EventInfo ei)
947 if (ei is MyEventBuilder) {
948 Pair pair = (Pair) events [ei];
950 return (MethodInfo) pair.First;
952 return ei.GetAddMethod ();
955 static public MethodInfo GetRemoveMethod (EventInfo ei)
957 if (ei is MyEventBuilder) {
958 Pair pair = (Pair) events [ei];
960 return (MethodInfo) pair.Second;
962 return ei.GetAddMethod ();
965 static Hashtable properties;
967 static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
969 if (properties == null)
970 properties = new Hashtable ();
972 if (properties.Contains (pb))
975 properties.Add (pb, new Pair (get, set));
981 // FIXME: we need to return the accessors depending on whether
982 // they are visible or not.
984 static public MethodInfo [] GetAccessors (PropertyInfo pi)
988 if (pi is PropertyBuilder){
989 Pair pair = (Pair) properties [pi];
991 ret = new MethodInfo [2];
992 ret [0] = (MethodInfo) pair.First;
993 ret [1] = (MethodInfo) pair.Second;
997 MethodInfo [] mi = new MethodInfo [2];
1000 // Why this and not pi.GetAccessors?
1001 // Because sometimes index 0 is the getter
1002 // sometimes it is 1
1004 mi [0] = pi.GetGetMethod (true);
1005 mi [1] = pi.GetSetMethod (true);
1011 static public MethodInfo GetPropertyGetter (PropertyInfo pi)
1013 if (pi is PropertyBuilder){
1014 Pair de = (Pair) properties [pi];
1016 return (MethodInfo) de.Second;
1018 return pi.GetSetMethod ();
1021 static public MethodInfo GetPropertySetter (PropertyInfo pi)
1023 if (pi is PropertyBuilder){
1024 Pair de = (Pair) properties [pi];
1026 return (MethodInfo) de.First;
1028 return pi.GetGetMethod ();
1032 /// This function returns the interfaces in the type `t'. Works with
1033 /// both types and TypeBuilders.
1035 public static Type [] GetInterfaces (Type t)
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
1043 // Since the array interfaces are always constant, we return those for
1048 t = TypeManager.array_type;
1050 if (t is TypeBuilder)
1051 return (Type []) builder_to_ifaces [t];
1053 return t.GetInterfaces ();
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.
1060 public static bool ImplementsInterface (Type t, Type iface)
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
1072 interfaces = GetInterfaces (t);
1074 if (interfaces != null){
1075 foreach (Type i in interfaces){
1082 } while (t != null);
1088 // This is needed, because enumerations from assemblies
1089 // do not report their underlyingtype, but they report
1092 public static Type EnumToUnderlying (Type t)
1094 t = t.UnderlyingSystemType;
1095 if (!TypeManager.IsEnumType (t))
1098 TypeCode tc = Type.GetTypeCode (t);
1101 case TypeCode.Boolean:
1102 return TypeManager.bool_type;
1104 return TypeManager.byte_type;
1105 case TypeCode.SByte:
1106 return TypeManager.sbyte_type;
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;
1122 throw new Exception ("Unhandled typecode in enum" + tc);
1126 /// Utility function that can be used to probe whether a type
1127 /// is managed or not.
1129 public static bool VerifyUnManaged (Type t, Location loc)
1133 // FIXME: this is more complex, we actually need to
1134 // make sure that the type does not contain any
1142 "Cannot take the address or size of a variable of a managed type ('" +
1143 CSharpName (t) + "')");
1148 /// Returns the name of the indexer in a given type.
1151 /// The default is not always `Item'. The user can change this behaviour by
1152 /// using the DefaultMemberAttribute in the class.
1154 /// For example, the String class indexer is named `Chars' not `Item'
1156 public static string IndexerPropertyName (Type t)
1159 if (t is TypeBuilder) {
1160 TypeContainer tc = (TypeContainer) builder_to_container [t];
1163 // FIXME: Temporary hack, until we deploy the IndexerName
1164 // property code (and attributes) in the interface code.
1170 return tc.IndexerName;
1173 System.Attribute attr = System.Attribute.GetCustomAttribute (
1174 t, TypeManager.default_member_type);
1176 DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
1177 return dma.MemberName;
1183 public static void MakePinned (LocalBuilder builder)
1186 // FIXME: Flag the "LocalBuilder" type as being
1187 // pinned. Figure out API.
1193 // Returns whether the array of memberinfos contains the given method
1195 static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method)
1197 Type [] new_args = TypeManager.GetArgumentTypes (new_method);
1199 foreach (MethodBase method in array){
1200 if (method.Name != new_method.Name)
1203 Type [] old_args = TypeManager.GetArgumentTypes (method);
1204 int old_count = old_args.Length;
1207 if (new_args.Length != old_count)
1210 for (i = 0; i < old_count; i++){
1211 if (old_args [i] != new_args [i])
1217 if (!(method is MethodInfo && new_method is MethodInfo))
1220 if (((MethodInfo) method).ReturnType == ((MethodInfo) new_method).ReturnType)
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
1230 // The name is assumed to be the same.
1232 public static ArrayList CopyNewMethods (ArrayList target_list, MemberInfo [] new_members)
1234 if (target_list == null){
1235 target_list = new ArrayList ();
1237 foreach (MemberInfo mi in new_members){
1238 if (mi is MethodBase)
1239 target_list.Add (mi);
1244 MemberInfo [] target_array = new MemberInfo [target_list.Count];
1245 target_list.CopyTo (target_array, 0);
1247 foreach (MemberInfo mi in new_members){
1248 MethodBase new_method = (MethodBase) mi;
1250 if (!ArrayContainsMethod (target_array, new_method))
1251 target_list.Add (new_method);
1256 #region MemberLookup implementation
1259 // Name of the member
1261 static string closure_name;
1264 // Whether we allow private members in the result (since FindMembers
1265 // uses NonPublic for both protected and private), we need to distinguish.
1267 static bool closure_private_ok;
1270 // Who is invoking us and which type is being queried currently.
1272 static Type closure_invocation_type;
1273 static Type closure_queried_type;
1276 // The assembly that defines the type is that is calling us
1278 static Assembly closure_invocation_assembly;
1281 // This filter filters by name + whether it is ok to include private
1282 // members in the search
1284 static internal bool FilterWithClosure (MemberInfo m, object filter_criteria)
1287 // Hack: we know that the filter criteria will always be in the `closure'
1291 if (m.Name != closure_name)
1295 // Ugly: we need to find out the type of `m', and depending
1296 // on this, tell whether we accept or not
1298 if (m is MethodBase){
1299 MethodBase mb = (MethodBase) m;
1300 MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
1302 if (ma == MethodAttributes.Private)
1303 return closure_private_ok;
1306 // FamAndAssem requires that we not only derivate, but we are on the
1309 if (ma == MethodAttributes.FamANDAssem){
1310 if (closure_invocation_assembly != mb.DeclaringType.Assembly)
1314 // FamORAssem, Family and Public:
1318 if (m is FieldInfo){
1319 FieldInfo fi = (FieldInfo) m;
1320 FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
1322 if (fa == FieldAttributes.Private)
1323 return closure_private_ok;
1326 // FamAndAssem requires that we not only derivate, but we are on the
1329 if (fa == FieldAttributes.FamANDAssem){
1330 if (closure_invocation_assembly != fi.DeclaringType.Assembly)
1333 // FamORAssem, Family and Public:
1338 // EventInfos and PropertyInfos, return true
1343 static MemberFilter FilterWithClosure_delegate = new MemberFilter (FilterWithClosure);
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'.
1349 // The binding flags are `bf' and the kind of members being looked up are `mt'
1351 // Returns an array of a single element for everything but Methods/Constructors
1352 // that might return multiple matches.
1354 public static MemberInfo [] MemberLookup (Type invocation_type, Type queried_type,
1355 MemberTypes mt, BindingFlags original_bf, string name)
1357 BindingFlags bf = original_bf;
1359 ArrayList method_list = null;
1360 Type current_type = queried_type;
1361 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
1363 bool always_ok_flag = false;
1365 closure_name = name;
1366 closure_invocation_type = invocation_type;
1367 closure_invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
1370 // If we are a nested class, we always have access to our container
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;
1379 if (invocation_name.Length > container_length){
1380 string shared = invocation_name.Substring (0, container_length);
1382 if (shared == container)
1383 always_ok_flag = true;
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.
1396 // The possible cases are:
1397 // public, private and protected (internal does not come into the
1400 if (invocation_type != null){
1401 if (invocation_type == current_type){
1404 private_ok = always_ok_flag;
1406 if (private_ok || invocation_type.IsSubclassOf (current_type))
1407 bf = original_bf | BindingFlags.NonPublic;
1410 bf = original_bf & ~BindingFlags.NonPublic;
1413 closure_private_ok = private_ok;
1414 closure_queried_type = current_type;
1416 mi = TypeManager.FindMembers (
1417 current_type, mt, bf | BindingFlags.DeclaredOnly,
1418 FilterWithClosure_delegate, name);
1420 if (current_type == TypeManager.object_type)
1423 current_type = current_type.BaseType;
1426 // This happens with interfaces, they have a null
1427 // basetype. Look members up in the Object class.
1429 if (current_type == null)
1430 current_type = TypeManager.object_type;
1436 int count = mi.Length;
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.
1446 if (count == 1 && !(mi [0] is MethodBase)){
1451 // Multiple properties: we query those just to find out the indexer
1454 if (mi [0] is PropertyInfo)
1458 // We found methods, turn the search into "method scan"
1462 method_list = CopyNewMethods (method_list, mi);
1463 mt &= (MemberTypes.Method | MemberTypes.Constructor);
1464 } while (searching);
1466 if (method_list != null && method_list.Count > 0)
1467 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
1470 // Interfaces do not list members they inherit, so we have to
1473 if (!queried_type.IsInterface)
1476 if (queried_type.IsArray)
1477 queried_type = TypeManager.array_type;
1479 Type [] ifaces = GetInterfaces (queried_type);
1483 foreach (Type itype in ifaces){
1486 x = MemberLookup (null, itype, mt, bf, name);