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 {
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 exception_type;
71 static public object obsolete_attribute_type;
72 static public object conditional_attribute_type;
75 // An empty array of types
77 static public Type [] NoTypes;
81 // Expressions representing the internal types. Used during declaration
84 static public Expression system_object_expr, system_string_expr;
85 static public Expression system_boolean_expr, system_decimal_expr;
86 static public Expression system_single_expr, system_double_expr;
87 static public Expression system_sbyte_expr, system_byte_expr;
88 static public Expression system_int16_expr, system_uint16_expr;
89 static public Expression system_int32_expr, system_uint32_expr;
90 static public Expression system_int64_expr, system_uint64_expr;
91 static public Expression system_char_expr, system_void_expr;
92 static public Expression system_asynccallback_expr;
93 static public Expression system_iasyncresult_expr;
96 // This is only used when compiling corlib
98 static public Type system_int32_type;
99 static public Type system_array_type;
100 static public Type system_type_type;
101 static public Type system_assemblybuilder_type;
102 static public MethodInfo system_int_array_get_length;
103 static public MethodInfo system_int_array_get_rank;
104 static public MethodInfo system_object_array_clone;
105 static public MethodInfo system_int_array_get_length_int;
106 static public MethodInfo system_int_array_get_lower_bound_int;
107 static public MethodInfo system_int_array_get_upper_bound_int;
108 static public MethodInfo system_void_array_copyto_array_int;
109 static public MethodInfo system_void_set_corlib_type_builders;
113 // Internal, not really used outside
115 static Type runtime_helpers_type;
118 // These methods are called by code generated by the compiler
120 static public MethodInfo string_concat_string_string;
121 static public MethodInfo string_concat_object_object;
122 static public MethodInfo string_isinterneted_string;
123 static public MethodInfo system_type_get_type_from_handle;
124 static public MethodInfo object_getcurrent_void;
125 static public MethodInfo bool_movenext_void;
126 static public MethodInfo void_dispose_void;
127 static public MethodInfo void_monitor_enter_object;
128 static public MethodInfo void_monitor_exit_object;
129 static public MethodInfo void_initializearray_array_fieldhandle;
130 static public MethodInfo int_getlength_int;
131 static public MethodInfo delegate_combine_delegate_delegate;
132 static public MethodInfo delegate_remove_delegate_delegate;
133 static public MethodInfo int_get_offset_to_string_data;
134 static public MethodInfo int_array_get_length;
135 static public MethodInfo int_array_get_rank;
136 static public MethodInfo object_array_clone;
137 static public MethodInfo int_array_get_length_int;
138 static public MethodInfo int_array_get_lower_bound_int;
139 static public MethodInfo int_array_get_upper_bound_int;
140 static public MethodInfo void_array_copyto_array_int;
143 // The attribute constructors.
145 static public ConstructorInfo cons_param_array_attribute;
146 static public ConstructorInfo void_decimal_ctor_five_args;
147 static public ConstructorInfo unverifiable_code_ctor;
150 // Holds the Array of Assemblies that have been loaded
151 // (either because it is the default or the user used the
152 // -r command line option)
154 static Assembly [] assemblies;
157 // Keeps a list of module builders. We used this to do lookups
158 // on the modulebuilder using GetType -- needed for arrays
160 static ModuleBuilder [] modules;
163 // This is the type_cache from the assemblies to avoid
164 // hitting System.Reflection on every lookup.
166 static Hashtable types;
169 // This is used to hotld the corresponding TypeContainer objects
170 // since we need this in FindMembers
172 static Hashtable typecontainers;
175 // Keeps track of those types that are defined by the
178 static ArrayList user_types;
180 static PtrHashtable builder_to_declspace;
183 // Tracks the interfaces implemented by typebuilders. We only
184 // enter those who do implement or or more interfaces
186 static PtrHashtable builder_to_ifaces;
189 // Maps MethodBase.RuntimeTypeHandle to a Type array that contains
190 // the arguments to the method
192 static Hashtable method_arguments;
195 // Maps PropertyBuilder to a Type array that contains
196 // the arguments to the indexer
198 static Hashtable indexer_arguments;
201 // Maybe `method_arguments' should be replaced and only
202 // method_internal_params should be kept?
204 static Hashtable method_internal_params;
207 // Keeps track of attribute types
210 static Hashtable builder_to_attr;
213 // Keeps track of methods
216 static Hashtable builder_to_method;
224 /// A filter for Findmembers that uses the Signature object to
227 static bool SignatureFilter (MemberInfo mi, object criteria)
229 Signature sig = (Signature) criteria;
231 if (!(mi is MethodBase))
234 if (mi.Name != sig.name)
237 int count = sig.args.Length;
239 if (mi is MethodBuilder || mi is ConstructorBuilder){
240 Type [] candidate_args = GetArgumentTypes ((MethodBase) mi);
242 if (candidate_args.Length != count)
245 for (int i = 0; i < count; i++)
246 if (candidate_args [i] != sig.args [i])
251 ParameterInfo [] pars = ((MethodBase) mi).GetParameters ();
253 if (pars.Length != count)
256 for (int i = 0; i < count; i++)
257 if (pars [i].ParameterType != sig.args [i])
263 // A delegate that points to the filter above.
264 static MemberFilter signature_filter;
267 // These are expressions that represent some of the internal data types, used
270 static void InitExpressionTypes ()
272 system_object_expr = new TypeLookupExpression ("System.Object");
273 system_string_expr = new TypeLookupExpression ("System.String");
274 system_boolean_expr = new TypeLookupExpression ("System.Boolean");
275 system_decimal_expr = new TypeLookupExpression ("System.Decimal");
276 system_single_expr = new TypeLookupExpression ("System.Single");
277 system_double_expr = new TypeLookupExpression ("System.Double");
278 system_sbyte_expr = new TypeLookupExpression ("System.SByte");
279 system_byte_expr = new TypeLookupExpression ("System.Byte");
280 system_int16_expr = new TypeLookupExpression ("System.Int16");
281 system_uint16_expr = new TypeLookupExpression ("System.UInt16");
282 system_int32_expr = new TypeLookupExpression ("System.Int32");
283 system_uint32_expr = new TypeLookupExpression ("System.UInt32");
284 system_int64_expr = new TypeLookupExpression ("System.Int64");
285 system_uint64_expr = new TypeLookupExpression ("System.UInt64");
286 system_char_expr = new TypeLookupExpression ("System.Char");
287 system_void_expr = new TypeLookupExpression ("System.Void");
288 system_asynccallback_expr = new TypeLookupExpression ("System.AsyncCallback");
289 system_iasyncresult_expr = new TypeLookupExpression ("System.IAsyncResult");
292 static TypeManager ()
294 assemblies = new Assembly [0];
296 user_types = new ArrayList ();
298 types = new Hashtable ();
299 typecontainers = new Hashtable ();
301 builder_to_declspace = new PtrHashtable ();
302 builder_to_attr = new PtrHashtable ();
303 builder_to_method = new PtrHashtable ();
304 method_arguments = new PtrHashtable ();
305 method_internal_params = new PtrHashtable ();
306 indexer_arguments = new PtrHashtable ();
307 builder_to_ifaces = new PtrHashtable ();
309 NoTypes = new Type [0];
311 signature_filter = new MemberFilter (SignatureFilter);
312 InitExpressionTypes ();
315 public static void AddUserType (string name, TypeBuilder t, Type [] ifaces)
320 Type prev = (Type) types [name];
321 TypeContainer tc = builder_to_declspace [prev] as TypeContainer;
325 // This probably never happens, as we catch this before
327 Report.Error (-17, "The type `" + name + "' has already been defined.");
331 tc = builder_to_declspace [t] as TypeContainer;
334 1595, "The type `" + name + "' is defined in an existing assembly;"+
335 " Using the new definition from: " + tc.Location);
336 Report.Warning (1595, "Previously defined in: " + prev.Assembly.FullName);
344 builder_to_ifaces [t] = ifaces;
348 // This entry point is used by types that we define under the covers
350 public static void RegisterBuilder (TypeBuilder tb, Type [] ifaces)
353 builder_to_ifaces [tb] = ifaces;
356 public static void AddUserType (string name, TypeBuilder t, TypeContainer tc, Type [] ifaces)
358 builder_to_declspace.Add (t, tc);
359 typecontainers.Add (name, tc);
360 AddUserType (name, t, ifaces);
363 public static void AddDelegateType (string name, TypeBuilder t, Delegate del)
366 builder_to_declspace.Add (t, del);
369 public static void AddEnumType (string name, TypeBuilder t, Enum en)
372 builder_to_declspace.Add (t, en);
375 public static void AddUserInterface (string name, TypeBuilder t, Interface i, Type [] ifaces)
377 AddUserType (name, t, ifaces);
378 builder_to_declspace.Add (t, i);
381 public static void AddMethod (MethodBuilder builder, MethodData method)
383 builder_to_method.Add (builder, method);
386 public static void RegisterAttrType (Type t, TypeContainer tc)
388 builder_to_attr.Add (t, tc);
392 /// Returns the TypeContainer whose Type is `t' or null if there is no
393 /// TypeContainer for `t' (ie, the Type comes from a library)
395 public static TypeContainer LookupTypeContainer (Type t)
397 return builder_to_declspace [t] as TypeContainer;
400 public static IMemberContainer LookupMemberContainer (Type t)
402 if (t is TypeBuilder) {
403 IMemberContainer container = builder_to_declspace [t] as IMemberContainer;
404 if (container != null)
408 return TypeHandle.GetTypeHandle (t);
411 public static Interface LookupInterface (Type t)
413 return builder_to_declspace [t] as Interface;
416 public static Delegate LookupDelegate (Type t)
418 return builder_to_declspace [t] as Delegate;
421 public static Enum LookupEnum (Type t)
423 return builder_to_declspace [t] as Enum;
426 public static TypeContainer LookupAttr (Type t)
428 return (TypeContainer) builder_to_attr [t];
432 /// Registers an assembly to load types from.
434 public static void AddAssembly (Assembly a)
436 int top = assemblies.Length;
437 Assembly [] n = new Assembly [top + 1];
439 assemblies.CopyTo (n, 0);
446 /// Registers a module builder to lookup types from
448 public static void AddModule (ModuleBuilder mb)
450 int top = modules != null ? modules.Length : 0;
451 ModuleBuilder [] n = new ModuleBuilder [top + 1];
454 modules.CopyTo (n, 0);
460 /// Returns the Type associated with @name
462 public static Type LookupType (string name)
467 // First lookup in user defined and cached values
470 t = (Type) types [name];
474 foreach (Assembly a in assemblies){
475 t = a.GetType (name);
483 foreach (ModuleBuilder mb in modules) {
484 t = mb.GetType (name);
495 /// Returns the C# name of a type if possible, or the full type name otherwise
497 static public string CSharpName (Type t)
499 return Regex.Replace (t.FullName,
501 @"(Int32|UInt32|Int16|Uint16|Int64|UInt64|" +
502 @"Single|Double|Char|Decimal|Byte|SByte|Object|" +
503 @"Boolean|String|Void)" +
505 new MatchEvaluator (CSharpNameMatch));
508 static String CSharpNameMatch (Match match)
510 string s = match.Groups [1].Captures [0].Value;
512 Replace ("int32", "int").
513 Replace ("uint32", "uint").
514 Replace ("int16", "short").
515 Replace ("uint16", "ushort").
516 Replace ("int64", "long").
517 Replace ("uint64", "ulong").
518 Replace ("single", "float").
519 Replace ("boolean", "bool")
520 + match.Groups [2].Captures [0].Value;
524 /// Returns the signature of the method
526 static public string CSharpSignature (MethodBase mb)
531 // FIXME: We should really have a single function to do
532 // everything instead of the following 5 line pattern
534 ParameterData iparams = LookupParametersByBuilder (mb);
536 if (iparams == null){
537 ParameterInfo [] pi = mb.GetParameters ();
538 iparams = new ReflectionParameters (pi);
541 for (int i = 0; i < iparams.Count; i++) {
545 sig += iparams.ParameterDesc(i);
549 return mb.DeclaringType.Name + "." + mb.Name + sig;
553 /// Looks up a type, and aborts if it is not found. This is used
554 /// by types required by the compiler
556 static Type CoreLookupType (string name)
558 Type t = LookupType (name);
561 Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
562 Environment.Exit (0);
569 /// Returns the MethodInfo for a method named `name' defined
570 /// in type `t' which takes arguments of types `args'
572 static MethodInfo GetMethod (Type t, string name, Type [] args)
580 list = FindMembers (t, MemberTypes.Method, instance_and_static | BindingFlags.Public,
581 signature_filter, sig);
582 if (list.Count == 0) {
583 Report.Error (-19, "Can not find the core function `" + name + "'");
587 MethodInfo mi = list [0] as MethodInfo;
589 Report.Error (-19, "Can not find the core function `" + name + "'");
597 /// Returns the ConstructorInfo for "args"
599 static ConstructorInfo GetConstructor (Type t, Type [] args)
607 list = FindMembers (t, MemberTypes.Constructor,
608 instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly,
609 signature_filter, sig);
610 if (list.Count == 0){
611 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
615 ConstructorInfo ci = list [0] as ConstructorInfo;
617 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
624 public static void InitEnumUnderlyingTypes ()
627 int32_type = CoreLookupType ("System.Int32");
628 int64_type = CoreLookupType ("System.Int64");
629 uint32_type = CoreLookupType ("System.UInt32");
630 uint64_type = CoreLookupType ("System.UInt64");
631 byte_type = CoreLookupType ("System.Byte");
632 sbyte_type = CoreLookupType ("System.SByte");
633 short_type = CoreLookupType ("System.Int16");
634 ushort_type = CoreLookupType ("System.UInt16");
638 /// The types have to be initialized after the initial
639 /// population of the type has happened (for example, to
640 /// bootstrap the corlib.dll
642 public static void InitCoreTypes ()
644 object_type = CoreLookupType ("System.Object");
645 value_type = CoreLookupType ("System.ValueType");
647 InitEnumUnderlyingTypes ();
649 char_type = CoreLookupType ("System.Char");
650 string_type = CoreLookupType ("System.String");
651 float_type = CoreLookupType ("System.Single");
652 double_type = CoreLookupType ("System.Double");
653 char_ptr_type = CoreLookupType ("System.Char*");
654 decimal_type = CoreLookupType ("System.Decimal");
655 bool_type = CoreLookupType ("System.Boolean");
656 enum_type = CoreLookupType ("System.Enum");
658 multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
659 delegate_type = CoreLookupType ("System.Delegate");
661 array_type = CoreLookupType ("System.Array");
662 void_type = CoreLookupType ("System.Void");
663 type_type = CoreLookupType ("System.Type");
665 runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
666 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
667 default_member_type = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
668 runtime_handle_type = CoreLookupType ("System.RuntimeTypeHandle");
669 asynccallback_type = CoreLookupType ("System.AsyncCallback");
670 iasyncresult_type = CoreLookupType ("System.IAsyncResult");
671 ienumerator_type = CoreLookupType ("System.Collections.IEnumerator");
672 idisposable_type = CoreLookupType ("System.IDisposable");
673 icloneable_type = CoreLookupType ("System.ICloneable");
674 monitor_type = CoreLookupType ("System.Threading.Monitor");
675 intptr_type = CoreLookupType ("System.IntPtr");
677 attribute_type = CoreLookupType ("System.Attribute");
678 attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
679 dllimport_type = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute");
680 methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute");
681 marshal_as_attr_type = CoreLookupType ("System.Runtime.InteropServices.MarshalAsAttribute");
682 param_array_type = CoreLookupType ("System.ParamArrayAttribute");
684 unverifiable_code_type= CoreLookupType ("System.Security.UnverifiableCodeAttribute");
686 void_ptr_type = CoreLookupType ("System.Void*");
688 indexer_name_type = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute");
690 exception_type = CoreLookupType ("System.Exception");
695 obsolete_attribute_type = CoreLookupType ("System.ObsoleteAttribute");
696 conditional_attribute_type = CoreLookupType ("System.Diagnostics.ConditionalAttribute");
699 // When compiling corlib, store the "real" types here.
701 if (!RootContext.StdLib) {
702 system_int32_type = typeof (System.Int32);
703 system_array_type = typeof (System.Array);
704 system_type_type = typeof (System.Type);
705 system_assemblybuilder_type = typeof (System.Reflection.Emit.AssemblyBuilder);
707 Type [] void_arg = { };
708 system_int_array_get_length = GetMethod (
709 system_array_type, "get_Length", void_arg);
710 system_int_array_get_rank = GetMethod (
711 system_array_type, "get_Rank", void_arg);
712 system_object_array_clone = GetMethod (
713 system_array_type, "Clone", void_arg);
715 Type [] system_int_arg = { system_int32_type };
716 system_int_array_get_length_int = GetMethod (
717 system_array_type, "GetLength", system_int_arg);
718 system_int_array_get_upper_bound_int = GetMethod (
719 system_array_type, "GetUpperBound", system_int_arg);
720 system_int_array_get_lower_bound_int = GetMethod (
721 system_array_type, "GetLowerBound", system_int_arg);
723 Type [] system_array_int_arg = { system_array_type, system_int32_type };
724 system_void_array_copyto_array_int = GetMethod (
725 system_array_type, "CopyTo", system_array_int_arg);
727 Type [] system_type_type_arg = { system_type_type, system_type_type, system_type_type };
730 system_void_set_corlib_type_builders = GetMethod (
731 system_assemblybuilder_type, "SetCorlibTypeBuilders",
732 system_type_type_arg);
734 object[] args = new object [3];
735 args [0] = object_type;
736 args [1] = value_type;
737 args [2] = enum_type;
739 system_void_set_corlib_type_builders.Invoke (CodeGen.AssemblyBuilder, args);
741 Console.WriteLine ("Corlib compilation is not supported in Microsoft.NET due to bugs in it");
747 // The helper methods that are used by the compiler
749 public static void InitCodeHelpers ()
752 // Now load the default methods that we use.
754 Type [] string_string = { string_type, string_type };
755 string_concat_string_string = GetMethod (
756 string_type, "Concat", string_string);
758 Type [] object_object = { object_type, object_type };
759 string_concat_object_object = GetMethod (
760 string_type, "Concat", object_object);
762 Type [] string_ = { string_type };
763 string_isinterneted_string = GetMethod (
764 string_type, "IsInterned", string_);
766 Type [] runtime_type_handle = { runtime_handle_type };
767 system_type_get_type_from_handle = GetMethod (
768 type_type, "GetTypeFromHandle", runtime_type_handle);
770 Type [] delegate_delegate = { delegate_type, delegate_type };
771 delegate_combine_delegate_delegate = GetMethod (
772 delegate_type, "Combine", delegate_delegate);
774 delegate_remove_delegate_delegate = GetMethod (
775 delegate_type, "Remove", delegate_delegate);
780 Type [] void_arg = { };
781 object_getcurrent_void = GetMethod (
782 ienumerator_type, "get_Current", void_arg);
783 bool_movenext_void = GetMethod (
784 ienumerator_type, "MoveNext", void_arg);
785 void_dispose_void = GetMethod (
786 idisposable_type, "Dispose", void_arg);
787 int_get_offset_to_string_data = GetMethod (
788 runtime_helpers_type, "get_OffsetToStringData", void_arg);
789 int_array_get_length = GetMethod (
790 array_type, "get_Length", void_arg);
791 int_array_get_rank = GetMethod (
792 array_type, "get_Rank", void_arg);
797 Type [] int_arg = { int32_type };
798 int_array_get_length_int = GetMethod (
799 array_type, "GetLength", int_arg);
800 int_array_get_upper_bound_int = GetMethod (
801 array_type, "GetUpperBound", int_arg);
802 int_array_get_lower_bound_int = GetMethod (
803 array_type, "GetLowerBound", int_arg);
806 // System.Array methods
808 object_array_clone = GetMethod (
809 array_type, "Clone", void_arg);
810 Type [] array_int_arg = { array_type, int32_type };
811 void_array_copyto_array_int = GetMethod (
812 array_type, "CopyTo", array_int_arg);
817 Type [] object_arg = { object_type };
818 void_monitor_enter_object = GetMethod (
819 monitor_type, "Enter", object_arg);
820 void_monitor_exit_object = GetMethod (
821 monitor_type, "Exit", object_arg);
823 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
825 void_initializearray_array_fieldhandle = GetMethod (
826 runtime_helpers_type, "InitializeArray", array_field_handle_arg);
831 int_getlength_int = GetMethod (
832 array_type, "GetLength", int_arg);
835 // Decimal constructors
837 Type [] dec_arg = { int32_type, int32_type, int32_type, bool_type, byte_type };
838 void_decimal_ctor_five_args = GetConstructor (
839 decimal_type, dec_arg);
844 cons_param_array_attribute = GetConstructor (
845 param_array_type, void_arg);
847 unverifiable_code_ctor = GetConstructor (
848 unverifiable_code_type, void_arg);
852 const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
854 static Hashtable type_hash = new Hashtable ();
857 /// This is the "old", non-cache based FindMembers() function. We cannot use
858 /// the cache here because there is no member name argument.
860 public static MemberList FindMembers (Type t, MemberTypes mt, BindingFlags bf,
861 MemberFilter filter, object criteria)
863 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
866 // `builder_to_declspace' contains all dynamic types.
870 Timer.StartTimer (TimerType.FindMembers);
871 list = decl.FindMembers (mt, bf, filter, criteria);
872 Timer.StopTimer (TimerType.FindMembers);
877 // We have to take care of arrays specially, because GetType on
878 // a TypeBuilder array will return a Type, not a TypeBuilder,
879 // and we can not call FindMembers on this type.
881 if (t.IsSubclassOf (TypeManager.array_type))
882 return new MemberList (TypeManager.array_type.FindMembers (mt, bf, filter, criteria));
885 // Since FindMembers will not lookup both static and instance
886 // members, we emulate this behaviour here.
888 if ((bf & instance_and_static) == instance_and_static){
889 MemberInfo [] i_members = t.FindMembers (
890 mt, bf & ~BindingFlags.Static, filter, criteria);
892 int i_len = i_members.Length;
894 MemberInfo one = i_members [0];
897 // If any of these are present, we are done!
899 if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
900 return new MemberList (i_members);
903 MemberInfo [] s_members = t.FindMembers (
904 mt, bf & ~BindingFlags.Instance, filter, criteria);
906 int s_len = s_members.Length;
907 if (i_len > 0 || s_len > 0)
908 return new MemberList (i_members, s_members);
911 return new MemberList (i_members);
913 return new MemberList (s_members);
917 return new MemberList (t.FindMembers (mt, bf, filter, criteria));
922 /// This method is only called from within MemberLookup. It tries to use the member
923 /// cache if possible and falls back to the normal FindMembers if not. The `used_cache'
924 /// flag tells the caller whether we used the cache or not. If we used the cache, then
925 /// our return value will already contain all inherited members and the caller don't need
926 /// to check base classes and interfaces anymore.
928 private static MemberList MemberLookup_FindMembers (Type t, MemberTypes mt, BindingFlags bf,
929 string name, out bool used_cache)
932 // We have to take care of arrays specially, because GetType on
933 // a TypeBuilder array will return a Type, not a TypeBuilder,
934 // and we can not call FindMembers on this type.
936 if (t.IsSubclassOf (TypeManager.array_type)) {
938 return TypeHandle.ArrayType.MemberCache.FindMembers (
939 mt, bf, name, FilterWithClosure_delegate, null);
943 // If this is a dynamic type, it's always in the `builder_to_declspace' hash table
944 // and we can ask the DeclSpace for the MemberCache.
946 if (t is TypeBuilder) {
947 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
948 MemberCache cache = decl.MemberCache;
951 // If this DeclSpace has a MemberCache, use it.
956 return cache.FindMembers (
957 mt, bf, name, FilterWithClosure_delegate, null);
960 // If there is no MemberCache, we need to use the "normal" FindMembers.
963 Timer.StartTimer (TimerType.FindMembers);
964 list = decl.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
965 FilterWithClosure_delegate, name);
966 Timer.StopTimer (TimerType.FindMembers);
972 // This call will always succeed. There is exactly one TypeHandle instance per
973 // type, TypeHandle.GetTypeHandle() will either return it or create a new one
974 // if it didn't already exist.
976 TypeHandle handle = TypeHandle.GetTypeHandle (t);
979 return handle.MemberCache.FindMembers (mt, bf, name, FilterWithClosure_delegate, null);
982 public static bool IsBuiltinType (Type t)
984 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
985 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
986 t == char_type || t == short_type || t == decimal_type || t == bool_type ||
987 t == sbyte_type || t == byte_type || t == ushort_type || t == void_type)
993 public static bool IsDelegateType (Type t)
995 if (t.IsSubclassOf (TypeManager.delegate_type))
1001 public static bool IsEnumType (Type t)
1003 if (t.IsSubclassOf (TypeManager.enum_type))
1009 public static bool IsValueType (Type t)
1011 if (t.IsSubclassOf (TypeManager.value_type))
1017 public static bool IsInterfaceType (Type t)
1019 Interface iface = builder_to_declspace [t] as Interface;
1028 // Checks whether `type' is a subclass or nested child of `parent'.
1030 public static bool IsSubclassOrNestedChildOf (Type type, Type parent)
1033 if ((type == parent) || type.IsSubclassOf (parent))
1036 // Handle nested types.
1037 type = type.DeclaringType;
1038 } while (type != null);
1044 /// Returns the User Defined Types
1046 public static ArrayList UserTypes {
1052 public static Hashtable TypeContainers {
1054 return typecontainers;
1058 static Hashtable builder_to_constant;
1060 public static void RegisterConstant (FieldBuilder fb, Const c)
1062 if (builder_to_constant == null)
1063 builder_to_constant = new PtrHashtable ();
1065 if (builder_to_constant.Contains (fb))
1068 builder_to_constant.Add (fb, c);
1071 public static Const LookupConstant (FieldBuilder fb)
1073 if (builder_to_constant == null)
1076 return (Const) builder_to_constant [fb];
1080 /// Gigantic work around for missing features in System.Reflection.Emit follows.
1084 /// Since System.Reflection.Emit can not return MethodBase.GetParameters
1085 /// for anything which is dynamic, and we need this in a number of places,
1086 /// we register this information here, and use it afterwards.
1088 static public bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
1093 method_arguments.Add (mb, args);
1094 method_internal_params.Add (mb, ip);
1099 static public InternalParameters LookupParametersByBuilder (MethodBase mb)
1101 if (! (mb is ConstructorBuilder || mb is MethodBuilder))
1104 if (method_internal_params.Contains (mb))
1105 return (InternalParameters) method_internal_params [mb];
1107 throw new Exception ("Argument for Method not registered" + mb);
1111 /// Returns the argument types for a method based on its methodbase
1113 /// For dynamic methods, we use the compiler provided types, for
1114 /// methods from existing assemblies we load them from GetParameters,
1115 /// and insert them into the cache
1117 static public Type [] GetArgumentTypes (MethodBase mb)
1119 if (method_arguments.Contains (mb))
1120 return (Type []) method_arguments [mb];
1122 ParameterInfo [] pi = mb.GetParameters ();
1124 Type [] types = new Type [c];
1126 for (int i = 0; i < c; i++)
1127 types [i] = pi [i].ParameterType;
1129 method_arguments.Add (mb, types);
1135 /// Returns the argument types for an indexer based on its PropertyInfo
1137 /// For dynamic indexers, we use the compiler provided types, for
1138 /// indexers from existing assemblies we load them from GetParameters,
1139 /// and insert them into the cache
1141 static public Type [] GetArgumentTypes (PropertyInfo indexer)
1143 if (indexer_arguments.Contains (indexer))
1144 return (Type []) indexer_arguments [indexer];
1145 else if (indexer is PropertyBuilder)
1146 // If we're a PropertyBuilder and not in the
1147 // `indexer_arguments' hash, then we're a property and
1151 ParameterInfo [] pi = indexer.GetIndexParameters ();
1152 // Property, not an indexer.
1156 Type [] types = new Type [c];
1158 for (int i = 0; i < c; i++)
1159 types [i] = pi [i].ParameterType;
1161 indexer_arguments.Add (indexer, types);
1167 // This is a workaround the fact that GetValue is not
1168 // supported for dynamic types
1170 static Hashtable fields = new Hashtable ();
1171 static public bool RegisterFieldValue (FieldBuilder fb, object value)
1173 if (fields.Contains (fb))
1176 fields.Add (fb, value);
1181 static public object GetValue (FieldBuilder fb)
1186 static Hashtable fieldbuilders_to_fields = new Hashtable ();
1187 static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f)
1189 if (fieldbuilders_to_fields.Contains (fb))
1192 fieldbuilders_to_fields.Add (fb, f);
1196 static public FieldBase GetField (FieldInfo fb)
1198 return (FieldBase) fieldbuilders_to_fields [fb];
1201 static Hashtable events;
1203 static public bool RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
1206 events = new Hashtable ();
1208 if (events.Contains (eb))
1211 events.Add (eb, new Pair (add, remove));
1216 static public MethodInfo GetAddMethod (EventInfo ei)
1218 if (ei is MyEventBuilder) {
1219 Pair pair = (Pair) events [ei];
1221 return (MethodInfo) pair.First;
1223 return ei.GetAddMethod ();
1226 static public MethodInfo GetRemoveMethod (EventInfo ei)
1228 if (ei is MyEventBuilder) {
1229 Pair pair = (Pair) events [ei];
1231 return (MethodInfo) pair.Second;
1233 return ei.GetAddMethod ();
1236 static Hashtable priv_fields_events;
1238 static public bool RegisterPrivateFieldOfEvent (EventInfo einfo, FieldBuilder builder)
1240 if (priv_fields_events == null)
1241 priv_fields_events = new Hashtable ();
1243 if (priv_fields_events.Contains (einfo))
1246 priv_fields_events.Add (einfo, builder);
1251 static public MemberInfo GetPrivateFieldOfEvent (EventInfo ei)
1253 return (MemberInfo) priv_fields_events [ei];
1256 static Hashtable properties;
1258 static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
1260 if (properties == null)
1261 properties = new Hashtable ();
1263 if (properties.Contains (pb))
1266 properties.Add (pb, new Pair (get, set));
1271 static public bool RegisterIndexer (PropertyBuilder pb, MethodBase get, MethodBase set, Type[] args)
1273 if (!RegisterProperty (pb, get,set))
1276 indexer_arguments.Add (pb, args);
1282 // FIXME: we need to return the accessors depending on whether
1283 // they are visible or not.
1285 static public MethodInfo [] GetAccessors (PropertyInfo pi)
1289 if (pi is PropertyBuilder){
1290 Pair pair = (Pair) properties [pi];
1292 ret = new MethodInfo [2];
1293 ret [0] = (MethodInfo) pair.First;
1294 ret [1] = (MethodInfo) pair.Second;
1298 MethodInfo [] mi = new MethodInfo [2];
1301 // Why this and not pi.GetAccessors?
1302 // Because sometimes index 0 is the getter
1303 // sometimes it is 1
1305 mi [0] = pi.GetGetMethod (true);
1306 mi [1] = pi.GetSetMethod (true);
1312 static public MethodInfo GetPropertyGetter (PropertyInfo pi)
1314 if (pi is PropertyBuilder){
1315 Pair de = (Pair) properties [pi];
1317 return (MethodInfo) de.Second;
1319 return pi.GetSetMethod ();
1322 static public MethodInfo GetPropertySetter (PropertyInfo pi)
1324 if (pi is PropertyBuilder){
1325 Pair de = (Pair) properties [pi];
1327 return (MethodInfo) de.First;
1329 return pi.GetGetMethod ();
1333 /// Given an array of interface types, expand and eliminate repeated ocurrences
1334 /// of an interface.
1338 /// This expands in context like: IA; IB : IA; IC : IA, IB; the interface "IC" to
1341 public static Type [] ExpandInterfaces (Type [] base_interfaces)
1343 ArrayList new_ifaces = new ArrayList ();
1345 foreach (Type iface in base_interfaces){
1346 if (!new_ifaces.Contains (iface))
1347 new_ifaces.Add (iface);
1349 Type [] implementing = TypeManager.GetInterfaces (iface);
1351 foreach (Type imp in implementing){
1352 if (!new_ifaces.Contains (imp))
1353 new_ifaces.Add (imp);
1356 Type [] ret = new Type [new_ifaces.Count];
1357 new_ifaces.CopyTo (ret, 0);
1362 /// This function returns the interfaces in the type `t'. Works with
1363 /// both types and TypeBuilders.
1365 public static Type [] GetInterfaces (Type t)
1368 // The reason for catching the Array case is that Reflection.Emit
1369 // will not return a TypeBuilder for Array types of TypeBuilder types,
1370 // but will still throw an exception if we try to call GetInterfaces
1373 // Since the array interfaces are always constant, we return those for
1378 t = TypeManager.array_type;
1380 if (t is TypeBuilder){
1381 Type [] parent_ifaces;
1383 if (t.BaseType == null)
1384 parent_ifaces = NoTypes;
1386 parent_ifaces = GetInterfaces (t.BaseType);
1387 Type [] type_ifaces = (Type []) builder_to_ifaces [t];
1388 if (type_ifaces == null)
1389 type_ifaces = NoTypes;
1391 int parent_count = parent_ifaces.Length;
1392 Type [] result = new Type [parent_count + type_ifaces.Length];
1393 parent_ifaces.CopyTo (result, 0);
1394 type_ifaces.CopyTo (result, parent_count);
1398 return t.GetInterfaces ();
1402 /// The following is used to check if a given type implements an interface.
1403 /// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
1405 public static bool ImplementsInterface (Type t, Type iface)
1410 // FIXME OPTIMIZATION:
1411 // as soon as we hit a non-TypeBuiler in the interface
1412 // chain, we could return, as the `Type.GetInterfaces'
1413 // will return all the interfaces implement by the type
1417 interfaces = GetInterfaces (t);
1419 if (interfaces != null){
1420 foreach (Type i in interfaces){
1427 } while (t != null);
1432 // This is a custom version of Convert.ChangeType() which works
1433 // with the TypeBuilder defined types when compiling corlib.
1434 public static object ChangeType (object value, Type conversionType)
1436 if (!(value is IConvertible))
1437 throw new ArgumentException ();
1439 IConvertible convertValue = (IConvertible) value;
1440 CultureInfo ci = CultureInfo.CurrentCulture;
1441 NumberFormatInfo provider = ci.NumberFormat;
1444 // We must use Type.Equals() here since `conversionType' is
1445 // the TypeBuilder created version of a system type and not
1446 // the system type itself. You cannot use Type.GetTypeCode()
1447 // on such a type - it'd always return TypeCode.Object.
1449 if (conversionType.Equals (typeof (Boolean)))
1450 return (object)(convertValue.ToBoolean (provider));
1451 else if (conversionType.Equals (typeof (Byte)))
1452 return (object)(convertValue.ToByte (provider));
1453 else if (conversionType.Equals (typeof (Char)))
1454 return (object)(convertValue.ToChar (provider));
1455 else if (conversionType.Equals (typeof (DateTime)))
1456 return (object)(convertValue.ToDateTime (provider));
1457 else if (conversionType.Equals (typeof (Decimal)))
1458 return (object)(convertValue.ToDecimal (provider));
1459 else if (conversionType.Equals (typeof (Double)))
1460 return (object)(convertValue.ToDouble (provider));
1461 else if (conversionType.Equals (typeof (Int16)))
1462 return (object)(convertValue.ToInt16 (provider));
1463 else if (conversionType.Equals (typeof (Int32)))
1464 return (object)(convertValue.ToInt32 (provider));
1465 else if (conversionType.Equals (typeof (Int64)))
1466 return (object)(convertValue.ToInt64 (provider));
1467 else if (conversionType.Equals (typeof (SByte)))
1468 return (object)(convertValue.ToSByte (provider));
1469 else if (conversionType.Equals (typeof (Single)))
1470 return (object)(convertValue.ToSingle (provider));
1471 else if (conversionType.Equals (typeof (String)))
1472 return (object)(convertValue.ToString (provider));
1473 else if (conversionType.Equals (typeof (UInt16)))
1474 return (object)(convertValue.ToUInt16 (provider));
1475 else if (conversionType.Equals (typeof (UInt32)))
1476 return (object)(convertValue.ToUInt32 (provider));
1477 else if (conversionType.Equals (typeof (UInt64)))
1478 return (object)(convertValue.ToUInt64 (provider));
1479 else if (conversionType.Equals (typeof (Object)))
1480 return (object)(value);
1482 throw new InvalidCastException ();
1486 // This is needed, because enumerations from assemblies
1487 // do not report their underlyingtype, but they report
1490 public static Type EnumToUnderlying (Type t)
1492 if (t == TypeManager.enum_type)
1495 t = t.UnderlyingSystemType;
1496 if (!TypeManager.IsEnumType (t))
1499 if (t is TypeBuilder) {
1500 // slow path needed to compile corlib
1501 if (t == TypeManager.bool_type ||
1502 t == TypeManager.byte_type ||
1503 t == TypeManager.sbyte_type ||
1504 t == TypeManager.char_type ||
1505 t == TypeManager.short_type ||
1506 t == TypeManager.ushort_type ||
1507 t == TypeManager.int32_type ||
1508 t == TypeManager.uint32_type ||
1509 t == TypeManager.int64_type ||
1510 t == TypeManager.uint64_type)
1512 throw new Exception ("Unhandled typecode in enum " + " from " + t.AssemblyQualifiedName);
1514 TypeCode tc = Type.GetTypeCode (t);
1517 case TypeCode.Boolean:
1518 return TypeManager.bool_type;
1520 return TypeManager.byte_type;
1521 case TypeCode.SByte:
1522 return TypeManager.sbyte_type;
1524 return TypeManager.char_type;
1525 case TypeCode.Int16:
1526 return TypeManager.short_type;
1527 case TypeCode.UInt16:
1528 return TypeManager.ushort_type;
1529 case TypeCode.Int32:
1530 return TypeManager.int32_type;
1531 case TypeCode.UInt32:
1532 return TypeManager.uint32_type;
1533 case TypeCode.Int64:
1534 return TypeManager.int64_type;
1535 case TypeCode.UInt64:
1536 return TypeManager.uint64_type;
1538 throw new Exception ("Unhandled typecode in enum " + tc + " from " + t.AssemblyQualifiedName);
1542 // When compiling corlib and called with one of the core types, return
1543 // the corresponding typebuilder for that type.
1545 public static Type TypeToCoreType (Type t)
1547 if (RootContext.StdLib || (t is TypeBuilder))
1550 TypeCode tc = Type.GetTypeCode (t);
1553 case TypeCode.Boolean:
1554 return TypeManager.bool_type;
1556 return TypeManager.byte_type;
1557 case TypeCode.SByte:
1558 return TypeManager.sbyte_type;
1560 return TypeManager.char_type;
1561 case TypeCode.Int16:
1562 return TypeManager.short_type;
1563 case TypeCode.UInt16:
1564 return TypeManager.ushort_type;
1565 case TypeCode.Int32:
1566 return TypeManager.int32_type;
1567 case TypeCode.UInt32:
1568 return TypeManager.uint32_type;
1569 case TypeCode.Int64:
1570 return TypeManager.int64_type;
1571 case TypeCode.UInt64:
1572 return TypeManager.uint64_type;
1573 case TypeCode.String:
1574 return TypeManager.string_type;
1576 if (t == typeof (void))
1577 return TypeManager.void_type;
1578 if (t == typeof (object))
1579 return TypeManager.object_type;
1580 if (t == typeof (System.Type))
1581 return TypeManager.type_type;
1587 /// Utility function that can be used to probe whether a type
1588 /// is managed or not.
1590 public static bool VerifyUnManaged (Type t, Location loc)
1592 if (t.IsValueType || t.IsPointer){
1594 // FIXME: this is more complex, we actually need to
1595 // make sure that the type does not contain any
1601 if (!RootContext.StdLib && (t == TypeManager.decimal_type))
1602 // We need this explicit check here to make it work when
1603 // compiling corlib.
1608 "Cannot take the address or size of a variable of a managed type ('" +
1609 CSharpName (t) + "')");
1614 /// Returns the name of the indexer in a given type.
1617 /// The default is not always `Item'. The user can change this behaviour by
1618 /// using the DefaultMemberAttribute in the class.
1620 /// For example, the String class indexer is named `Chars' not `Item'
1622 public static string IndexerPropertyName (Type t)
1624 if (t is TypeBuilder) {
1625 if (t.IsInterface) {
1626 Interface i = LookupInterface (t);
1628 if ((i == null) || (i.IndexerName == null))
1631 return i.IndexerName;
1633 TypeContainer tc = LookupTypeContainer (t);
1635 if ((tc == null) || (tc.IndexerName == null))
1638 return tc.IndexerName;
1642 System.Attribute attr = System.Attribute.GetCustomAttribute (
1643 t, TypeManager.default_member_type);
1645 DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
1646 return dma.MemberName;
1652 public static void MakePinned (LocalBuilder builder)
1655 // FIXME: Flag the "LocalBuilder" type as being
1656 // pinned. Figure out API.
1662 // Returns whether the array of memberinfos contains the given method
1664 static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method)
1666 Type [] new_args = TypeManager.GetArgumentTypes (new_method);
1668 foreach (MethodBase method in array){
1669 if (method.Name != new_method.Name)
1672 Type [] old_args = TypeManager.GetArgumentTypes (method);
1673 int old_count = old_args.Length;
1676 if (new_args.Length != old_count)
1679 for (i = 0; i < old_count; i++){
1680 if (old_args [i] != new_args [i])
1692 // We copy methods from `new_members' into `target_list' if the signature
1693 // for the method from in the new list does not exist in the target_list
1695 // The name is assumed to be the same.
1697 public static ArrayList CopyNewMethods (ArrayList target_list, MemberList new_members)
1699 if (target_list == null){
1700 target_list = new ArrayList ();
1702 foreach (MemberInfo mi in new_members){
1703 if (mi is MethodBase)
1704 target_list.Add (mi);
1709 MemberInfo [] target_array = new MemberInfo [target_list.Count];
1710 target_list.CopyTo (target_array, 0);
1712 foreach (MemberInfo mi in new_members){
1713 MethodBase new_method = (MethodBase) mi;
1715 if (!ArrayContainsMethod (target_array, new_method))
1716 target_list.Add (new_method);
1722 public enum MethodFlags {
1724 IsObsoleteError = 2,
1729 // Returns the TypeManager.MethodFlags for this method.
1730 // This emits an error 619 / warning 618 if the method is obsolete.
1731 // In the former case, TypeManager.MethodFlags.IsObsoleteError is returned.
1733 static public MethodFlags GetMethodFlags (MethodBase mb, Location loc)
1735 MethodFlags flags = 0;
1737 if (mb.DeclaringType is TypeBuilder){
1738 MethodData method = (MethodData) builder_to_method [mb];
1739 if (method == null) {
1740 // FIXME: implement Obsolete attribute on Property,
1741 // Indexer and Event.
1745 return method.GetMethodFlags (loc);
1748 object [] attrs = mb.GetCustomAttributes (true);
1749 foreach (object ta in attrs){
1750 if (!(ta is System.Attribute)){
1751 Console.WriteLine ("Unknown type in GetMethodFlags: " + ta);
1754 System.Attribute a = (System.Attribute) ta;
1755 if (a.TypeId == TypeManager.obsolete_attribute_type){
1756 ObsoleteAttribute oa = (ObsoleteAttribute) a;
1758 string method_desc = TypeManager.CSharpSignature (mb);
1761 Report.Error (619, loc, "Method `" + method_desc +
1762 "' is obsolete: `" + oa.Message + "'");
1763 return MethodFlags.IsObsoleteError;
1765 Report.Warning (618, loc, "Method `" + method_desc +
1766 "' is obsolete: `" + oa.Message + "'");
1768 flags |= MethodFlags.IsObsolete;
1774 // Skip over conditional code.
1776 if (a.TypeId == TypeManager.conditional_attribute_type){
1777 ConditionalAttribute ca = (ConditionalAttribute) a;
1779 if (RootContext.AllDefines [ca.ConditionString] == null)
1780 flags |= MethodFlags.ShouldIgnore;
1787 #region MemberLookup implementation
1790 // Name of the member
1792 static string closure_name;
1795 // Whether we allow private members in the result (since FindMembers
1796 // uses NonPublic for both protected and private), we need to distinguish.
1798 static bool closure_private_ok;
1801 // Who is invoking us and which type is being queried currently.
1803 static Type closure_invocation_type;
1804 static Type closure_queried_type;
1805 static Type closure_start_type;
1808 // The assembly that defines the type is that is calling us
1810 static Assembly closure_invocation_assembly;
1813 // This filter filters by name + whether it is ok to include private
1814 // members in the search
1816 static internal bool FilterWithClosure (MemberInfo m, object filter_criteria)
1819 // Hack: we know that the filter criteria will always be in the `closure'
1823 if ((filter_criteria != null) && (m.Name != (string) filter_criteria))
1826 if (closure_start_type == closure_invocation_type)
1830 // Ugly: we need to find out the type of `m', and depending
1831 // on this, tell whether we accept or not
1833 if (m is MethodBase){
1834 MethodBase mb = (MethodBase) m;
1835 MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
1837 if (ma == MethodAttributes.Private)
1838 return closure_private_ok || (closure_invocation_type == m.DeclaringType);
1841 // FamAndAssem requires that we not only derivate, but we are on the
1844 if (ma == MethodAttributes.FamANDAssem){
1845 if (closure_invocation_assembly != mb.DeclaringType.Assembly)
1849 // Assembly and FamORAssem succeed if we're in the same assembly.
1850 if ((ma == MethodAttributes.Assembly) || (ma == MethodAttributes.FamORAssem)){
1851 if (closure_invocation_assembly == mb.DeclaringType.Assembly)
1855 // We already know that we aren't in the same assembly.
1856 if (ma == MethodAttributes.Assembly)
1859 // Family and FamANDAssem require that we derive.
1860 if ((ma == MethodAttributes.Family) || (ma == MethodAttributes.FamANDAssem)){
1861 if (closure_invocation_type == null)
1864 if (!IsSubclassOrNestedChildOf (closure_invocation_type, mb.DeclaringType))
1867 // Although a derived class can access protected members of its base class
1868 // it cannot do so through an instance of the base class (CS1540).
1869 if ((closure_invocation_type != closure_start_type) &&
1870 closure_invocation_type.IsSubclassOf (closure_start_type))
1880 if (m is FieldInfo){
1881 FieldInfo fi = (FieldInfo) m;
1882 FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
1884 if (fa == FieldAttributes.Private)
1885 return closure_private_ok || (closure_invocation_type == m.DeclaringType);
1888 // FamAndAssem requires that we not only derivate, but we are on the
1891 if (fa == FieldAttributes.FamANDAssem){
1892 if (closure_invocation_assembly != fi.DeclaringType.Assembly)
1896 // Assembly and FamORAssem succeed if we're in the same assembly.
1897 if ((fa == FieldAttributes.Assembly) || (fa == FieldAttributes.FamORAssem)){
1898 if (closure_invocation_assembly == fi.DeclaringType.Assembly)
1902 // We already know that we aren't in the same assembly.
1903 if (fa == FieldAttributes.Assembly)
1906 // Family and FamANDAssem require that we derive.
1907 if ((fa == FieldAttributes.Family) || (fa == FieldAttributes.FamANDAssem)){
1908 if (closure_invocation_type == null)
1911 if (!IsSubclassOrNestedChildOf (closure_invocation_type, fi.DeclaringType))
1914 // Although a derived class can access protected members of its base class
1915 // it cannot do so through an instance of the base class (CS1540).
1916 if ((closure_invocation_type != closure_start_type) &&
1917 closure_invocation_type.IsSubclassOf (closure_start_type))
1928 // EventInfos and PropertyInfos, return true
1933 static MemberFilter FilterWithClosure_delegate = new MemberFilter (FilterWithClosure);
1936 // Looks up a member called `name' in the `queried_type'. This lookup
1937 // is done by code that is contained in the definition for `invocation_type'.
1939 // The binding flags are `bf' and the kind of members being looked up are `mt'
1941 // Returns an array of a single element for everything but Methods/Constructors
1942 // that might return multiple matches.
1944 public static MemberInfo [] MemberLookup (Type invocation_type, Type queried_type,
1945 MemberTypes mt, BindingFlags original_bf, string name)
1947 Timer.StartTimer (TimerType.MemberLookup);
1949 MemberInfo[] retval = RealMemberLookup (invocation_type, queried_type,
1950 mt, original_bf, name);
1952 Timer.StopTimer (TimerType.MemberLookup);
1957 static MemberInfo [] RealMemberLookup (Type invocation_type, Type queried_type,
1958 MemberTypes mt, BindingFlags original_bf, string name)
1960 BindingFlags bf = original_bf;
1962 ArrayList method_list = null;
1963 Type current_type = queried_type;
1964 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
1966 bool always_ok_flag = false;
1967 bool skip_iface_check = true, used_cache = false;
1969 closure_name = name;
1970 closure_invocation_type = invocation_type;
1971 closure_invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
1972 closure_start_type = queried_type;
1975 // If we are a nested class, we always have access to our container
1978 if (invocation_type != null){
1979 string invocation_name = invocation_type.FullName;
1980 if (invocation_name.IndexOf ('+') != -1){
1981 string container = queried_type.FullName + "+";
1982 int container_length = container.Length;
1984 if (invocation_name.Length > container_length){
1985 string shared = invocation_name.Substring (0, container_length);
1987 if (shared == container)
1988 always_ok_flag = true;
1997 // `NonPublic' is lame, because it includes both protected and
1998 // private methods, so we need to control this behavior by
1999 // explicitly tracking if a private method is ok or not.
2001 // The possible cases are:
2002 // public, private and protected (internal does not come into the
2005 if (invocation_type != null){
2006 if (invocation_type == current_type){
2009 private_ok = always_ok_flag;
2011 if (private_ok || invocation_type.IsSubclassOf (current_type))
2012 bf = original_bf | BindingFlags.NonPublic;
2015 bf = original_bf & ~BindingFlags.NonPublic;
2018 closure_private_ok = private_ok;
2019 closure_queried_type = current_type;
2021 Timer.StopTimer (TimerType.MemberLookup);
2023 list = MemberLookup_FindMembers (current_type, mt, bf, name, out used_cache);
2025 Timer.StartTimer (TimerType.MemberLookup);
2028 // When queried for an interface type, the cache will automatically check all
2029 // inherited members, so we don't need to do this here. However, this only
2030 // works if we already used the cache in the first iteration of this loop.
2032 // If we used the cache in any further iteration, we can still terminate the
2033 // loop since the cache always looks in all parent classes.
2039 skip_iface_check = false;
2041 if (current_type == TypeManager.object_type)
2044 current_type = current_type.BaseType;
2047 // This happens with interfaces, they have a null
2048 // basetype. Look members up in the Object class.
2050 if (current_type == null)
2051 current_type = TypeManager.object_type;
2054 if (list.Count == 0)
2058 // Events and types are returned by both `static' and `instance'
2059 // searches, which means that our above FindMembers will
2060 // return two copies of the same.
2062 if (list.Count == 1 && !(list [0] is MethodBase)){
2063 return (MemberInfo []) list;
2067 // Multiple properties: we query those just to find out the indexer
2070 if (list [0] is PropertyInfo)
2071 return (MemberInfo []) list;
2074 // We found methods, turn the search into "method scan"
2078 method_list = CopyNewMethods (method_list, list);
2079 mt &= (MemberTypes.Method | MemberTypes.Constructor);
2080 } while (searching);
2082 if (method_list != null && method_list.Count > 0)
2083 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
2086 // This happens if we already used the cache in the first iteration, in this case
2087 // the cache already looked in all interfaces.
2089 if (skip_iface_check)
2093 // Interfaces do not list members they inherit, so we have to
2096 if (!queried_type.IsInterface)
2099 if (queried_type.IsArray)
2100 queried_type = TypeManager.array_type;
2102 Type [] ifaces = GetInterfaces (queried_type);
2106 foreach (Type itype in ifaces){
2109 x = MemberLookup (null, itype, mt, bf, name);
2121 /// There is exactly one instance of this class per type.
2123 public sealed class TypeHandle : IMemberContainer {
2124 public readonly TypeHandle BaseType;
2126 readonly int id = ++next_id;
2127 static int next_id = 0;
2130 /// Lookup a TypeHandle instance for the given type. If the type doesn't have
2131 /// a TypeHandle yet, a new instance of it is created. This static method
2132 /// ensures that we'll only have one TypeHandle instance per type.
2134 public static TypeHandle GetTypeHandle (Type t)
2136 TypeHandle handle = (TypeHandle) type_hash [t];
2140 handle = new TypeHandle (t);
2141 type_hash.Add (t, handle);
2146 /// Returns the TypeHandle for TypeManager.object_type.
2148 public static IMemberContainer ObjectType {
2150 if (object_type != null)
2153 object_type = GetTypeHandle (TypeManager.object_type);
2160 /// Returns the TypeHandle for TypeManager.array_type.
2162 public static IMemberContainer ArrayType {
2164 if (array_type != null)
2167 array_type = GetTypeHandle (TypeManager.array_type);
2173 private static PtrHashtable type_hash = new PtrHashtable ();
2175 private static TypeHandle object_type = null;
2176 private static TypeHandle array_type = null;
2179 private bool is_interface;
2180 private MemberCache member_cache;
2182 private TypeHandle (Type type)
2185 if (type.BaseType != null)
2186 BaseType = GetTypeHandle (type.BaseType);
2187 else if ((type != TypeManager.object_type) && (type != typeof (object)))
2188 is_interface = true;
2189 this.member_cache = new MemberCache (this);
2192 // IMemberContainer methods
2194 public string Name {
2196 return type.FullName;
2206 public IMemberContainer Parent {
2212 public bool IsInterface {
2214 return is_interface;
2218 public MemberList GetMembers (MemberTypes mt, BindingFlags bf)
2220 return new MemberList (type.FindMembers (mt, bf | BindingFlags.DeclaredOnly, null, null));
2223 // IMemberFinder methods
2225 public MemberList FindMembers (MemberTypes mt, BindingFlags bf, string name,
2226 MemberFilter filter, object criteria)
2228 return member_cache.FindMembers (mt, bf, name, filter, criteria);
2231 public MemberCache MemberCache {
2233 return member_cache;
2237 public override string ToString ()
2239 if (BaseType != null)
2240 return "TypeHandle (" + id + "," + Name + " : " + BaseType + ")";
2242 return "TypeHandle (" + id + "," + Name + ")";