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)
13 using System.Globalization;
14 using System.Collections;
15 using System.Reflection;
16 using System.Reflection.Emit;
17 using System.Text.RegularExpressions;
18 using System.Runtime.CompilerServices;
19 using System.Diagnostics;
21 namespace Mono.CSharp {
24 /// This is a readonly list of MemberInfo's.
26 public class MemberList : IList {
27 public readonly IList List;
31 /// Create a new MemberList from the given IList.
33 public MemberList (IList list)
38 this.List = new ArrayList ();
43 /// Concatenate the ILists `first' and `second' to a new MemberList.
45 public MemberList (IList first, IList second)
47 ArrayList list = new ArrayList ();
48 list.AddRange (first);
49 list.AddRange (second);
54 public static readonly MemberList Empty = new MemberList (new ArrayList ());
56 public static explicit operator MemberInfo [] (MemberList list)
58 Timer.StartTimer (TimerType.MiscTimer);
59 MemberInfo [] result = new MemberInfo [list.Count];
60 list.CopyTo (result, 0);
61 Timer.StopTimer (TimerType.MiscTimer);
73 public bool IsSynchronized {
75 return List.IsSynchronized;
79 public object SyncRoot {
85 public void CopyTo (Array array, int index)
87 List.CopyTo (array, index);
92 public IEnumerator GetEnumerator ()
94 return List.GetEnumerator ();
99 public bool IsFixedSize {
105 public bool IsReadOnly {
111 object IList.this [int index] {
117 throw new NotSupportedException ();
121 // FIXME: try to find out whether we can avoid the cast in this indexer.
122 public MemberInfo this [int index] {
124 return (MemberInfo) List [index];
128 public int Add (object value)
130 throw new NotSupportedException ();
135 throw new NotSupportedException ();
138 public bool Contains (object value)
140 return List.Contains (value);
143 public int IndexOf (object value)
145 return List.IndexOf (value);
148 public void Insert (int index, object value)
150 throw new NotSupportedException ();
153 public void Remove (object value)
155 throw new NotSupportedException ();
158 public void RemoveAt (int index)
160 throw new NotSupportedException ();
164 public interface IMemberFinder {
165 MemberList FindMembers (MemberTypes mt, BindingFlags bf,
166 MemberFilter filter, object criteria);
168 MemberCache MemberCache {
173 public interface IMemberContainer : IMemberFinder {
182 IMemberContainer Parent {
190 MemberList GetMembers (MemberTypes mt, BindingFlags bf);
193 public class TypeManager {
195 // A list of core types that the compiler requires or uses
197 static public Type object_type;
198 static public Type value_type;
199 static public Type string_type;
200 static public Type int32_type;
201 static public Type uint32_type;
202 static public Type int64_type;
203 static public Type uint64_type;
204 static public Type float_type;
205 static public Type double_type;
206 static public Type char_type;
207 static public Type char_ptr_type;
208 static public Type short_type;
209 static public Type decimal_type;
210 static public Type bool_type;
211 static public Type sbyte_type;
212 static public Type byte_type;
213 static public Type ushort_type;
214 static public Type enum_type;
215 static public Type delegate_type;
216 static public Type multicast_delegate_type;
217 static public Type void_type;
218 static public Type enumeration_type;
219 static public Type array_type;
220 static public Type runtime_handle_type;
221 static public Type icloneable_type;
222 static public Type type_type;
223 static public Type ienumerator_type;
224 static public Type idisposable_type;
225 static public Type default_member_type;
226 static public Type iasyncresult_type;
227 static public Type asynccallback_type;
228 static public Type intptr_type;
229 static public Type monitor_type;
230 static public Type runtime_field_handle_type;
231 static public Type attribute_type;
232 static public Type attribute_usage_type;
233 static public Type dllimport_type;
234 static public Type unverifiable_code_type;
235 static public Type methodimpl_attr_type;
236 static public Type marshal_as_attr_type;
237 static public Type param_array_type;
238 static public Type void_ptr_type;
239 static public Type indexer_name_type;
240 static public Type exception_type;
241 static public object obsolete_attribute_type;
242 static public object conditional_attribute_type;
245 // An empty array of types
247 static public Type [] NoTypes;
251 // Expressions representing the internal types. Used during declaration
254 static public Expression system_object_expr, system_string_expr;
255 static public Expression system_boolean_expr, system_decimal_expr;
256 static public Expression system_single_expr, system_double_expr;
257 static public Expression system_sbyte_expr, system_byte_expr;
258 static public Expression system_int16_expr, system_uint16_expr;
259 static public Expression system_int32_expr, system_uint32_expr;
260 static public Expression system_int64_expr, system_uint64_expr;
261 static public Expression system_char_expr, system_void_expr;
262 static public Expression system_asynccallback_expr;
263 static public Expression system_iasyncresult_expr;
266 // This is only used when compiling corlib
268 static public Type system_int32_type;
269 static public Type system_array_type;
270 static public Type system_type_type;
271 static public Type system_assemblybuilder_type;
272 static public MethodInfo system_int_array_get_length;
273 static public MethodInfo system_int_array_get_rank;
274 static public MethodInfo system_object_array_clone;
275 static public MethodInfo system_int_array_get_length_int;
276 static public MethodInfo system_int_array_get_lower_bound_int;
277 static public MethodInfo system_int_array_get_upper_bound_int;
278 static public MethodInfo system_void_array_copyto_array_int;
279 static public MethodInfo system_void_set_corlib_type_builders;
283 // Internal, not really used outside
285 static Type runtime_helpers_type;
288 // These methods are called by code generated by the compiler
290 static public MethodInfo string_concat_string_string;
291 static public MethodInfo string_concat_object_object;
292 static public MethodInfo string_isinterneted_string;
293 static public MethodInfo system_type_get_type_from_handle;
294 static public MethodInfo object_getcurrent_void;
295 static public MethodInfo bool_movenext_void;
296 static public MethodInfo void_dispose_void;
297 static public MethodInfo void_monitor_enter_object;
298 static public MethodInfo void_monitor_exit_object;
299 static public MethodInfo void_initializearray_array_fieldhandle;
300 static public MethodInfo int_getlength_int;
301 static public MethodInfo delegate_combine_delegate_delegate;
302 static public MethodInfo delegate_remove_delegate_delegate;
303 static public MethodInfo int_get_offset_to_string_data;
304 static public MethodInfo int_array_get_length;
305 static public MethodInfo int_array_get_rank;
306 static public MethodInfo object_array_clone;
307 static public MethodInfo int_array_get_length_int;
308 static public MethodInfo int_array_get_lower_bound_int;
309 static public MethodInfo int_array_get_upper_bound_int;
310 static public MethodInfo void_array_copyto_array_int;
313 // The attribute constructors.
315 static public ConstructorInfo cons_param_array_attribute;
316 static public ConstructorInfo void_decimal_ctor_five_args;
317 static public ConstructorInfo unverifiable_code_ctor;
320 // Holds the Array of Assemblies that have been loaded
321 // (either because it is the default or the user used the
322 // -r command line option)
324 static Assembly [] assemblies;
327 // Keeps a list of module builders. We used this to do lookups
328 // on the modulebuilder using GetType -- needed for arrays
330 static ModuleBuilder [] modules;
333 // This is the type_cache from the assemblies to avoid
334 // hitting System.Reflection on every lookup.
336 static Hashtable types;
339 // This is used to hotld the corresponding TypeContainer objects
340 // since we need this in FindMembers
342 static Hashtable typecontainers;
345 // Keeps track of those types that are defined by the
348 static ArrayList user_types;
350 static PtrHashtable builder_to_member_finder;
353 // Tracks the interfaces implemented by typebuilders. We only
354 // enter those who do implement or or more interfaces
356 static PtrHashtable builder_to_ifaces;
359 // Maps MethodBase.RuntimeTypeHandle to a Type array that contains
360 // the arguments to the method
362 static Hashtable method_arguments;
365 // Maps PropertyBuilder to a Type array that contains
366 // the arguments to the indexer
368 static Hashtable indexer_arguments;
371 // Maybe `method_arguments' should be replaced and only
372 // method_internal_params should be kept?
374 static Hashtable method_internal_params;
377 // Keeps track of attribute types
380 static Hashtable builder_to_attr;
383 // Keeps track of methods
386 static Hashtable builder_to_method;
394 /// A filter for Findmembers that uses the Signature object to
397 static bool SignatureFilter (MemberInfo mi, object criteria)
399 Signature sig = (Signature) criteria;
401 if (!(mi is MethodBase))
404 if (mi.Name != sig.name)
407 int count = sig.args.Length;
409 if (mi is MethodBuilder || mi is ConstructorBuilder){
410 Type [] candidate_args = GetArgumentTypes ((MethodBase) mi);
412 if (candidate_args.Length != count)
415 for (int i = 0; i < count; i++)
416 if (candidate_args [i] != sig.args [i])
421 ParameterInfo [] pars = ((MethodBase) mi).GetParameters ();
423 if (pars.Length != count)
426 for (int i = 0; i < count; i++)
427 if (pars [i].ParameterType != sig.args [i])
433 // A delegate that points to the filter above.
434 static MemberFilter signature_filter;
437 // These are expressions that represent some of the internal data types, used
440 static void InitExpressionTypes ()
442 system_object_expr = new TypeLookupExpression ("System.Object");
443 system_string_expr = new TypeLookupExpression ("System.String");
444 system_boolean_expr = new TypeLookupExpression ("System.Boolean");
445 system_decimal_expr = new TypeLookupExpression ("System.Decimal");
446 system_single_expr = new TypeLookupExpression ("System.Single");
447 system_double_expr = new TypeLookupExpression ("System.Double");
448 system_sbyte_expr = new TypeLookupExpression ("System.SByte");
449 system_byte_expr = new TypeLookupExpression ("System.Byte");
450 system_int16_expr = new TypeLookupExpression ("System.Int16");
451 system_uint16_expr = new TypeLookupExpression ("System.UInt16");
452 system_int32_expr = new TypeLookupExpression ("System.Int32");
453 system_uint32_expr = new TypeLookupExpression ("System.UInt32");
454 system_int64_expr = new TypeLookupExpression ("System.Int64");
455 system_uint64_expr = new TypeLookupExpression ("System.UInt64");
456 system_char_expr = new TypeLookupExpression ("System.Char");
457 system_void_expr = new TypeLookupExpression ("System.Void");
458 system_asynccallback_expr = new TypeLookupExpression ("System.AsyncCallback");
459 system_iasyncresult_expr = new TypeLookupExpression ("System.IAsyncResult");
462 static TypeManager ()
464 assemblies = new Assembly [0];
466 user_types = new ArrayList ();
468 types = new Hashtable ();
469 typecontainers = new Hashtable ();
471 builder_to_member_finder = new PtrHashtable ();
472 builder_to_attr = new PtrHashtable ();
473 builder_to_method = new PtrHashtable ();
474 method_arguments = new PtrHashtable ();
475 method_internal_params = new PtrHashtable ();
476 indexer_arguments = new PtrHashtable ();
477 builder_to_ifaces = new PtrHashtable ();
479 NoTypes = new Type [0];
481 signature_filter = new MemberFilter (SignatureFilter);
482 InitExpressionTypes ();
485 public static void AddUserType (string name, TypeBuilder t, Type [] ifaces)
490 Type prev = (Type) types [name];
491 TypeContainer tc = builder_to_member_finder [prev] as TypeContainer;
495 // This probably never happens, as we catch this before
497 Report.Error (-17, "The type `" + name + "' has already been defined.");
501 tc = builder_to_member_finder [t] as TypeContainer;
504 1595, "The type `" + name + "' is defined in an existing assembly;"+
505 " Using the new definition from: " + tc.Location);
506 Report.Warning (1595, "Previously defined in: " + prev.Assembly.FullName);
514 builder_to_ifaces [t] = ifaces;
518 // This entry point is used by types that we define under the covers
520 public static void RegisterBuilder (TypeBuilder tb, Type [] ifaces)
523 builder_to_ifaces [tb] = ifaces;
526 public static void AddUserType (string name, TypeBuilder t, TypeContainer tc, Type [] ifaces)
528 builder_to_member_finder.Add (t, tc);
529 typecontainers.Add (name, tc);
530 AddUserType (name, t, ifaces);
533 public static void AddDelegateType (string name, TypeBuilder t, Delegate del)
536 builder_to_member_finder.Add (t, del);
539 public static void AddEnumType (string name, TypeBuilder t, Enum en)
542 builder_to_member_finder.Add (t, en);
545 public static void AddUserInterface (string name, TypeBuilder t, Interface i, Type [] ifaces)
547 AddUserType (name, t, ifaces);
548 builder_to_member_finder.Add (t, i);
551 public static void AddMethod (MethodBuilder builder, MethodData method)
553 builder_to_method.Add (builder, method);
556 public static void RegisterAttrType (Type t, TypeContainer tc)
558 builder_to_attr.Add (t, tc);
562 /// Returns the TypeContainer whose Type is `t' or null if there is no
563 /// TypeContainer for `t' (ie, the Type comes from a library)
565 public static TypeContainer LookupTypeContainer (Type t)
567 return builder_to_member_finder [t] as TypeContainer;
570 public static IMemberContainer LookupMemberContainer (Type t)
572 IMemberContainer container = builder_to_member_finder [t] as IMemberContainer;
573 if (container != null)
576 return TypeHandle.GetTypeHandle (t);
579 public static Interface LookupInterface (Type t)
581 return builder_to_member_finder [t] as Interface;
584 public static Delegate LookupDelegate (Type t)
586 return builder_to_member_finder [t] as Delegate;
589 public static Enum LookupEnum (Type t)
591 return builder_to_member_finder [t] as Enum;
594 public static TypeContainer LookupAttr (Type t)
596 return (TypeContainer) builder_to_attr [t];
600 /// Registers an assembly to load types from.
602 public static void AddAssembly (Assembly a)
604 int top = assemblies.Length;
605 Assembly [] n = new Assembly [top + 1];
607 assemblies.CopyTo (n, 0);
614 /// Registers a module builder to lookup types from
616 public static void AddModule (ModuleBuilder mb)
618 int top = modules != null ? modules.Length : 0;
619 ModuleBuilder [] n = new ModuleBuilder [top + 1];
622 modules.CopyTo (n, 0);
628 /// Returns the Type associated with @name
630 public static Type LookupType (string name)
635 // First lookup in user defined and cached values
638 t = (Type) types [name];
642 foreach (Assembly a in assemblies){
643 t = a.GetType (name);
651 foreach (ModuleBuilder mb in modules) {
652 t = mb.GetType (name);
663 /// Returns the C# name of a type if possible, or the full type name otherwise
665 static public string CSharpName (Type t)
667 return Regex.Replace (t.FullName,
669 @"(Int32|UInt32|Int16|Uint16|Int64|UInt64|" +
670 @"Single|Double|Char|Decimal|Byte|SByte|Object|" +
671 @"Boolean|String|Void)" +
673 new MatchEvaluator (CSharpNameMatch));
676 static String CSharpNameMatch (Match match)
678 string s = match.Groups [1].Captures [0].Value;
680 Replace ("int32", "int").
681 Replace ("uint32", "uint").
682 Replace ("int16", "short").
683 Replace ("uint16", "ushort").
684 Replace ("int64", "long").
685 Replace ("uint64", "ulong").
686 Replace ("single", "float").
687 Replace ("boolean", "bool")
688 + match.Groups [2].Captures [0].Value;
692 /// Returns the signature of the method
694 static public string CSharpSignature (MethodBase mb)
699 // FIXME: We should really have a single function to do
700 // everything instead of the following 5 line pattern
702 ParameterData iparams = LookupParametersByBuilder (mb);
704 if (iparams == null){
705 ParameterInfo [] pi = mb.GetParameters ();
706 iparams = new ReflectionParameters (pi);
709 for (int i = 0; i < iparams.Count; i++) {
713 sig += iparams.ParameterDesc(i);
717 return mb.DeclaringType.Name + "." + mb.Name + sig;
721 /// Looks up a type, and aborts if it is not found. This is used
722 /// by types required by the compiler
724 static Type CoreLookupType (string name)
726 Type t = LookupType (name);
729 Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
730 Environment.Exit (0);
737 /// Returns the MethodInfo for a method named `name' defined
738 /// in type `t' which takes arguments of types `args'
740 static MethodInfo GetMethod (Type t, string name, Type [] args)
748 list = FindMembers (t, MemberTypes.Method, instance_and_static | BindingFlags.Public,
749 signature_filter, sig);
750 if (list.Count == 0) {
751 Report.Error (-19, "Can not find the core function `" + name + "'");
755 MethodInfo mi = list [0] as MethodInfo;
757 Report.Error (-19, "Can not find the core function `" + name + "'");
765 /// Returns the ConstructorInfo for "args"
767 static ConstructorInfo GetConstructor (Type t, Type [] args)
775 list = FindMembers (t, MemberTypes.Constructor,
776 instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly,
777 signature_filter, sig);
778 if (list.Count == 0){
779 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
783 ConstructorInfo ci = list [0] as ConstructorInfo;
785 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
792 public static void InitEnumUnderlyingTypes ()
795 int32_type = CoreLookupType ("System.Int32");
796 int64_type = CoreLookupType ("System.Int64");
797 uint32_type = CoreLookupType ("System.UInt32");
798 uint64_type = CoreLookupType ("System.UInt64");
799 byte_type = CoreLookupType ("System.Byte");
800 sbyte_type = CoreLookupType ("System.SByte");
801 short_type = CoreLookupType ("System.Int16");
802 ushort_type = CoreLookupType ("System.UInt16");
806 /// The types have to be initialized after the initial
807 /// population of the type has happened (for example, to
808 /// bootstrap the corlib.dll
810 public static void InitCoreTypes ()
812 object_type = CoreLookupType ("System.Object");
813 value_type = CoreLookupType ("System.ValueType");
815 InitEnumUnderlyingTypes ();
817 char_type = CoreLookupType ("System.Char");
818 string_type = CoreLookupType ("System.String");
819 float_type = CoreLookupType ("System.Single");
820 double_type = CoreLookupType ("System.Double");
821 char_ptr_type = CoreLookupType ("System.Char*");
822 decimal_type = CoreLookupType ("System.Decimal");
823 bool_type = CoreLookupType ("System.Boolean");
824 enum_type = CoreLookupType ("System.Enum");
826 multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
827 delegate_type = CoreLookupType ("System.Delegate");
829 array_type = CoreLookupType ("System.Array");
830 void_type = CoreLookupType ("System.Void");
831 type_type = CoreLookupType ("System.Type");
833 runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
834 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
835 default_member_type = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
836 runtime_handle_type = CoreLookupType ("System.RuntimeTypeHandle");
837 asynccallback_type = CoreLookupType ("System.AsyncCallback");
838 iasyncresult_type = CoreLookupType ("System.IAsyncResult");
839 ienumerator_type = CoreLookupType ("System.Collections.IEnumerator");
840 idisposable_type = CoreLookupType ("System.IDisposable");
841 icloneable_type = CoreLookupType ("System.ICloneable");
842 monitor_type = CoreLookupType ("System.Threading.Monitor");
843 intptr_type = CoreLookupType ("System.IntPtr");
845 attribute_type = CoreLookupType ("System.Attribute");
846 attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
847 dllimport_type = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute");
848 methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute");
849 marshal_as_attr_type = CoreLookupType ("System.Runtime.InteropServices.MarshalAsAttribute");
850 param_array_type = CoreLookupType ("System.ParamArrayAttribute");
852 unverifiable_code_type= CoreLookupType ("System.Security.UnverifiableCodeAttribute");
854 void_ptr_type = CoreLookupType ("System.Void*");
856 indexer_name_type = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute");
858 exception_type = CoreLookupType ("System.Exception");
863 obsolete_attribute_type = CoreLookupType ("System.ObsoleteAttribute");
864 conditional_attribute_type = CoreLookupType ("System.Diagnostics.ConditionalAttribute");
867 // When compiling corlib, store the "real" types here.
869 if (!RootContext.StdLib) {
870 system_int32_type = typeof (System.Int32);
871 system_array_type = typeof (System.Array);
872 system_type_type = typeof (System.Type);
873 system_assemblybuilder_type = typeof (System.Reflection.Emit.AssemblyBuilder);
875 Type [] void_arg = { };
876 system_int_array_get_length = GetMethod (
877 system_array_type, "get_Length", void_arg);
878 system_int_array_get_rank = GetMethod (
879 system_array_type, "get_Rank", void_arg);
880 system_object_array_clone = GetMethod (
881 system_array_type, "Clone", void_arg);
883 Type [] system_int_arg = { system_int32_type };
884 system_int_array_get_length_int = GetMethod (
885 system_array_type, "GetLength", system_int_arg);
886 system_int_array_get_upper_bound_int = GetMethod (
887 system_array_type, "GetUpperBound", system_int_arg);
888 system_int_array_get_lower_bound_int = GetMethod (
889 system_array_type, "GetLowerBound", system_int_arg);
891 Type [] system_array_int_arg = { system_array_type, system_int32_type };
892 system_void_array_copyto_array_int = GetMethod (
893 system_array_type, "CopyTo", system_array_int_arg);
895 Type [] system_type_type_arg = { system_type_type, system_type_type, system_type_type };
898 system_void_set_corlib_type_builders = GetMethod (
899 system_assemblybuilder_type, "SetCorlibTypeBuilders",
900 system_type_type_arg);
902 object[] args = new object [3];
903 args [0] = object_type;
904 args [1] = value_type;
905 args [2] = enum_type;
907 system_void_set_corlib_type_builders.Invoke (CodeGen.AssemblyBuilder, args);
909 Console.WriteLine ("Corlib compilation is not supported in Microsoft.NET due to bugs in it");
915 // The helper methods that are used by the compiler
917 public static void InitCodeHelpers ()
920 // Now load the default methods that we use.
922 Type [] string_string = { string_type, string_type };
923 string_concat_string_string = GetMethod (
924 string_type, "Concat", string_string);
926 Type [] object_object = { object_type, object_type };
927 string_concat_object_object = GetMethod (
928 string_type, "Concat", object_object);
930 Type [] string_ = { string_type };
931 string_isinterneted_string = GetMethod (
932 string_type, "IsInterned", string_);
934 Type [] runtime_type_handle = { runtime_handle_type };
935 system_type_get_type_from_handle = GetMethod (
936 type_type, "GetTypeFromHandle", runtime_type_handle);
938 Type [] delegate_delegate = { delegate_type, delegate_type };
939 delegate_combine_delegate_delegate = GetMethod (
940 delegate_type, "Combine", delegate_delegate);
942 delegate_remove_delegate_delegate = GetMethod (
943 delegate_type, "Remove", delegate_delegate);
948 Type [] void_arg = { };
949 object_getcurrent_void = GetMethod (
950 ienumerator_type, "get_Current", void_arg);
951 bool_movenext_void = GetMethod (
952 ienumerator_type, "MoveNext", void_arg);
953 void_dispose_void = GetMethod (
954 idisposable_type, "Dispose", void_arg);
955 int_get_offset_to_string_data = GetMethod (
956 runtime_helpers_type, "get_OffsetToStringData", void_arg);
957 int_array_get_length = GetMethod (
958 array_type, "get_Length", void_arg);
959 int_array_get_rank = GetMethod (
960 array_type, "get_Rank", void_arg);
965 Type [] int_arg = { int32_type };
966 int_array_get_length_int = GetMethod (
967 array_type, "GetLength", int_arg);
968 int_array_get_upper_bound_int = GetMethod (
969 array_type, "GetUpperBound", int_arg);
970 int_array_get_lower_bound_int = GetMethod (
971 array_type, "GetLowerBound", int_arg);
974 // System.Array methods
976 object_array_clone = GetMethod (
977 array_type, "Clone", void_arg);
978 Type [] array_int_arg = { array_type, int32_type };
979 void_array_copyto_array_int = GetMethod (
980 array_type, "CopyTo", array_int_arg);
985 Type [] object_arg = { object_type };
986 void_monitor_enter_object = GetMethod (
987 monitor_type, "Enter", object_arg);
988 void_monitor_exit_object = GetMethod (
989 monitor_type, "Exit", object_arg);
991 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
993 void_initializearray_array_fieldhandle = GetMethod (
994 runtime_helpers_type, "InitializeArray", array_field_handle_arg);
999 int_getlength_int = GetMethod (
1000 array_type, "GetLength", int_arg);
1003 // Decimal constructors
1005 Type [] dec_arg = { int32_type, int32_type, int32_type, bool_type, byte_type };
1006 void_decimal_ctor_five_args = GetConstructor (
1007 decimal_type, dec_arg);
1012 cons_param_array_attribute = GetConstructor (
1013 param_array_type, void_arg);
1015 unverifiable_code_ctor = GetConstructor (
1016 unverifiable_code_type, void_arg);
1020 const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
1022 static Hashtable type_hash = new Hashtable ();
1024 public static MemberList FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1025 MemberFilter filter, object criteria)
1027 IMemberFinder finder = (IMemberFinder) builder_to_member_finder [t];
1029 if (finder != null) {
1031 Timer.StartTimer (TimerType.FindMembers);
1032 list = finder.FindMembers (mt, bf, filter, criteria);
1033 Timer.StopTimer (TimerType.FindMembers);
1038 // We have to take care of arrays specially, because GetType on
1039 // a TypeBuilder array will return a Type, not a TypeBuilder,
1040 // and we can not call FindMembers on this type.
1043 if (t.IsSubclassOf (TypeManager.array_type))
1044 return new MemberList (TypeManager.array_type.FindMembers (mt, bf, filter, criteria));
1047 // Since FindMembers will not lookup both static and instance
1048 // members, we emulate this behaviour here.
1050 if ((bf & instance_and_static) == instance_and_static){
1051 MemberInfo [] i_members = t.FindMembers (
1052 mt, bf & ~BindingFlags.Static, filter, criteria);
1054 int i_len = i_members.Length;
1056 MemberInfo one = i_members [0];
1059 // If any of these are present, we are done!
1061 if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
1062 return new MemberList (i_members);
1065 MemberInfo [] s_members = t.FindMembers (
1066 mt, bf & ~BindingFlags.Instance, filter, criteria);
1068 int s_len = s_members.Length;
1069 if (i_len > 0 || s_len > 0)
1070 return new MemberList (i_members, s_members);
1073 return new MemberList (i_members);
1075 return new MemberList (s_members);
1079 return new MemberList (t.FindMembers (mt, bf, filter, criteria));
1083 /// FIXME FIXME FIXME
1084 /// This method is a big hack until the new MemberCache is finished, it will be gone in
1086 /// FIXME FIXME FIXME
1088 private static MemberList MemberLookup_FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1089 string name, ref bool searching)
1092 // We have to take care of arrays specially, because GetType on
1093 // a TypeBuilder array will return a Type, not a TypeBuilder,
1094 // and we can not call FindMembers on this type.
1097 if (t.IsSubclassOf (TypeManager.array_type)) {
1099 return TypeHandle.ArrayType.MemberCache.FindMembers (
1100 mt, bf, name, FilterWithClosure_delegate, null);
1103 IMemberFinder finder = (IMemberFinder) builder_to_member_finder [t];
1105 if (finder != null) {
1106 MemberCache cache = finder.MemberCache;
1108 if (cache != null) {
1110 return cache.FindMembers (
1111 mt, bf, name, FilterWithClosure_delegate, null);
1115 Timer.StartTimer (TimerType.FindMembers);
1116 list = finder.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1117 FilterWithClosure_delegate, name);
1118 Timer.StopTimer (TimerType.FindMembers);
1122 finder = TypeHandle.GetTypeHandle (t);
1123 builder_to_member_finder.Add (t, finder);
1126 return finder.MemberCache.FindMembers (mt, bf, name, FilterWithClosure_delegate, null);
1129 public static bool IsBuiltinType (Type t)
1131 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
1132 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1133 t == char_type || t == short_type || t == decimal_type || t == bool_type ||
1134 t == sbyte_type || t == byte_type || t == ushort_type || t == void_type)
1140 public static bool IsDelegateType (Type t)
1142 if (t.IsSubclassOf (TypeManager.delegate_type))
1148 public static bool IsEnumType (Type t)
1150 if (t.IsSubclassOf (TypeManager.enum_type))
1156 public static bool IsValueType (Type t)
1158 if (t.IsSubclassOf (TypeManager.value_type))
1164 public static bool IsInterfaceType (Type t)
1166 Interface iface = builder_to_member_finder [t] as Interface;
1175 // Checks whether `type' is a subclass or nested child of `parent'.
1177 public static bool IsSubclassOrNestedChildOf (Type type, Type parent)
1180 if ((type == parent) || type.IsSubclassOf (parent))
1183 // Handle nested types.
1184 type = type.DeclaringType;
1185 } while (type != null);
1191 /// Returns the User Defined Types
1193 public static ArrayList UserTypes {
1199 public static Hashtable TypeContainers {
1201 return typecontainers;
1205 static Hashtable builder_to_constant;
1207 public static void RegisterConstant (FieldBuilder fb, Const c)
1209 if (builder_to_constant == null)
1210 builder_to_constant = new PtrHashtable ();
1212 if (builder_to_constant.Contains (fb))
1215 builder_to_constant.Add (fb, c);
1218 public static Const LookupConstant (FieldBuilder fb)
1220 if (builder_to_constant == null)
1223 return (Const) builder_to_constant [fb];
1227 /// Gigantic work around for missing features in System.Reflection.Emit follows.
1231 /// Since System.Reflection.Emit can not return MethodBase.GetParameters
1232 /// for anything which is dynamic, and we need this in a number of places,
1233 /// we register this information here, and use it afterwards.
1235 static public bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
1240 method_arguments.Add (mb, args);
1241 method_internal_params.Add (mb, ip);
1246 static public InternalParameters LookupParametersByBuilder (MethodBase mb)
1248 if (! (mb is ConstructorBuilder || mb is MethodBuilder))
1251 if (method_internal_params.Contains (mb))
1252 return (InternalParameters) method_internal_params [mb];
1254 throw new Exception ("Argument for Method not registered" + mb);
1258 /// Returns the argument types for a method based on its methodbase
1260 /// For dynamic methods, we use the compiler provided types, for
1261 /// methods from existing assemblies we load them from GetParameters,
1262 /// and insert them into the cache
1264 static public Type [] GetArgumentTypes (MethodBase mb)
1266 if (method_arguments.Contains (mb))
1267 return (Type []) method_arguments [mb];
1269 ParameterInfo [] pi = mb.GetParameters ();
1271 Type [] types = new Type [c];
1273 for (int i = 0; i < c; i++)
1274 types [i] = pi [i].ParameterType;
1276 method_arguments.Add (mb, types);
1282 /// Returns the argument types for an indexer based on its PropertyInfo
1284 /// For dynamic indexers, we use the compiler provided types, for
1285 /// indexers from existing assemblies we load them from GetParameters,
1286 /// and insert them into the cache
1288 static public Type [] GetArgumentTypes (PropertyInfo indexer)
1290 if (indexer_arguments.Contains (indexer))
1291 return (Type []) indexer_arguments [indexer];
1292 else if (indexer is PropertyBuilder)
1293 // If we're a PropertyBuilder and not in the
1294 // `indexer_arguments' hash, then we're a property and
1298 ParameterInfo [] pi = indexer.GetIndexParameters ();
1299 // Property, not an indexer.
1303 Type [] types = new Type [c];
1305 for (int i = 0; i < c; i++)
1306 types [i] = pi [i].ParameterType;
1308 indexer_arguments.Add (indexer, types);
1314 // This is a workaround the fact that GetValue is not
1315 // supported for dynamic types
1317 static Hashtable fields = new Hashtable ();
1318 static public bool RegisterFieldValue (FieldBuilder fb, object value)
1320 if (fields.Contains (fb))
1323 fields.Add (fb, value);
1328 static public object GetValue (FieldBuilder fb)
1333 static Hashtable fieldbuilders_to_fields = new Hashtable ();
1334 static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f)
1336 if (fieldbuilders_to_fields.Contains (fb))
1339 fieldbuilders_to_fields.Add (fb, f);
1343 static public FieldBase GetField (FieldInfo fb)
1345 return (FieldBase) fieldbuilders_to_fields [fb];
1348 static Hashtable events;
1350 static public bool RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
1353 events = new Hashtable ();
1355 if (events.Contains (eb))
1358 events.Add (eb, new Pair (add, remove));
1363 static public MethodInfo GetAddMethod (EventInfo ei)
1365 if (ei is MyEventBuilder) {
1366 Pair pair = (Pair) events [ei];
1368 return (MethodInfo) pair.First;
1370 return ei.GetAddMethod ();
1373 static public MethodInfo GetRemoveMethod (EventInfo ei)
1375 if (ei is MyEventBuilder) {
1376 Pair pair = (Pair) events [ei];
1378 return (MethodInfo) pair.Second;
1380 return ei.GetAddMethod ();
1383 static Hashtable priv_fields_events;
1385 static public bool RegisterPrivateFieldOfEvent (EventInfo einfo, FieldBuilder builder)
1387 if (priv_fields_events == null)
1388 priv_fields_events = new Hashtable ();
1390 if (priv_fields_events.Contains (einfo))
1393 priv_fields_events.Add (einfo, builder);
1398 static public MemberInfo GetPrivateFieldOfEvent (EventInfo ei)
1400 return (MemberInfo) priv_fields_events [ei];
1403 static Hashtable properties;
1405 static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
1407 if (properties == null)
1408 properties = new Hashtable ();
1410 if (properties.Contains (pb))
1413 properties.Add (pb, new Pair (get, set));
1418 static public bool RegisterIndexer (PropertyBuilder pb, MethodBase get, MethodBase set, Type[] args)
1420 if (!RegisterProperty (pb, get,set))
1423 indexer_arguments.Add (pb, args);
1429 // FIXME: we need to return the accessors depending on whether
1430 // they are visible or not.
1432 static public MethodInfo [] GetAccessors (PropertyInfo pi)
1436 if (pi is PropertyBuilder){
1437 Pair pair = (Pair) properties [pi];
1439 ret = new MethodInfo [2];
1440 ret [0] = (MethodInfo) pair.First;
1441 ret [1] = (MethodInfo) pair.Second;
1445 MethodInfo [] mi = new MethodInfo [2];
1448 // Why this and not pi.GetAccessors?
1449 // Because sometimes index 0 is the getter
1450 // sometimes it is 1
1452 mi [0] = pi.GetGetMethod (true);
1453 mi [1] = pi.GetSetMethod (true);
1459 static public MethodInfo GetPropertyGetter (PropertyInfo pi)
1461 if (pi is PropertyBuilder){
1462 Pair de = (Pair) properties [pi];
1464 return (MethodInfo) de.Second;
1466 return pi.GetSetMethod ();
1469 static public MethodInfo GetPropertySetter (PropertyInfo pi)
1471 if (pi is PropertyBuilder){
1472 Pair de = (Pair) properties [pi];
1474 return (MethodInfo) de.First;
1476 return pi.GetGetMethod ();
1480 /// Given an array of interface types, expand and eliminate repeated ocurrences
1481 /// of an interface.
1485 /// This expands in context like: IA; IB : IA; IC : IA, IB; the interface "IC" to
1488 public static Type [] ExpandInterfaces (Type [] base_interfaces)
1490 ArrayList new_ifaces = new ArrayList ();
1492 foreach (Type iface in base_interfaces){
1493 if (!new_ifaces.Contains (iface))
1494 new_ifaces.Add (iface);
1496 Type [] implementing = TypeManager.GetInterfaces (iface);
1498 foreach (Type imp in implementing){
1499 if (!new_ifaces.Contains (imp))
1500 new_ifaces.Add (imp);
1503 Type [] ret = new Type [new_ifaces.Count];
1504 new_ifaces.CopyTo (ret, 0);
1509 /// This function returns the interfaces in the type `t'. Works with
1510 /// both types and TypeBuilders.
1512 public static Type [] GetInterfaces (Type t)
1515 // The reason for catching the Array case is that Reflection.Emit
1516 // will not return a TypeBuilder for Array types of TypeBuilder types,
1517 // but will still throw an exception if we try to call GetInterfaces
1520 // Since the array interfaces are always constant, we return those for
1525 t = TypeManager.array_type;
1527 if (t is TypeBuilder){
1528 Type [] parent_ifaces;
1530 if (t.BaseType == null)
1531 parent_ifaces = NoTypes;
1533 parent_ifaces = GetInterfaces (t.BaseType);
1534 Type [] type_ifaces = (Type []) builder_to_ifaces [t];
1535 if (type_ifaces == null)
1536 type_ifaces = NoTypes;
1538 int parent_count = parent_ifaces.Length;
1539 Type [] result = new Type [parent_count + type_ifaces.Length];
1540 parent_ifaces.CopyTo (result, 0);
1541 type_ifaces.CopyTo (result, parent_count);
1545 return t.GetInterfaces ();
1549 /// The following is used to check if a given type implements an interface.
1550 /// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
1552 public static bool ImplementsInterface (Type t, Type iface)
1557 // FIXME OPTIMIZATION:
1558 // as soon as we hit a non-TypeBuiler in the interface
1559 // chain, we could return, as the `Type.GetInterfaces'
1560 // will return all the interfaces implement by the type
1564 interfaces = GetInterfaces (t);
1566 if (interfaces != null){
1567 foreach (Type i in interfaces){
1574 } while (t != null);
1579 // This is a custom version of Convert.ChangeType() which works
1580 // with the TypeBuilder defined types when compiling corlib.
1581 public static object ChangeType (object value, Type conversionType)
1583 if (!(value is IConvertible))
1584 throw new ArgumentException ();
1586 IConvertible convertValue = (IConvertible) value;
1587 CultureInfo ci = CultureInfo.CurrentCulture;
1588 NumberFormatInfo provider = ci.NumberFormat;
1591 // We must use Type.Equals() here since `conversionType' is
1592 // the TypeBuilder created version of a system type and not
1593 // the system type itself. You cannot use Type.GetTypeCode()
1594 // on such a type - it'd always return TypeCode.Object.
1596 if (conversionType.Equals (typeof (Boolean)))
1597 return (object)(convertValue.ToBoolean (provider));
1598 else if (conversionType.Equals (typeof (Byte)))
1599 return (object)(convertValue.ToByte (provider));
1600 else if (conversionType.Equals (typeof (Char)))
1601 return (object)(convertValue.ToChar (provider));
1602 else if (conversionType.Equals (typeof (DateTime)))
1603 return (object)(convertValue.ToDateTime (provider));
1604 else if (conversionType.Equals (typeof (Decimal)))
1605 return (object)(convertValue.ToDecimal (provider));
1606 else if (conversionType.Equals (typeof (Double)))
1607 return (object)(convertValue.ToDouble (provider));
1608 else if (conversionType.Equals (typeof (Int16)))
1609 return (object)(convertValue.ToInt16 (provider));
1610 else if (conversionType.Equals (typeof (Int32)))
1611 return (object)(convertValue.ToInt32 (provider));
1612 else if (conversionType.Equals (typeof (Int64)))
1613 return (object)(convertValue.ToInt64 (provider));
1614 else if (conversionType.Equals (typeof (SByte)))
1615 return (object)(convertValue.ToSByte (provider));
1616 else if (conversionType.Equals (typeof (Single)))
1617 return (object)(convertValue.ToSingle (provider));
1618 else if (conversionType.Equals (typeof (String)))
1619 return (object)(convertValue.ToString (provider));
1620 else if (conversionType.Equals (typeof (UInt16)))
1621 return (object)(convertValue.ToUInt16 (provider));
1622 else if (conversionType.Equals (typeof (UInt32)))
1623 return (object)(convertValue.ToUInt32 (provider));
1624 else if (conversionType.Equals (typeof (UInt64)))
1625 return (object)(convertValue.ToUInt64 (provider));
1626 else if (conversionType.Equals (typeof (Object)))
1627 return (object)(value);
1629 throw new InvalidCastException ();
1633 // This is needed, because enumerations from assemblies
1634 // do not report their underlyingtype, but they report
1637 public static Type EnumToUnderlying (Type t)
1639 if (t == TypeManager.enum_type)
1642 t = t.UnderlyingSystemType;
1643 if (!TypeManager.IsEnumType (t))
1646 if (t is TypeBuilder) {
1647 // slow path needed to compile corlib
1648 if (t == TypeManager.bool_type ||
1649 t == TypeManager.byte_type ||
1650 t == TypeManager.sbyte_type ||
1651 t == TypeManager.char_type ||
1652 t == TypeManager.short_type ||
1653 t == TypeManager.ushort_type ||
1654 t == TypeManager.int32_type ||
1655 t == TypeManager.uint32_type ||
1656 t == TypeManager.int64_type ||
1657 t == TypeManager.uint64_type)
1659 throw new Exception ("Unhandled typecode in enum " + " from " + t.AssemblyQualifiedName);
1661 TypeCode tc = Type.GetTypeCode (t);
1664 case TypeCode.Boolean:
1665 return TypeManager.bool_type;
1667 return TypeManager.byte_type;
1668 case TypeCode.SByte:
1669 return TypeManager.sbyte_type;
1671 return TypeManager.char_type;
1672 case TypeCode.Int16:
1673 return TypeManager.short_type;
1674 case TypeCode.UInt16:
1675 return TypeManager.ushort_type;
1676 case TypeCode.Int32:
1677 return TypeManager.int32_type;
1678 case TypeCode.UInt32:
1679 return TypeManager.uint32_type;
1680 case TypeCode.Int64:
1681 return TypeManager.int64_type;
1682 case TypeCode.UInt64:
1683 return TypeManager.uint64_type;
1685 throw new Exception ("Unhandled typecode in enum " + tc + " from " + t.AssemblyQualifiedName);
1689 // When compiling corlib and called with one of the core types, return
1690 // the corresponding typebuilder for that type.
1692 public static Type TypeToCoreType (Type t)
1694 if (RootContext.StdLib || (t is TypeBuilder))
1697 TypeCode tc = Type.GetTypeCode (t);
1700 case TypeCode.Boolean:
1701 return TypeManager.bool_type;
1703 return TypeManager.byte_type;
1704 case TypeCode.SByte:
1705 return TypeManager.sbyte_type;
1707 return TypeManager.char_type;
1708 case TypeCode.Int16:
1709 return TypeManager.short_type;
1710 case TypeCode.UInt16:
1711 return TypeManager.ushort_type;
1712 case TypeCode.Int32:
1713 return TypeManager.int32_type;
1714 case TypeCode.UInt32:
1715 return TypeManager.uint32_type;
1716 case TypeCode.Int64:
1717 return TypeManager.int64_type;
1718 case TypeCode.UInt64:
1719 return TypeManager.uint64_type;
1720 case TypeCode.String:
1721 return TypeManager.string_type;
1723 if (t == typeof (void))
1724 return TypeManager.void_type;
1725 if (t == typeof (object))
1726 return TypeManager.object_type;
1727 if (t == typeof (System.Type))
1728 return TypeManager.type_type;
1734 /// Utility function that can be used to probe whether a type
1735 /// is managed or not.
1737 public static bool VerifyUnManaged (Type t, Location loc)
1739 if (t.IsValueType || t.IsPointer){
1741 // FIXME: this is more complex, we actually need to
1742 // make sure that the type does not contain any
1748 if (!RootContext.StdLib && (t == TypeManager.decimal_type))
1749 // We need this explicit check here to make it work when
1750 // compiling corlib.
1755 "Cannot take the address or size of a variable of a managed type ('" +
1756 CSharpName (t) + "')");
1761 /// Returns the name of the indexer in a given type.
1764 /// The default is not always `Item'. The user can change this behaviour by
1765 /// using the DefaultMemberAttribute in the class.
1767 /// For example, the String class indexer is named `Chars' not `Item'
1769 public static string IndexerPropertyName (Type t)
1771 if (t is TypeBuilder) {
1772 if (t.IsInterface) {
1773 Interface i = LookupInterface (t);
1775 if ((i == null) || (i.IndexerName == null))
1778 return i.IndexerName;
1780 TypeContainer tc = LookupTypeContainer (t);
1782 if ((tc == null) || (tc.IndexerName == null))
1785 return tc.IndexerName;
1789 System.Attribute attr = System.Attribute.GetCustomAttribute (
1790 t, TypeManager.default_member_type);
1792 DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
1793 return dma.MemberName;
1799 public static void MakePinned (LocalBuilder builder)
1802 // FIXME: Flag the "LocalBuilder" type as being
1803 // pinned. Figure out API.
1809 // Returns whether the array of memberinfos contains the given method
1811 static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method)
1813 Type [] new_args = TypeManager.GetArgumentTypes (new_method);
1815 foreach (MethodBase method in array){
1816 if (method.Name != new_method.Name)
1819 Type [] old_args = TypeManager.GetArgumentTypes (method);
1820 int old_count = old_args.Length;
1823 if (new_args.Length != old_count)
1826 for (i = 0; i < old_count; i++){
1827 if (old_args [i] != new_args [i])
1839 // We copy methods from `new_members' into `target_list' if the signature
1840 // for the method from in the new list does not exist in the target_list
1842 // The name is assumed to be the same.
1844 public static ArrayList CopyNewMethods (ArrayList target_list, MemberList new_members)
1846 if (target_list == null){
1847 target_list = new ArrayList ();
1849 foreach (MemberInfo mi in new_members){
1850 if (mi is MethodBase)
1851 target_list.Add (mi);
1856 MemberInfo [] target_array = new MemberInfo [target_list.Count];
1857 target_list.CopyTo (target_array, 0);
1859 foreach (MemberInfo mi in new_members){
1860 MethodBase new_method = (MethodBase) mi;
1862 if (!ArrayContainsMethod (target_array, new_method))
1863 target_list.Add (new_method);
1869 public enum MethodFlags {
1871 IsObsoleteError = 2,
1876 // Returns the TypeManager.MethodFlags for this method.
1877 // This emits an error 619 / warning 618 if the method is obsolete.
1878 // In the former case, TypeManager.MethodFlags.IsObsoleteError is returned.
1880 static public MethodFlags GetMethodFlags (MethodBase mb, Location loc)
1882 MethodFlags flags = 0;
1884 if (mb.DeclaringType is TypeBuilder){
1885 MethodData method = (MethodData) builder_to_method [mb];
1886 if (method == null) {
1887 // FIXME: implement Obsolete attribute on Property,
1888 // Indexer and Event.
1892 return method.GetMethodFlags (loc);
1895 object [] attrs = mb.GetCustomAttributes (true);
1896 foreach (object ta in attrs){
1897 if (!(ta is System.Attribute)){
1898 Console.WriteLine ("Unknown type in GetMethodFlags: " + ta);
1901 System.Attribute a = (System.Attribute) ta;
1902 if (a.TypeId == TypeManager.obsolete_attribute_type){
1903 ObsoleteAttribute oa = (ObsoleteAttribute) a;
1905 string method_desc = TypeManager.CSharpSignature (mb);
1908 Report.Error (619, loc, "Method `" + method_desc +
1909 "' is obsolete: `" + oa.Message + "'");
1910 return MethodFlags.IsObsoleteError;
1912 Report.Warning (618, loc, "Method `" + method_desc +
1913 "' is obsolete: `" + oa.Message + "'");
1915 flags |= MethodFlags.IsObsolete;
1921 // Skip over conditional code.
1923 if (a.TypeId == TypeManager.conditional_attribute_type){
1924 ConditionalAttribute ca = (ConditionalAttribute) a;
1926 if (RootContext.AllDefines [ca.ConditionString] == null)
1927 flags |= MethodFlags.ShouldIgnore;
1934 #region MemberLookup implementation
1937 // Name of the member
1939 static string closure_name;
1942 // Whether we allow private members in the result (since FindMembers
1943 // uses NonPublic for both protected and private), we need to distinguish.
1945 static bool closure_private_ok;
1948 // Who is invoking us and which type is being queried currently.
1950 static Type closure_invocation_type;
1951 static Type closure_queried_type;
1952 static Type closure_start_type;
1955 // The assembly that defines the type is that is calling us
1957 static Assembly closure_invocation_assembly;
1960 // This filter filters by name + whether it is ok to include private
1961 // members in the search
1963 static internal bool FilterWithClosure (MemberInfo m, object filter_criteria)
1966 // Hack: we know that the filter criteria will always be in the `closure'
1970 if ((filter_criteria != null) && (m.Name != (string) filter_criteria))
1973 if (closure_start_type == closure_invocation_type)
1977 // Ugly: we need to find out the type of `m', and depending
1978 // on this, tell whether we accept or not
1980 if (m is MethodBase){
1981 MethodBase mb = (MethodBase) m;
1982 MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
1984 if (ma == MethodAttributes.Private)
1985 return closure_private_ok || (closure_invocation_type == m.DeclaringType);
1988 // FamAndAssem requires that we not only derivate, but we are on the
1991 if (ma == MethodAttributes.FamANDAssem){
1992 if (closure_invocation_assembly != mb.DeclaringType.Assembly)
1996 // Assembly and FamORAssem succeed if we're in the same assembly.
1997 if ((ma == MethodAttributes.Assembly) || (ma == MethodAttributes.FamORAssem)){
1998 if (closure_invocation_assembly == mb.DeclaringType.Assembly)
2002 // We already know that we aren't in the same assembly.
2003 if (ma == MethodAttributes.Assembly)
2006 // Family and FamANDAssem require that we derive.
2007 if ((ma == MethodAttributes.Family) || (ma == MethodAttributes.FamANDAssem)){
2008 if (closure_invocation_type == null)
2011 if (!IsSubclassOrNestedChildOf (closure_invocation_type, mb.DeclaringType))
2014 // Although a derived class can access protected members of its base class
2015 // it cannot do so through an instance of the base class (CS1540).
2016 if ((closure_invocation_type != closure_start_type) &&
2017 closure_invocation_type.IsSubclassOf (closure_start_type))
2027 if (m is FieldInfo){
2028 FieldInfo fi = (FieldInfo) m;
2029 FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
2031 if (fa == FieldAttributes.Private)
2032 return closure_private_ok || (closure_invocation_type == m.DeclaringType);
2035 // FamAndAssem requires that we not only derivate, but we are on the
2038 if (fa == FieldAttributes.FamANDAssem){
2039 if (closure_invocation_assembly != fi.DeclaringType.Assembly)
2043 // Assembly and FamORAssem succeed if we're in the same assembly.
2044 if ((fa == FieldAttributes.Assembly) || (fa == FieldAttributes.FamORAssem)){
2045 if (closure_invocation_assembly == fi.DeclaringType.Assembly)
2049 // We already know that we aren't in the same assembly.
2050 if (fa == FieldAttributes.Assembly)
2053 // Family and FamANDAssem require that we derive.
2054 if ((fa == FieldAttributes.Family) || (fa == FieldAttributes.FamANDAssem)){
2055 if (closure_invocation_type == null)
2058 if (!IsSubclassOrNestedChildOf (closure_invocation_type, fi.DeclaringType))
2061 // Although a derived class can access protected members of its base class
2062 // it cannot do so through an instance of the base class (CS1540).
2063 if ((closure_invocation_type != closure_start_type) &&
2064 closure_invocation_type.IsSubclassOf (closure_start_type))
2075 // EventInfos and PropertyInfos, return true
2080 static MemberFilter FilterWithClosure_delegate = new MemberFilter (FilterWithClosure);
2083 // Looks up a member called `name' in the `queried_type'. This lookup
2084 // is done by code that is contained in the definition for `invocation_type'.
2086 // The binding flags are `bf' and the kind of members being looked up are `mt'
2088 // Returns an array of a single element for everything but Methods/Constructors
2089 // that might return multiple matches.
2091 public static MemberInfo [] MemberLookup (Type invocation_type, Type queried_type,
2092 MemberTypes mt, BindingFlags original_bf, string name)
2094 Timer.StartTimer (TimerType.MemberLookup);
2096 MemberInfo[] retval = RealMemberLookup (invocation_type, queried_type,
2097 mt, original_bf, name);
2099 Timer.StopTimer (TimerType.MemberLookup);
2104 static MemberInfo [] RealMemberLookup (Type invocation_type, Type queried_type,
2105 MemberTypes mt, BindingFlags original_bf, string name)
2107 BindingFlags bf = original_bf;
2109 ArrayList method_list = null;
2110 Type current_type = queried_type;
2111 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
2113 bool always_ok_flag = false;
2115 closure_name = name;
2116 closure_invocation_type = invocation_type;
2117 closure_invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
2118 closure_start_type = queried_type;
2121 // If we are a nested class, we always have access to our container
2124 if (invocation_type != null){
2125 string invocation_name = invocation_type.FullName;
2126 if (invocation_name.IndexOf ('+') != -1){
2127 string container = queried_type.FullName + "+";
2128 int container_length = container.Length;
2130 if (invocation_name.Length > container_length){
2131 string shared = invocation_name.Substring (0, container_length);
2133 if (shared == container)
2134 always_ok_flag = true;
2143 // `NonPublic' is lame, because it includes both protected and
2144 // private methods, so we need to control this behavior by
2145 // explicitly tracking if a private method is ok or not.
2147 // The possible cases are:
2148 // public, private and protected (internal does not come into the
2151 if (invocation_type != null){
2152 if (invocation_type == current_type){
2155 private_ok = always_ok_flag;
2157 if (private_ok || invocation_type.IsSubclassOf (current_type))
2158 bf = original_bf | BindingFlags.NonPublic;
2161 bf = original_bf & ~BindingFlags.NonPublic;
2164 closure_private_ok = private_ok;
2165 closure_queried_type = current_type;
2167 Timer.StopTimer (TimerType.MemberLookup);
2169 list = MemberLookup_FindMembers (current_type, mt, bf, name, ref searching);
2171 Timer.StartTimer (TimerType.MemberLookup);
2173 if (current_type == TypeManager.object_type)
2176 current_type = current_type.BaseType;
2179 // This happens with interfaces, they have a null
2180 // basetype. Look members up in the Object class.
2182 if (current_type == null)
2183 current_type = TypeManager.object_type;
2186 if (list.Count == 0)
2190 // Events and types are returned by both `static' and `instance'
2191 // searches, which means that our above FindMembers will
2192 // return two copies of the same.
2194 if (list.Count == 1 && !(list [0] is MethodBase)){
2195 return (MemberInfo []) list;
2199 // Multiple properties: we query those just to find out the indexer
2202 if (list [0] is PropertyInfo)
2203 return (MemberInfo []) list;
2206 // We found methods, turn the search into "method scan"
2210 method_list = CopyNewMethods (method_list, list);
2211 mt &= (MemberTypes.Method | MemberTypes.Constructor);
2212 } while (searching);
2214 if (method_list != null && method_list.Count > 0)
2215 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
2218 // Interfaces do not list members they inherit, so we have to
2221 if (!queried_type.IsInterface)
2224 if (queried_type.IsArray)
2225 queried_type = TypeManager.array_type;
2227 Type [] ifaces = GetInterfaces (queried_type);
2231 foreach (Type itype in ifaces){
2234 x = MemberLookup (null, itype, mt, bf, name);
2245 public class MemberCache {
2246 public readonly IMemberContainer Container;
2247 protected Hashtable member_hash;
2250 /// Create a new MemberCache for the given IMemberContainer `container'.
2252 public MemberCache (IMemberContainer container)
2254 this.Container = container;
2256 Timer.IncrementCounter (CounterType.MemberCache);
2257 Timer.StartTimer (TimerType.CacheInit);
2259 if (Container.Parent != null)
2260 member_hash = SetupCache (Container.Parent.MemberCache);
2261 else if (Container.IsInterface)
2262 member_hash = SetupCache (TypeHandle.ObjectType.MemberCache);
2264 member_hash = new Hashtable ();
2266 AddMembers (Container);
2268 Timer.StopTimer (TimerType.CacheInit);
2272 /// Bootstrap this member cache by doing a deep-copy of our parent.
2274 Hashtable SetupCache (MemberCache parent)
2276 Hashtable hash = new Hashtable ();
2278 IDictionaryEnumerator it = parent.member_hash.GetEnumerator ();
2279 while (it.MoveNext ()) {
2280 hash [it.Key] = ((ArrayList) it.Value).Clone ();
2286 void AddMembers (IMemberContainer container)
2288 AddMembers (MemberTypes.Constructor | MemberTypes.Field | MemberTypes.Method |
2289 MemberTypes.Property, container);
2290 AddMembers (MemberTypes.NestedType | MemberTypes.Event,
2291 BindingFlags.Public, container);
2292 AddMembers (MemberTypes.NestedType | MemberTypes.Event,
2293 BindingFlags.NonPublic, container);
2296 void AddMembers (MemberTypes mt, IMemberContainer container)
2298 AddMembers (mt, BindingFlags.Static | BindingFlags.Public, container);
2299 AddMembers (mt, BindingFlags.Static | BindingFlags.NonPublic, container);
2300 AddMembers (mt, BindingFlags.Instance | BindingFlags.Public, container);
2301 AddMembers (mt, BindingFlags.Instance | BindingFlags.NonPublic, container);
2304 void AddMembers (MemberTypes mt, BindingFlags bf, IMemberContainer container)
2306 MemberList members = container.GetMembers (mt, bf);
2307 BindingFlags new_bf = (container == Container) ? bf | BindingFlags.DeclaredOnly : bf;
2309 foreach (MemberInfo member in members) {
2310 string name = member.Name;
2312 ArrayList list = (ArrayList) member_hash [name];
2314 list = new ArrayList ();
2315 member_hash.Add (name, list);
2318 list.Add (new CacheEntry (container, member, mt, new_bf));
2322 protected static EntryType GetEntryType (MemberTypes mt, BindingFlags bf)
2324 EntryType type = EntryType.None;
2326 if ((mt & MemberTypes.Constructor) != 0)
2327 type |= EntryType.Constructor;
2328 if ((mt & MemberTypes.Event) != 0)
2329 type |= EntryType.Event;
2330 if ((mt & MemberTypes.Field) != 0)
2331 type |= EntryType.Field;
2332 if ((mt & MemberTypes.Method) != 0)
2333 type |= EntryType.Method;
2334 if ((mt & MemberTypes.Property) != 0)
2335 type |= EntryType.Property;
2336 if ((mt & MemberTypes.NestedType) != 0)
2337 type |= EntryType.NestedType;
2339 if ((bf & BindingFlags.Instance) != 0)
2340 type |= EntryType.Instance;
2341 if ((bf & BindingFlags.Static) != 0)
2342 type |= EntryType.Static;
2343 if ((bf & (BindingFlags.Instance | BindingFlags.Static)) == 0)
2344 type |= EntryType.Instance | EntryType.Static;
2345 if ((bf & BindingFlags.Public) != 0)
2346 type |= EntryType.Public;
2347 if ((bf & BindingFlags.NonPublic) != 0)
2348 type |= EntryType.NonPublic;
2349 if ((bf & BindingFlags.DeclaredOnly) != 0)
2350 type |= EntryType.Declared;
2355 public static bool IsSingleMemberType (MemberTypes mt)
2358 case MemberTypes.Constructor:
2359 case MemberTypes.Event:
2360 case MemberTypes.Field:
2361 case MemberTypes.Method:
2362 case MemberTypes.Property:
2363 case MemberTypes.NestedType:
2372 protected enum EntryType {
2377 MaskStatic = Instance|Static,
2381 MaskProtection = Public|NonPublic,
2385 Constructor = 0x020,
2392 MaskType = Constructor|Event|Field|Method|Property|NestedType
2395 protected struct CacheEntry {
2396 public readonly IMemberContainer Container;
2397 public readonly EntryType EntryType;
2398 public readonly MemberInfo Member;
2400 public CacheEntry (IMemberContainer container, MemberInfo member,
2401 MemberTypes mt, BindingFlags bf)
2403 this.Container = container;
2404 this.Member = member;
2405 this.EntryType = GetEntryType (mt, bf);
2409 protected bool DoneSearching (ArrayList list)
2412 // We've found exactly one member in the current class and it's not
2413 // a method or constructor.
2415 if (list.Count == 1 && !(list [0] is MethodBase))
2419 // Multiple properties: we query those just to find out the indexer
2422 if ((list.Count > 0) && (list [0] is PropertyInfo))
2428 public MemberList FindMembers (MemberTypes mt, BindingFlags bf, string name,
2429 MemberFilter filter, object criteria)
2431 bool declared_only = (bf & BindingFlags.DeclaredOnly) != 0;
2433 ArrayList applicable = (ArrayList) member_hash [name];
2434 if (applicable == null)
2435 return MemberList.Empty;
2437 ArrayList list = new ArrayList ();
2439 Timer.StartTimer (TimerType.CachedLookup);
2441 IMemberContainer current = Container;
2443 // `applicable' is a list of all members with the given member name `name'
2444 // in the current class and all its parent classes. The list is sorted in
2445 // reverse order due to the way how the cache is initialy created (to speed
2446 // things up, we're doing a deep-copy of our parent).
2448 for (int i = applicable.Count-1; i >= 0; i--) {
2449 CacheEntry entry = (CacheEntry) applicable [i];
2451 // This happens each time we're walking one level up in the class
2452 // hierarchy. If we're doing a DeclaredOnly search, we must abort
2453 // the first time this happens (this may already happen in the first
2454 // iteration of this loop if there are no members with the name we're
2455 // looking for in the current class).
2456 if (entry.Container != current) {
2457 if (declared_only || DoneSearching (list))
2460 current = entry.Container;
2463 EntryType type = GetEntryType (mt, bf);
2465 // Is the member of the correct type ?
2466 if ((entry.EntryType & type & EntryType.MaskType) == 0)
2469 // Is the member static/non-static ?
2470 if ((entry.EntryType & type & EntryType.MaskStatic) == 0)
2473 // Apply the filter to it.
2474 if (filter (entry.Member, criteria))
2475 list.Add (entry.Member);
2478 Timer.StopTimer (TimerType.CachedLookup);
2480 return new MemberList (list);
2484 public sealed class TypeHandle : IMemberContainer {
2485 public readonly TypeHandle BaseType;
2487 readonly int id = ++next_id;
2488 static int next_id = 0;
2491 /// Lookup a TypeHandle instance for the given type. If the type doesn't have
2492 /// a TypeHandle yet, a new instance of it is created. This static method
2493 /// ensures that we'll only have one TypeHandle instance per type.
2495 public static TypeHandle GetTypeHandle (Type t)
2497 TypeHandle handle = (TypeHandle) type_hash [t];
2501 handle = new TypeHandle (t);
2502 type_hash.Add (t, handle);
2507 /// Returns the TypeHandle for TypeManager.object_type.
2509 public static IMemberContainer ObjectType {
2511 if (object_type != null)
2514 object_type = GetTypeHandle (TypeManager.object_type);
2521 /// Returns the TypeHandle for TypeManager.array_type.
2523 public static IMemberContainer ArrayType {
2525 if (array_type != null)
2528 array_type = GetTypeHandle (TypeManager.array_type);
2534 private static PtrHashtable type_hash = new PtrHashtable ();
2536 private static TypeHandle object_type = null;
2537 private static TypeHandle array_type = null;
2540 private bool is_interface;
2541 private MemberCache member_cache;
2543 private TypeHandle (Type type)
2546 if (type.BaseType != null)
2547 BaseType = GetTypeHandle (type.BaseType);
2548 else if ((type != TypeManager.object_type) && (type != typeof (object)))
2549 is_interface = true;
2550 this.member_cache = new MemberCache (this);
2553 // IMemberContainer methods
2555 public string Name {
2557 return Type.FullName;
2567 public IMemberContainer Parent {
2573 public bool IsInterface {
2575 return is_interface;
2579 public MemberList GetMembers (MemberTypes mt, BindingFlags bf)
2581 return new MemberList (Type.FindMembers (mt, bf | BindingFlags.DeclaredOnly, null, null));
2584 // IMemberFinder methods
2586 public MemberList FindMembers (MemberTypes mt, BindingFlags bf,
2587 MemberFilter filter, object criteria)
2589 throw new NotSupportedException ();
2592 public MemberCache MemberCache {
2594 return member_cache;
2598 public override string ToString ()
2600 if (BaseType != null)
2601 return "TypeHandle (" + id + "," + Name + " : " + BaseType + ")";
2603 return "TypeHandle (" + id + "," + Name + ")";