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)
14 // We will eventually remove the SIMPLE_SPEEDUP, and should never change
15 // the behavior of the compilation. This can be removed if we rework
16 // the code to get a list of namespaces available.
18 #define SIMPLE_SPEEDUP
22 using System.Globalization;
23 using System.Collections;
24 using System.Reflection;
25 using System.Reflection.Emit;
27 using System.Text.RegularExpressions;
28 using System.Runtime.CompilerServices;
29 using System.Diagnostics;
31 namespace Mono.CSharp {
33 public partial class TypeManager {
35 // A list of core types that the compiler requires or uses
37 static public Type object_type;
38 static public Type value_type;
39 static public Type string_type;
40 static public Type int32_type;
41 static public Type uint32_type;
42 static public Type int64_type;
43 static public Type uint64_type;
44 static public Type float_type;
45 static public Type double_type;
46 static public Type char_type;
47 static public Type char_ptr_type;
48 static public Type short_type;
49 static public Type decimal_type;
50 static public Type bool_type;
51 static public Type sbyte_type;
52 static public Type byte_type;
53 static public Type ushort_type;
54 static public Type enum_type;
55 static public Type delegate_type;
56 static public Type multicast_delegate_type;
57 static public Type void_type;
58 static public Type null_type;
59 static public Type enumeration_type;
60 static public Type array_type;
61 static public Type runtime_handle_type;
62 static public Type icloneable_type;
63 static public Type type_type;
64 static public Type ienumerator_type;
65 static public Type ienumerable_type;
66 static public Type idisposable_type;
67 static public Type iconvertible_type;
68 static public Type default_member_type;
69 static public Type iasyncresult_type;
70 static public Type asynccallback_type;
71 static public Type intptr_type;
72 static public Type monitor_type;
73 static public Type runtime_field_handle_type;
74 static public Type runtime_argument_handle_type;
75 static public Type attribute_type;
76 static public Type attribute_usage_type;
77 static public Type decimal_constant_attribute_type;
78 static public Type dllimport_type;
79 static public Type unverifiable_code_type;
80 static public Type methodimpl_attr_type;
81 static public Type marshal_as_attr_type;
82 static public Type param_array_type;
83 static public Type guid_attr_type;
84 static public Type void_ptr_type;
85 static public Type indexer_name_type;
86 static public Type exception_type;
87 static public Type invalid_operation_exception_type;
88 static public Type not_supported_exception_type;
89 static public Type obsolete_attribute_type;
90 static public Type conditional_attribute_type;
91 static public Type in_attribute_type;
92 static public Type out_attribute_type;
93 static public Type anonymous_method_type;
94 static public Type cls_compliant_attribute_type;
95 static public Type typed_reference_type;
96 static public Type arg_iterator_type;
97 static public Type mbr_type;
98 static public Type struct_layout_attribute_type;
99 static public Type field_offset_attribute_type;
100 static public Type security_attr_type;
103 // An empty array of types
105 static public Type [] NoTypes;
106 static public TypeExpr [] NoTypeExprs;
110 // Expressions representing the internal types. Used during declaration
113 static public TypeExpr system_object_expr, system_string_expr;
114 static public TypeExpr system_boolean_expr, system_decimal_expr;
115 static public TypeExpr system_single_expr, system_double_expr;
116 static public TypeExpr system_sbyte_expr, system_byte_expr;
117 static public TypeExpr system_int16_expr, system_uint16_expr;
118 static public TypeExpr system_int32_expr, system_uint32_expr;
119 static public TypeExpr system_int64_expr, system_uint64_expr;
120 static public TypeExpr system_char_expr, system_void_expr;
121 static public TypeExpr system_asynccallback_expr;
122 static public TypeExpr system_iasyncresult_expr;
123 static public TypeExpr system_valuetype_expr;
124 static public TypeExpr system_intptr_expr;
127 // This is only used when compiling corlib
129 static public Type system_int32_type;
130 static public Type system_array_type;
131 static public Type system_type_type;
132 static public Type system_assemblybuilder_type;
133 static public MethodInfo system_int_array_get_length;
134 static public MethodInfo system_int_array_get_rank;
135 static public MethodInfo system_object_array_clone;
136 static public MethodInfo system_int_array_get_length_int;
137 static public MethodInfo system_int_array_get_lower_bound_int;
138 static public MethodInfo system_int_array_get_upper_bound_int;
139 static public MethodInfo system_void_array_copyto_array_int;
143 // Internal, not really used outside
145 static Type runtime_helpers_type;
148 // These methods are called by code generated by the compiler
150 static public MethodInfo string_concat_string_string;
151 static public MethodInfo string_concat_string_string_string;
152 static public MethodInfo string_concat_string_string_string_string;
153 static public MethodInfo string_concat_string_dot_dot_dot;
154 static public MethodInfo string_concat_object_object;
155 static public MethodInfo string_concat_object_object_object;
156 static public MethodInfo string_concat_object_dot_dot_dot;
157 static public MethodInfo string_isinterneted_string;
158 static public MethodInfo system_type_get_type_from_handle;
159 static public MethodInfo object_getcurrent_void;
160 static public MethodInfo bool_movenext_void;
161 static public MethodInfo ienumerable_getenumerator_void;
162 static public MethodInfo void_reset_void;
163 static public MethodInfo void_dispose_void;
164 static public MethodInfo void_monitor_enter_object;
165 static public MethodInfo void_monitor_exit_object;
166 static public MethodInfo void_initializearray_array_fieldhandle;
167 static public MethodInfo int_getlength_int;
168 static public MethodInfo delegate_combine_delegate_delegate;
169 static public MethodInfo delegate_remove_delegate_delegate;
170 static public MethodInfo int_get_offset_to_string_data;
171 static public MethodInfo int_array_get_length;
172 static public MethodInfo int_array_get_rank;
173 static public MethodInfo object_array_clone;
174 static public MethodInfo int_array_get_length_int;
175 static public MethodInfo int_array_get_lower_bound_int;
176 static public MethodInfo int_array_get_upper_bound_int;
177 static public MethodInfo void_array_copyto_array_int;
180 // The attribute constructors.
182 static public ConstructorInfo object_ctor;
183 static public ConstructorInfo cons_param_array_attribute;
184 static public ConstructorInfo void_decimal_ctor_five_args;
185 static public ConstructorInfo void_decimal_ctor_int_arg;
186 static public ConstructorInfo unverifiable_code_ctor;
187 static public ConstructorInfo invalid_operation_ctor;
188 static public ConstructorInfo default_member_ctor;
189 static public ConstructorInfo decimal_constant_attribute_ctor;
192 // Holds the Array of Assemblies that have been loaded
193 // (either because it is the default or the user used the
194 // -r command line option)
196 static Assembly [] assemblies;
199 // Keeps a list of modules. We used this to do lookups
200 // on the module using GetType -- needed for arrays
202 static Module [] modules;
205 // This is the type_cache from the assemblies to avoid
206 // hitting System.Reflection on every lookup.
208 static Hashtable types;
211 // This is used to hotld the corresponding TypeContainer objects
212 // since we need this in FindMembers
214 static Hashtable typecontainers;
217 // Keeps track of those types that are defined by the
220 static ArrayList user_types;
222 static PtrHashtable builder_to_declspace;
224 static PtrHashtable builder_to_member_cache;
227 // Tracks the interfaces implemented by typebuilders. We only
228 // enter those who do implement or or more interfaces
230 static PtrHashtable builder_to_ifaces;
233 // Maps MethodBase.RuntimeTypeHandle to a Type array that contains
234 // the arguments to the method
236 static Hashtable method_arguments;
239 // Maps PropertyBuilder to a Type array that contains
240 // the arguments to the indexer
242 static Hashtable indexer_arguments;
245 // Maps a MethodBase to its ParameterData (either InternalParameters or ReflectionParameters)
247 static Hashtable method_params;
250 // Keeps track of methods
253 static Hashtable builder_to_method;
256 // Contains all public types from referenced assemblies.
257 // This member is used only if CLS Compliance verification is required.
259 public static Hashtable all_imported_types;
266 public static void CleanUp ()
268 // Lets get everything clean so that we can collect before generating code
272 typecontainers = null;
274 builder_to_declspace = null;
275 builder_to_member_cache = null;
276 builder_to_ifaces = null;
277 method_arguments = null;
278 indexer_arguments = null;
279 method_params = null;
280 builder_to_method = null;
284 negative_hits = null;
285 builder_to_constant = null;
286 fieldbuilders_to_fields = null;
288 priv_fields_events = null;
292 TypeHandle.CleanUp ();
296 /// A filter for Findmembers that uses the Signature object to
299 static bool SignatureFilter (MemberInfo mi, object criteria)
301 Signature sig = (Signature) criteria;
303 if (!(mi is MethodBase))
306 if (mi.Name != sig.name)
309 int count = sig.args.Length;
311 if (mi is MethodBuilder || mi is ConstructorBuilder){
312 Type [] candidate_args = GetArgumentTypes ((MethodBase) mi);
314 if (candidate_args.Length != count)
317 for (int i = 0; i < count; i++)
318 if (candidate_args [i] != sig.args [i])
323 ParameterInfo [] pars = ((MethodBase) mi).GetParameters ();
325 if (pars.Length != count)
328 for (int i = 0; i < count; i++)
329 if (pars [i].ParameterType != sig.args [i])
335 // A delegate that points to the filter above.
336 static MemberFilter signature_filter;
339 // These are expressions that represent some of the internal data types, used
342 static void InitExpressionTypes ()
344 system_object_expr = new TypeLookupExpression ("System.Object");
345 system_string_expr = new TypeLookupExpression ("System.String");
346 system_boolean_expr = new TypeLookupExpression ("System.Boolean");
347 system_decimal_expr = new TypeLookupExpression ("System.Decimal");
348 system_single_expr = new TypeLookupExpression ("System.Single");
349 system_double_expr = new TypeLookupExpression ("System.Double");
350 system_sbyte_expr = new TypeLookupExpression ("System.SByte");
351 system_byte_expr = new TypeLookupExpression ("System.Byte");
352 system_int16_expr = new TypeLookupExpression ("System.Int16");
353 system_uint16_expr = new TypeLookupExpression ("System.UInt16");
354 system_int32_expr = new TypeLookupExpression ("System.Int32");
355 system_uint32_expr = new TypeLookupExpression ("System.UInt32");
356 system_int64_expr = new TypeLookupExpression ("System.Int64");
357 system_uint64_expr = new TypeLookupExpression ("System.UInt64");
358 system_char_expr = new TypeLookupExpression ("System.Char");
359 system_void_expr = new TypeLookupExpression ("System.Void");
360 system_asynccallback_expr = new TypeLookupExpression ("System.AsyncCallback");
361 system_iasyncresult_expr = new TypeLookupExpression ("System.IAsyncResult");
362 system_valuetype_expr = new TypeLookupExpression ("System.ValueType");
363 system_intptr_expr = new TypeLookupExpression ("System.IntPtr");
366 static TypeManager ()
368 assemblies = new Assembly [0];
370 user_types = new ArrayList ();
372 types = new Hashtable ();
373 typecontainers = new Hashtable ();
375 builder_to_declspace = new PtrHashtable ();
376 builder_to_member_cache = new PtrHashtable ();
377 builder_to_method = new PtrHashtable ();
378 method_arguments = new PtrHashtable ();
379 method_params = new PtrHashtable ();
380 indexer_arguments = new PtrHashtable ();
381 builder_to_ifaces = new PtrHashtable ();
383 NoTypes = new Type [0];
384 NoTypeExprs = new TypeExpr [0];
386 signature_filter = new MemberFilter (SignatureFilter);
388 InitExpressionTypes ();
391 public static void HandleDuplicate (string name, Type t)
393 Type prev = (Type) types [name];
394 TypeContainer tc = builder_to_declspace [prev] as TypeContainer;
398 // This probably never happens, as we catch this before
400 Report.Error (-17, "The type `" + name + "' has already been defined.");
404 tc = builder_to_declspace [t] as TypeContainer;
407 1595, "The type `" + name + "' is defined in an existing assembly;"+
408 " Using the new definition from: " + tc.Location);
411 1595, "The type `" + name + "' is defined in an existing assembly;");
414 Report.Warning (1595, "Previously defined in: " + prev.Assembly.FullName);
420 public static void AddUserType (string name, TypeBuilder t)
425 HandleDuplicate (name, t);
431 // This entry point is used by types that we define under the covers
433 public static void RegisterBuilder (Type tb, Type [] ifaces)
436 builder_to_ifaces [tb] = ifaces;
439 public static void AddUserType (string name, TypeBuilder t, TypeContainer tc)
441 builder_to_declspace.Add (t, tc);
442 typecontainers.Add (name, tc);
443 AddUserType (name, t);
446 public static void AddDelegateType (string name, TypeBuilder t, Delegate del)
451 HandleDuplicate (name, t);
454 builder_to_declspace.Add (t, del);
457 public static void AddEnumType (string name, TypeBuilder t, Enum en)
462 HandleDuplicate (name, t);
464 builder_to_declspace.Add (t, en);
467 public static void AddMethod (MethodBase builder, IMethodData method)
469 builder_to_method.Add (builder, method);
472 public static IMethodData GetMethod (MethodBase builder)
474 return (IMethodData) builder_to_method [builder];
478 /// Returns the DeclSpace whose Type is `t' or null if there is no
479 /// DeclSpace for `t' (ie, the Type comes from a library)
481 public static DeclSpace LookupDeclSpace (Type t)
483 return builder_to_declspace [t] as DeclSpace;
487 /// Returns the TypeContainer whose Type is `t' or null if there is no
488 /// TypeContainer for `t' (ie, the Type comes from a library)
490 public static TypeContainer LookupTypeContainer (Type t)
492 return builder_to_declspace [t] as TypeContainer;
495 public static MemberCache LookupMemberCache (Type t)
497 if (t is TypeBuilder) {
498 IMemberContainer container = builder_to_declspace [t] as IMemberContainer;
499 if (container != null)
500 return container.MemberCache;
503 if (t is GenericTypeParameterBuilder) {
504 IMemberContainer container = builder_to_type_param [t] as IMemberContainer;
506 if (container != null)
507 return container.MemberCache;
510 return TypeHandle.GetMemberCache (t);
513 public static MemberCache LookupBaseInterfacesCache (Type t)
515 Type [] ifaces = t.GetInterfaces ();
517 if (ifaces != null && ifaces.Length == 1)
518 return LookupMemberCache (ifaces [0]);
520 // TODO: the builder_to_member_cache should be indexed by 'ifaces', not 't'
521 MemberCache cache = builder_to_member_cache [t] as MemberCache;
525 cache = new MemberCache (ifaces);
526 builder_to_member_cache.Add (t, cache);
530 public static TypeContainer LookupInterface (Type t)
532 TypeContainer tc = (TypeContainer) builder_to_declspace [t];
533 if ((tc == null) || (tc.Kind != Kind.Interface))
539 public static Delegate LookupDelegate (Type t)
541 return builder_to_declspace [t] as Delegate;
544 public static Enum LookupEnum (Type t)
546 return builder_to_declspace [t] as Enum;
549 public static Class LookupClass (Type t)
551 return (Class) builder_to_declspace [t];
555 /// Registers an assembly to load types from.
557 public static void AddAssembly (Assembly a)
559 foreach (Assembly assembly in assemblies) {
564 int top = assemblies.Length;
565 Assembly [] n = new Assembly [top + 1];
567 assemblies.CopyTo (n, 0);
573 public static Assembly [] GetAssemblies ()
579 /// Registers a module builder to lookup types from
581 public static void AddModule (Module mb)
583 int top = modules != null ? modules.Length : 0;
584 Module [] n = new Module [top + 1];
587 modules.CopyTo (n, 0);
592 public static Module[] Modules {
598 static Hashtable references = new Hashtable ();
601 // Gets the reference to T version of the Type (T&)
603 public static Type GetReferenceType (Type t)
605 return t.MakeByRefType ();
608 static Hashtable pointers = new Hashtable ();
611 // Gets the pointer to T version of the Type (T*)
613 public static Type GetPointerType (Type t)
615 string tname = t.FullName + "*";
617 Type ret = t.Assembly.GetType (tname);
620 // If the type comes from the assembly we are building
621 // We need the Hashtable, because .NET 1.1 will return different instance types
622 // every time we call ModuleBuilder.GetType.
625 if (pointers [t] == null)
626 pointers [t] = CodeGen.Module.Builder.GetType (tname);
628 ret = (Type) pointers [t];
635 // Low-level lookup, cache-less
637 static Type LookupTypeReflection (string name)
641 foreach (Assembly a in assemblies){
642 t = a.GetType (name);
647 TypeAttributes ta = t.Attributes & TypeAttributes.VisibilityMask;
648 if (ta == TypeAttributes.NotPublic ||
649 ta == TypeAttributes.NestedPrivate ||
650 ta == TypeAttributes.NestedAssembly ||
651 ta == TypeAttributes.NestedFamANDAssem){
654 // In .NET pointers turn out to be private, even if their
655 // element type is not
658 t = t.GetElementType ();
668 foreach (Module mb in modules) {
669 t = mb.GetType (name);
677 static Hashtable negative_hits = new Hashtable ();
680 // This function is used when you want to avoid the lookups, and want to go
681 // directly to the source. This will use the cache.
683 // Notice that bypassing the cache is bad, because on Microsoft.NET runtime
684 // GetType ("DynamicType[]") != GetType ("DynamicType[]"), and there is no
685 // way to test things other than doing a fullname compare
687 public static Type LookupTypeDirect (string name)
689 Type t = (Type) types [name];
693 t = LookupTypeReflection (name);
701 static readonly char [] dot_array = { '.' };
704 /// Returns the Type associated with @name, takes care of the fact that
705 /// reflection expects nested types to be separated from the main type
706 /// with a "+" instead of a "."
708 public static Type LookupType (string name)
713 // First lookup in user defined and cached values
716 t = (Type) types [name];
720 // Two thirds of the failures are caught here.
721 if (negative_hits.Contains (name))
724 // Sadly, split takes a param array, so this ends up allocating *EVERY TIME*
725 string [] elements = name.Split (dot_array);
726 int count = elements.Length;
728 for (int n = 1; n <= count; n++){
729 string top_level_type = String.Join (".", elements, 0, n);
731 // One third of the failures are caught here.
732 if (negative_hits.Contains (top_level_type))
735 t = (Type) types [top_level_type];
737 t = LookupTypeReflection (top_level_type);
739 negative_hits [top_level_type] = null;
750 // We know that System.Object does not have children, and since its the base of
751 // all the objects, it always gets probbed for inner classes.
753 if (top_level_type == "System.Object")
756 string newt = top_level_type + "+" + String.Join ("+", elements, n, count - n);
757 //Console.WriteLine ("Looking up: " + newt + " " + name);
758 t = LookupTypeReflection (newt);
760 negative_hits [name] = null;
765 negative_hits [name] = null;
770 /// Computes the namespaces that we import from the assemblies we reference.
772 public static void ComputeNamespaces ()
774 MethodInfo assembly_get_namespaces = typeof (Assembly).GetMethod ("GetNamespaces", BindingFlags.Instance|BindingFlags.NonPublic);
777 // First add the assembly namespaces
779 if (assembly_get_namespaces != null){
780 int count = assemblies.Length;
782 for (int i = 0; i < count; i++){
783 Assembly a = assemblies [i];
784 string [] namespaces = (string []) assembly_get_namespaces.Invoke (a, null);
785 foreach (string ns in namespaces){
788 Namespace.LookupNamespace (ns, true);
792 Hashtable cache = new Hashtable ();
793 cache.Add ("", null);
794 foreach (Assembly a in assemblies) {
795 foreach (Type t in a.GetExportedTypes ()) {
796 string ns = t.Namespace;
797 if (ns == null || cache.Contains (ns))
800 Namespace.LookupNamespace (ns, true);
801 cache.Add (ns, null);
808 /// Fills static table with exported types from all referenced assemblies.
809 /// This information is required for CLS Compliance tests.
811 public static void LoadAllImportedTypes ()
813 all_imported_types = new Hashtable ();
814 foreach (Assembly a in assemblies) {
815 foreach (Type t in a.GetExportedTypes ()) {
816 all_imported_types [t.FullName] = t;
821 public static bool NamespaceClash (string name, Location loc)
823 if (Namespace.LookupNamespace (name, false) == null)
826 Report.Error (519, loc, String.Format ("`{0}' clashes with a predefined namespace", name));
831 /// Returns the C# name of a type if possible, or the full type name otherwise
833 static public string CSharpName (Type t)
835 if (t.FullName == null)
838 return Regex.Replace (t.FullName,
840 @"(Int32|UInt32|Int16|UInt16|Int64|UInt64|" +
841 @"Single|Double|Char|Decimal|Byte|SByte|Object|" +
842 @"Boolean|String|Void|Null)" +
844 new MatchEvaluator (CSharpNameMatch)).Replace ('+', '.');
847 static String CSharpNameMatch (Match match)
849 string s = match.Groups [1].Captures [0].Value;
851 Replace ("int32", "int").
852 Replace ("uint32", "uint").
853 Replace ("int16", "short").
854 Replace ("uint16", "ushort").
855 Replace ("int64", "long").
856 Replace ("uint64", "ulong").
857 Replace ("single", "float").
858 Replace ("boolean", "bool")
859 + match.Groups [2].Captures [0].Value;
863 /// Returns the signature of the method with full namespace classification
865 static public string GetFullNameSignature (MemberInfo mi)
867 // Unfortunately, there's no dynamic dispatch on the arguments of a function.
868 return (mi is MethodBase)
869 ? GetFullNameSignature (mi as MethodBase)
870 : mi.DeclaringType.FullName.Replace ('+', '.') + '.' + mi.Name;
873 static public string GetFullNameSignature (MethodBase mb)
875 string name = mb.Name;
877 name = mb.DeclaringType.Name;
879 if (mb.IsSpecialName) {
880 if (name.StartsWith ("get_") || name.StartsWith ("set_")) {
881 name = name.Remove (0, 4);
888 return mb.DeclaringType.FullName.Replace ('+', '.') + '.' + name;
891 static public string GetFullName (Type t)
893 if (t.FullName == null)
896 string name = t.FullName.Replace ('+', '.');
898 DeclSpace tc = LookupDeclSpace (t);
899 if ((tc != null) && tc.IsGeneric) {
900 TypeParameter[] tparam = tc.TypeParameters;
902 StringBuilder sb = new StringBuilder (name);
904 for (int i = 0; i < tparam.Length; i++) {
907 sb.Append (tparam [i].Name);
910 return sb.ToString ();
911 } else if (t.HasGenericArguments && !t.IsGenericInstance) {
912 Type[] tparam = t.GetGenericArguments ();
914 StringBuilder sb = new StringBuilder (name);
916 for (int i = 0; i < tparam.Length; i++) {
919 sb.Append (tparam [i].Name);
922 return sb.ToString ();
929 /// Returns the signature of the property and indexer
931 static public string CSharpSignature (PropertyBuilder pb, bool is_indexer)
934 return GetFullNameSignature (pb);
937 MethodBase mb = pb.GetSetMethod (true) != null ? pb.GetSetMethod (true) : pb.GetGetMethod (true);
938 string signature = GetFullNameSignature (mb);
939 string arg = GetParameterData (mb).ParameterDesc (0);
940 return String.Format ("{0}.this[{1}]", signature.Substring (0, signature.LastIndexOf ('.')), arg);
944 /// Returns the signature of the method
946 static public string CSharpSignature (MethodBase mb)
948 StringBuilder sig = new StringBuilder ("(");
950 ParameterData iparams = GetParameterData (mb);
953 if (mb.IsSpecialName && iparams.Count == 0 && !mb.IsConstructor)
954 return GetFullNameSignature (mb);
956 for (int i = 0; i < iparams.Count; i++) {
960 sig.Append (iparams.ParameterDesc (i));
965 if (mb.IsSpecialName && iparams.Count == 1 && !mb.IsConstructor) {
966 sig.Replace ('(', '[');
967 sig.Replace (')', ']');
970 return GetFullNameSignature (mb) + sig.ToString ();
973 public static string GetMethodName (MethodInfo m)
975 if (!IsGenericMethod (m))
978 return MemberName.MakeName (m.Name, m.GetGenericArguments ().Length);
982 /// Looks up a type, and aborts if it is not found. This is used
983 /// by types required by the compiler
985 static Type CoreLookupType (string name)
987 Type t = LookupTypeDirect (name);
990 Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
991 Environment.Exit (1);
998 /// Returns the MethodInfo for a method named `name' defined
999 /// in type `t' which takes arguments of types `args'
1001 static MethodInfo GetMethod (Type t, string name, Type [] args, bool is_private, bool report_errors)
1005 BindingFlags flags = instance_and_static | BindingFlags.Public;
1011 flags |= BindingFlags.NonPublic;
1013 list = FindMembers (t, MemberTypes.Method, flags, signature_filter, sig);
1014 if (list.Count == 0) {
1016 Report.Error (-19, "Can not find the core function `" + name + "'");
1020 MethodInfo mi = list [0] as MethodInfo;
1023 Report.Error (-19, "Can not find the core function `" + name + "'");
1030 static MethodInfo GetMethod (Type t, string name, Type [] args, bool report_errors)
1032 return GetMethod (t, name, args, false, report_errors);
1035 static MethodInfo GetMethod (Type t, string name, Type [] args)
1037 return GetMethod (t, name, args, true);
1042 /// Returns the ConstructorInfo for "args"
1044 static ConstructorInfo GetConstructor (Type t, Type [] args)
1052 list = FindMembers (t, MemberTypes.Constructor,
1053 instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly,
1054 signature_filter, sig);
1055 if (list.Count == 0){
1056 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
1060 ConstructorInfo ci = list [0] as ConstructorInfo;
1062 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
1069 public static void InitEnumUnderlyingTypes ()
1072 int32_type = CoreLookupType ("System.Int32");
1073 int64_type = CoreLookupType ("System.Int64");
1074 uint32_type = CoreLookupType ("System.UInt32");
1075 uint64_type = CoreLookupType ("System.UInt64");
1076 byte_type = CoreLookupType ("System.Byte");
1077 sbyte_type = CoreLookupType ("System.SByte");
1078 short_type = CoreLookupType ("System.Int16");
1079 ushort_type = CoreLookupType ("System.UInt16");
1083 /// The types have to be initialized after the initial
1084 /// population of the type has happened (for example, to
1085 /// bootstrap the corlib.dll
1087 public static void InitCoreTypes ()
1089 object_type = CoreLookupType ("System.Object");
1090 value_type = CoreLookupType ("System.ValueType");
1092 InitEnumUnderlyingTypes ();
1094 char_type = CoreLookupType ("System.Char");
1095 string_type = CoreLookupType ("System.String");
1096 float_type = CoreLookupType ("System.Single");
1097 double_type = CoreLookupType ("System.Double");
1098 char_ptr_type = CoreLookupType ("System.Char*");
1099 decimal_type = CoreLookupType ("System.Decimal");
1100 bool_type = CoreLookupType ("System.Boolean");
1101 enum_type = CoreLookupType ("System.Enum");
1103 multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
1104 delegate_type = CoreLookupType ("System.Delegate");
1106 array_type = CoreLookupType ("System.Array");
1107 void_type = CoreLookupType ("System.Void");
1108 type_type = CoreLookupType ("System.Type");
1110 runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
1111 runtime_argument_handle_type = CoreLookupType ("System.RuntimeArgumentHandle");
1112 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
1113 default_member_type = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
1114 runtime_handle_type = CoreLookupType ("System.RuntimeTypeHandle");
1115 asynccallback_type = CoreLookupType ("System.AsyncCallback");
1116 iasyncresult_type = CoreLookupType ("System.IAsyncResult");
1117 ienumerator_type = CoreLookupType ("System.Collections.IEnumerator");
1118 ienumerable_type = CoreLookupType ("System.Collections.IEnumerable");
1119 idisposable_type = CoreLookupType ("System.IDisposable");
1120 icloneable_type = CoreLookupType ("System.ICloneable");
1121 iconvertible_type = CoreLookupType ("System.IConvertible");
1122 monitor_type = CoreLookupType ("System.Threading.Monitor");
1123 intptr_type = CoreLookupType ("System.IntPtr");
1125 attribute_type = CoreLookupType ("System.Attribute");
1126 attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
1127 dllimport_type = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute");
1128 methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute");
1129 marshal_as_attr_type = CoreLookupType ("System.Runtime.InteropServices.MarshalAsAttribute");
1130 param_array_type = CoreLookupType ("System.ParamArrayAttribute");
1131 in_attribute_type = CoreLookupType ("System.Runtime.InteropServices.InAttribute");
1132 out_attribute_type = CoreLookupType ("System.Runtime.InteropServices.OutAttribute");
1133 typed_reference_type = CoreLookupType ("System.TypedReference");
1134 arg_iterator_type = CoreLookupType ("System.ArgIterator");
1135 mbr_type = CoreLookupType ("System.MarshalByRefObject");
1136 decimal_constant_attribute_type = CoreLookupType ("System.Runtime.CompilerServices.DecimalConstantAttribute");
1139 // Sigh. Remove this before the release. Wonder what versions of Mono
1140 // people are running.
1142 guid_attr_type = LookupType ("System.Runtime.InteropServices.GuidAttribute");
1144 unverifiable_code_type= CoreLookupType ("System.Security.UnverifiableCodeAttribute");
1146 void_ptr_type = CoreLookupType ("System.Void*");
1148 indexer_name_type = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute");
1150 exception_type = CoreLookupType ("System.Exception");
1151 invalid_operation_exception_type = CoreLookupType ("System.InvalidOperationException");
1152 not_supported_exception_type = CoreLookupType ("System.NotSupportedException");
1157 obsolete_attribute_type = CoreLookupType ("System.ObsoleteAttribute");
1158 conditional_attribute_type = CoreLookupType ("System.Diagnostics.ConditionalAttribute");
1159 cls_compliant_attribute_type = CoreLookupType ("System.CLSCompliantAttribute");
1160 struct_layout_attribute_type = CoreLookupType ("System.Runtime.InteropServices.StructLayoutAttribute");
1161 field_offset_attribute_type = CoreLookupType ("System.Runtime.InteropServices.FieldOffsetAttribute");
1162 security_attr_type = CoreLookupType ("System.Security.Permissions.SecurityAttribute");
1164 InitGenericCoreTypes ();
1167 // When compiling corlib, store the "real" types here.
1169 if (!RootContext.StdLib) {
1170 system_int32_type = typeof (System.Int32);
1171 system_array_type = typeof (System.Array);
1172 system_type_type = typeof (System.Type);
1173 system_assemblybuilder_type = typeof (System.Reflection.Emit.AssemblyBuilder);
1175 Type [] void_arg = { };
1176 system_int_array_get_length = GetMethod (
1177 system_array_type, "get_Length", void_arg);
1178 system_int_array_get_rank = GetMethod (
1179 system_array_type, "get_Rank", void_arg);
1180 system_object_array_clone = GetMethod (
1181 system_array_type, "Clone", void_arg);
1183 Type [] system_int_arg = { system_int32_type };
1184 system_int_array_get_length_int = GetMethod (
1185 system_array_type, "GetLength", system_int_arg);
1186 system_int_array_get_upper_bound_int = GetMethod (
1187 system_array_type, "GetUpperBound", system_int_arg);
1188 system_int_array_get_lower_bound_int = GetMethod (
1189 system_array_type, "GetLowerBound", system_int_arg);
1191 Type [] system_array_int_arg = { system_array_type, system_int32_type };
1192 system_void_array_copyto_array_int = GetMethod (
1193 system_array_type, "CopyTo", system_array_int_arg);
1195 Type [] system_3_type_arg = {
1196 system_type_type, system_type_type, system_type_type };
1197 Type [] system_4_type_arg = {
1198 system_type_type, system_type_type, system_type_type, system_type_type };
1200 MethodInfo set_corlib_type_builders = GetMethod (
1201 system_assemblybuilder_type, "SetCorlibTypeBuilders",
1202 system_4_type_arg, true, false);
1204 if (set_corlib_type_builders != null) {
1205 object[] args = new object [4];
1206 args [0] = object_type;
1207 args [1] = value_type;
1208 args [2] = enum_type;
1209 args [3] = void_type;
1211 set_corlib_type_builders.Invoke (CodeGen.Assembly.Builder, args);
1213 // Compatibility for an older version of the class libs.
1214 set_corlib_type_builders = GetMethod (
1215 system_assemblybuilder_type, "SetCorlibTypeBuilders",
1216 system_3_type_arg, true, true);
1218 if (set_corlib_type_builders == null) {
1219 Report.Error (-26, "Corlib compilation is not supported in Microsoft.NET due to bugs in it");
1223 object[] args = new object [3];
1224 args [0] = object_type;
1225 args [1] = value_type;
1226 args [2] = enum_type;
1228 set_corlib_type_builders.Invoke (CodeGen.Assembly.Builder, args);
1232 system_object_expr.Type = object_type;
1233 system_string_expr.Type = string_type;
1234 system_boolean_expr.Type = bool_type;
1235 system_decimal_expr.Type = decimal_type;
1236 system_single_expr.Type = float_type;
1237 system_double_expr.Type = double_type;
1238 system_sbyte_expr.Type = sbyte_type;
1239 system_byte_expr.Type = byte_type;
1240 system_int16_expr.Type = short_type;
1241 system_uint16_expr.Type = ushort_type;
1242 system_int32_expr.Type = int32_type;
1243 system_uint32_expr.Type = uint32_type;
1244 system_int64_expr.Type = int64_type;
1245 system_uint64_expr.Type = uint64_type;
1246 system_char_expr.Type = char_type;
1247 system_void_expr.Type = void_type;
1248 system_asynccallback_expr.Type = asynccallback_type;
1249 system_iasyncresult_expr.Type = iasyncresult_type;
1250 system_valuetype_expr.Type = value_type;
1253 // These are only used for compare purposes
1255 anonymous_method_type = typeof (AnonymousMethod);
1256 null_type = typeof (NullType);
1260 // The helper methods that are used by the compiler
1262 public static void InitCodeHelpers ()
1265 // Now load the default methods that we use.
1267 Type [] string_string = { string_type, string_type };
1268 string_concat_string_string = GetMethod (
1269 string_type, "Concat", string_string);
1270 Type [] string_string_string = { string_type, string_type, string_type };
1271 string_concat_string_string_string = GetMethod (
1272 string_type, "Concat", string_string_string);
1273 Type [] string_string_string_string = { string_type, string_type, string_type, string_type };
1274 string_concat_string_string_string_string = GetMethod (
1275 string_type, "Concat", string_string_string_string);
1276 Type[] params_string = { TypeManager.LookupType ("System.String[]") };
1277 string_concat_string_dot_dot_dot = GetMethod (
1278 string_type, "Concat", params_string);
1280 Type [] object_object = { object_type, object_type };
1281 string_concat_object_object = GetMethod (
1282 string_type, "Concat", object_object);
1283 Type [] object_object_object = { object_type, object_type, object_type };
1284 string_concat_object_object_object = GetMethod (
1285 string_type, "Concat", object_object_object);
1286 Type[] params_object = { TypeManager.LookupType ("System.Object[]") };
1287 string_concat_object_dot_dot_dot = GetMethod (
1288 string_type, "Concat", params_object);
1290 Type [] string_ = { string_type };
1291 string_isinterneted_string = GetMethod (
1292 string_type, "IsInterned", string_);
1294 Type [] runtime_type_handle = { runtime_handle_type };
1295 system_type_get_type_from_handle = GetMethod (
1296 type_type, "GetTypeFromHandle", runtime_type_handle);
1298 Type [] delegate_delegate = { delegate_type, delegate_type };
1299 delegate_combine_delegate_delegate = GetMethod (
1300 delegate_type, "Combine", delegate_delegate);
1302 delegate_remove_delegate_delegate = GetMethod (
1303 delegate_type, "Remove", delegate_delegate);
1308 Type [] void_arg = { };
1309 object_getcurrent_void = GetMethod (
1310 ienumerator_type, "get_Current", void_arg);
1311 bool_movenext_void = GetMethod (
1312 ienumerator_type, "MoveNext", void_arg);
1313 void_reset_void = GetMethod (
1314 ienumerator_type, "Reset", void_arg);
1315 void_dispose_void = GetMethod (
1316 idisposable_type, "Dispose", void_arg);
1317 int_get_offset_to_string_data = GetMethod (
1318 runtime_helpers_type, "get_OffsetToStringData", void_arg);
1319 int_array_get_length = GetMethod (
1320 array_type, "get_Length", void_arg);
1321 int_array_get_rank = GetMethod (
1322 array_type, "get_Rank", void_arg);
1323 ienumerable_getenumerator_void = GetMethod (
1324 ienumerable_type, "GetEnumerator", void_arg);
1329 Type [] int_arg = { int32_type };
1330 int_array_get_length_int = GetMethod (
1331 array_type, "GetLength", int_arg);
1332 int_array_get_upper_bound_int = GetMethod (
1333 array_type, "GetUpperBound", int_arg);
1334 int_array_get_lower_bound_int = GetMethod (
1335 array_type, "GetLowerBound", int_arg);
1338 // System.Array methods
1340 object_array_clone = GetMethod (
1341 array_type, "Clone", void_arg);
1342 Type [] array_int_arg = { array_type, int32_type };
1343 void_array_copyto_array_int = GetMethod (
1344 array_type, "CopyTo", array_int_arg);
1349 Type [] object_arg = { object_type };
1350 void_monitor_enter_object = GetMethod (
1351 monitor_type, "Enter", object_arg);
1352 void_monitor_exit_object = GetMethod (
1353 monitor_type, "Exit", object_arg);
1355 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
1357 void_initializearray_array_fieldhandle = GetMethod (
1358 runtime_helpers_type, "InitializeArray", array_field_handle_arg);
1363 int_getlength_int = GetMethod (
1364 array_type, "GetLength", int_arg);
1367 // Decimal constructors
1369 Type [] dec_arg = { int32_type, int32_type, int32_type, bool_type, byte_type };
1370 void_decimal_ctor_five_args = GetConstructor (
1371 decimal_type, dec_arg);
1373 void_decimal_ctor_int_arg = GetConstructor (decimal_type, int_arg);
1378 cons_param_array_attribute = GetConstructor (
1379 param_array_type, void_arg);
1381 unverifiable_code_ctor = GetConstructor (
1382 unverifiable_code_type, void_arg);
1384 decimal_constant_attribute_ctor = GetConstructor (decimal_constant_attribute_type, new Type []
1385 { byte_type, byte_type, uint32_type, uint32_type, uint32_type } );
1387 default_member_ctor = GetConstructor (default_member_type, string_);
1390 // InvalidOperationException
1392 invalid_operation_ctor = GetConstructor (
1393 invalid_operation_exception_type, void_arg);
1397 object_ctor = GetConstructor (object_type, void_arg);
1399 InitGenericCodeHelpers ();
1402 const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
1405 /// This is the "old", non-cache based FindMembers() function. We cannot use
1406 /// the cache here because there is no member name argument.
1408 public static MemberList FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1409 MemberFilter filter, object criteria)
1411 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1414 // `builder_to_declspace' contains all dynamic types.
1418 Timer.StartTimer (TimerType.FindMembers);
1419 list = decl.FindMembers (mt, bf, filter, criteria);
1420 Timer.StopTimer (TimerType.FindMembers);
1425 // We have to take care of arrays specially, because GetType on
1426 // a TypeBuilder array will return a Type, not a TypeBuilder,
1427 // and we can not call FindMembers on this type.
1429 if (t.IsSubclassOf (TypeManager.array_type))
1430 return new MemberList (TypeManager.array_type.FindMembers (mt, bf, filter, criteria));
1432 if (t is GenericTypeParameterBuilder) {
1433 TypeParameter tparam = (TypeParameter) builder_to_type_param [t];
1435 Timer.StartTimer (TimerType.FindMembers);
1436 MemberList list = tparam.FindMembers (
1437 mt, bf | BindingFlags.DeclaredOnly, filter, criteria);
1438 Timer.StopTimer (TimerType.FindMembers);
1443 // Since FindMembers will not lookup both static and instance
1444 // members, we emulate this behaviour here.
1446 if ((bf & instance_and_static) == instance_and_static){
1447 MemberInfo [] i_members = t.FindMembers (
1448 mt, bf & ~BindingFlags.Static, filter, criteria);
1450 int i_len = i_members.Length;
1452 MemberInfo one = i_members [0];
1455 // If any of these are present, we are done!
1457 if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
1458 return new MemberList (i_members);
1461 MemberInfo [] s_members = t.FindMembers (
1462 mt, bf & ~BindingFlags.Instance, filter, criteria);
1464 int s_len = s_members.Length;
1465 if (i_len > 0 || s_len > 0)
1466 return new MemberList (i_members, s_members);
1469 return new MemberList (i_members);
1471 return new MemberList (s_members);
1475 return new MemberList (t.FindMembers (mt, bf, filter, criteria));
1480 /// This method is only called from within MemberLookup. It tries to use the member
1481 /// cache if possible and falls back to the normal FindMembers if not. The `used_cache'
1482 /// flag tells the caller whether we used the cache or not. If we used the cache, then
1483 /// our return value will already contain all inherited members and the caller don't need
1484 /// to check base classes and interfaces anymore.
1486 private static MemberInfo [] MemberLookup_FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1487 string name, out bool used_cache)
1492 // We have to take care of arrays specially, because GetType on
1493 // a TypeBuilder array will return a Type, not a TypeBuilder,
1494 // and we can not call FindMembers on this type.
1496 if (t == TypeManager.array_type || t.IsSubclassOf (TypeManager.array_type)) {
1498 return TypeHandle.ArrayType.MemberCache.FindMembers (
1499 mt, bf, name, FilterWithClosure_delegate, null);
1503 // If this is a dynamic type, it's always in the `builder_to_declspace' hash table
1504 // and we can ask the DeclSpace for the MemberCache.
1506 if (t is TypeBuilder) {
1507 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1508 cache = decl.MemberCache;
1511 // If this DeclSpace has a MemberCache, use it.
1514 if (cache != null) {
1516 return cache.FindMembers (
1517 mt, bf, name, FilterWithClosure_delegate, null);
1520 // If there is no MemberCache, we need to use the "normal" FindMembers.
1521 // Note, this is a VERY uncommon route!
1524 Timer.StartTimer (TimerType.FindMembers);
1525 list = decl.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1526 FilterWithClosure_delegate, name);
1527 Timer.StopTimer (TimerType.FindMembers);
1529 return (MemberInfo []) list;
1532 if (t is GenericTypeParameterBuilder) {
1533 TypeParameter tparam = (TypeParameter) builder_to_type_param [t];
1536 Timer.StartTimer (TimerType.FindMembers);
1537 list = tparam.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1538 FilterWithClosure_delegate, name);
1539 Timer.StopTimer (TimerType.FindMembers);
1541 return (MemberInfo []) list;
1545 // This call will always succeed. There is exactly one TypeHandle instance per
1546 // type, TypeHandle.GetMemberCache() will, if necessary, create a new one, and return
1547 // the corresponding MemberCache.
1549 cache = TypeHandle.GetMemberCache (t);
1552 return cache.FindMembers (mt, bf, name, FilterWithClosure_delegate, null);
1555 public static bool IsBuiltinType (Type t)
1557 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
1558 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1559 t == char_type || t == short_type || t == decimal_type || t == bool_type ||
1560 t == sbyte_type || t == byte_type || t == ushort_type || t == void_type)
1566 public static bool IsBuiltinType (TypeContainer tc)
1568 return IsBuiltinType (tc.TypeBuilder);
1572 // This is like IsBuiltinType, but lacks decimal_type, we should also clean up
1573 // the pieces in the code where we use IsBuiltinType and special case decimal_type.
1575 public static bool IsCLRType (Type t)
1577 if (t == object_type || t == int32_type || t == uint32_type ||
1578 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1579 t == char_type || t == short_type || t == bool_type ||
1580 t == sbyte_type || t == byte_type || t == ushort_type)
1586 public static bool IsDelegateType (Type t)
1588 if (t.IsGenericInstance)
1589 t = t.GetGenericTypeDefinition ();
1591 if (t.IsSubclassOf (TypeManager.delegate_type))
1597 public static bool IsEnumType (Type t)
1599 if (t.IsSubclassOf (TypeManager.enum_type))
1604 public static bool IsBuiltinOrEnum (Type t)
1606 if (IsBuiltinType (t))
1615 public static bool IsNullType (Type t)
1617 return t == null_type;
1621 // Whether a type is unmanaged. This is used by the unsafe code (25.2)
1623 public static bool IsUnmanagedType (Type t)
1625 if (IsBuiltinType (t) && t != TypeManager.string_type)
1634 if (IsValueType (t)){
1635 if (t is TypeBuilder){
1636 TypeContainer tc = LookupTypeContainer (t);
1638 if (tc.Fields != null){
1639 foreach (Field f in tc.Fields){
1640 if (f.FieldBuilder.IsStatic)
1642 if (!IsUnmanagedType (f.FieldBuilder.FieldType))
1648 FieldInfo [] fields = t.GetFields ();
1650 foreach (FieldInfo f in fields){
1653 if (!IsUnmanagedType (f.FieldType))
1663 public static bool IsValueType (Type t)
1665 return t.IsGenericParameter || t.IsValueType;
1668 public static bool IsInterfaceType (Type t)
1670 TypeContainer tc = (TypeContainer) builder_to_declspace [t];
1674 return tc.Kind == Kind.Interface;
1677 public static bool IsSubclassOf (Type type, Type base_type)
1679 TypeParameter tparam = LookupTypeParameter (type);
1680 TypeParameter pparam = LookupTypeParameter (base_type);
1682 if ((tparam != null) && (pparam != null)) {
1683 if (tparam == pparam)
1686 return tparam.IsSubclassOf (base_type);
1690 if (type.Equals (base_type))
1693 type = type.BaseType;
1694 } while (type != null);
1699 public static bool IsPrivateAccessible (Type type, Type parent)
1701 if (type.Equals (parent))
1704 if ((type is TypeBuilder) && type.IsGenericTypeDefinition && parent.IsGenericInstance) {
1706 // `a' is a generic type definition's TypeBuilder and `b' is a
1707 // generic instance of the same type.
1713 // void Test (Stack<T> stack) { }
1716 // The first argument of `Test' will be the generic instance
1717 // "Stack<!0>" - which is the same type than the "Stack" TypeBuilder.
1720 // We hit this via Closure.Filter() for gen-82.cs.
1722 if (type != parent.GetGenericTypeDefinition ())
1728 if (type.IsGenericInstance && parent.IsGenericInstance) {
1729 if (type.GetGenericTypeDefinition () != parent.GetGenericTypeDefinition ())
1738 public static bool IsFamilyAccessible (Type type, Type parent)
1740 TypeParameter tparam = LookupTypeParameter (type);
1741 TypeParameter pparam = LookupTypeParameter (parent);
1743 if ((tparam != null) && (pparam != null)) {
1744 if (tparam == pparam)
1747 return tparam.IsSubclassOf (parent);
1751 if (IsEqualGenericInstance (type, parent))
1754 type = type.BaseType;
1755 } while (type != null);
1761 // Checks whether `type' is a subclass or nested child of `base_type'.
1763 public static bool IsNestedFamilyAccessible (Type type, Type base_type)
1766 if (IsFamilyAccessible (type, base_type))
1769 // Handle nested types.
1770 type = type.DeclaringType;
1771 } while (type != null);
1777 // Checks whether `type' is a nested child of `parent'.
1779 public static bool IsNestedChildOf (Type type, Type parent)
1781 if (IsEqual (type, parent))
1784 type = type.DeclaringType;
1785 while (type != null) {
1786 if (IsEqual (type, parent))
1789 type = type.DeclaringType;
1796 // Do the right thing when returning the element type of an
1797 // array type based on whether we are compiling corlib or not
1799 public static Type GetElementType (Type t)
1801 if (RootContext.StdLib)
1802 return t.GetElementType ();
1804 return TypeToCoreType (t.GetElementType ());
1808 /// Returns the User Defined Types
1810 public static ArrayList UserTypes {
1816 public static Hashtable TypeContainers {
1818 return typecontainers;
1822 static Hashtable builder_to_constant;
1824 public static void RegisterConstant (FieldBuilder fb, Const c)
1826 if (builder_to_constant == null)
1827 builder_to_constant = new PtrHashtable ();
1829 if (builder_to_constant.Contains (fb))
1832 builder_to_constant.Add (fb, c);
1835 public static Const LookupConstant (FieldBuilder fb)
1837 if (builder_to_constant == null)
1840 return (Const) builder_to_constant [fb];
1844 /// Gigantic work around for missing features in System.Reflection.Emit follows.
1848 /// Since System.Reflection.Emit can not return MethodBase.GetParameters
1849 /// for anything which is dynamic, and we need this in a number of places,
1850 /// we register this information here, and use it afterwards.
1852 static public void RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
1857 method_arguments.Add (mb, args);
1858 method_params.Add (mb, ip);
1861 static public ParameterData GetParameterData (MethodBase mb)
1863 object pd = method_params [mb];
1865 if (mb is MethodBuilder || mb is ConstructorBuilder)
1866 throw new InternalErrorException ("Argument for Method not registered" + mb);
1868 method_params [mb] = pd = new ReflectionParameters (mb);
1871 return (ParameterData) pd;
1875 /// Returns the argument types for a method based on its methodbase
1877 /// For dynamic methods, we use the compiler provided types, for
1878 /// methods from existing assemblies we load them from GetParameters,
1879 /// and insert them into the cache
1881 static public Type [] GetArgumentTypes (MethodBase mb)
1883 object t = method_arguments [mb];
1887 ParameterInfo [] pi = mb.GetParameters ();
1894 types = new Type [c];
1895 for (int i = 0; i < c; i++)
1896 types [i] = pi [i].ParameterType;
1898 method_arguments.Add (mb, types);
1903 /// Returns the argument types for an indexer based on its PropertyInfo
1905 /// For dynamic indexers, we use the compiler provided types, for
1906 /// indexers from existing assemblies we load them from GetParameters,
1907 /// and insert them into the cache
1909 static public Type [] GetArgumentTypes (PropertyInfo indexer)
1911 if (indexer_arguments.Contains (indexer))
1912 return (Type []) indexer_arguments [indexer];
1913 else if (indexer is PropertyBuilder)
1914 // If we're a PropertyBuilder and not in the
1915 // `indexer_arguments' hash, then we're a property and
1919 ParameterInfo [] pi = indexer.GetIndexParameters ();
1920 // Property, not an indexer.
1924 Type [] types = new Type [c];
1926 for (int i = 0; i < c; i++)
1927 types [i] = pi [i].ParameterType;
1929 indexer_arguments.Add (indexer, types);
1935 // This is a workaround the fact that GetValue is not
1936 // supported for dynamic types
1938 static Hashtable fields = new Hashtable ();
1939 static public bool RegisterFieldValue (FieldBuilder fb, object value)
1941 if (fields.Contains (fb))
1944 fields.Add (fb, value);
1949 static public object GetValue (FieldBuilder fb)
1954 static Hashtable fieldbuilders_to_fields = new Hashtable ();
1955 static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f)
1957 if (fieldbuilders_to_fields.Contains (fb))
1960 fieldbuilders_to_fields.Add (fb, f);
1965 // The return value can be null; This will be the case for
1966 // auxiliary FieldBuilders created by the compiler that have no
1967 // real field being declared on the source code
1969 static public FieldBase GetField (FieldInfo fb)
1971 return (FieldBase) fieldbuilders_to_fields [fb];
1974 static Hashtable events;
1976 static public void RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
1979 events = new Hashtable ();
1981 if (!events.Contains (eb)) {
1982 events.Add (eb, new Pair (add, remove));
1986 static public MethodInfo GetAddMethod (EventInfo ei)
1988 if (ei is MyEventBuilder) {
1989 Pair pair = (Pair) events [ei];
1991 return (MethodInfo) pair.First;
1993 return ei.GetAddMethod (true);
1996 static public MethodInfo GetRemoveMethod (EventInfo ei)
1998 if (ei is MyEventBuilder) {
1999 Pair pair = (Pair) events [ei];
2001 return (MethodInfo) pair.Second;
2003 return ei.GetRemoveMethod (true);
2006 static Hashtable priv_fields_events;
2008 static public bool RegisterPrivateFieldOfEvent (EventInfo einfo, FieldBuilder builder)
2010 if (priv_fields_events == null)
2011 priv_fields_events = new Hashtable ();
2013 if (priv_fields_events.Contains (einfo))
2016 priv_fields_events.Add (einfo, builder);
2021 static public MemberInfo GetPrivateFieldOfEvent (EventInfo ei)
2023 if (priv_fields_events == null)
2026 return (MemberInfo) priv_fields_events [ei];
2029 static Hashtable properties;
2031 static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
2033 if (properties == null)
2034 properties = new Hashtable ();
2036 if (properties.Contains (pb))
2039 properties.Add (pb, new Pair (get, set));
2044 static public bool RegisterIndexer (PropertyBuilder pb, MethodBase get,
2045 MethodBase set, Type[] args)
2047 if (!RegisterProperty (pb, get,set))
2050 indexer_arguments.Add (pb, args);
2055 public static bool CheckStructCycles (TypeContainer tc, Hashtable seen)
2057 Hashtable hash = new Hashtable ();
2058 return CheckStructCycles (tc, seen, hash);
2061 public static bool CheckStructCycles (TypeContainer tc, Hashtable seen,
2064 if ((tc.Kind != Kind.Struct) || IsBuiltinType (tc))
2068 // `seen' contains all types we've already visited.
2070 if (seen.Contains (tc))
2072 seen.Add (tc, null);
2074 if (tc.Fields == null)
2077 foreach (Field field in tc.Fields) {
2078 if (field.FieldBuilder == null || field.FieldBuilder.IsStatic)
2081 Type ftype = field.FieldBuilder.FieldType;
2082 TypeContainer ftc = LookupTypeContainer (ftype);
2086 if (hash.Contains (ftc)) {
2087 Report.Error (523, tc.Location,
2088 "Struct member `{0}.{1}' of type `{2}' " +
2089 "causes a cycle in the struct layout",
2090 tc.Name, field.Name, ftc.Name);
2095 // `hash' contains all types in the current path.
2097 hash.Add (tc, null);
2099 bool ok = CheckStructCycles (ftc, seen, hash);
2106 if (!seen.Contains (ftc))
2107 seen.Add (ftc, null);
2114 /// Given an array of interface types, expand and eliminate repeated ocurrences
2115 /// of an interface.
2119 /// This expands in context like: IA; IB : IA; IC : IA, IB; the interface "IC" to
2122 public static Type[] ExpandInterfaces (EmitContext ec, TypeExpr [] base_interfaces)
2124 ArrayList new_ifaces = new ArrayList ();
2126 foreach (TypeExpr iface in base_interfaces){
2127 TypeExpr texpr = iface.ResolveAsTypeTerminal (ec);
2131 if (!new_ifaces.Contains (texpr.Type))
2132 new_ifaces.Add (texpr.Type);
2134 Type [] implementing = texpr.Type.GetInterfaces ();
2136 foreach (Type imp in implementing){
2137 if (!new_ifaces.Contains (imp))
2138 new_ifaces.Add (imp);
2141 Type [] ret = new Type [new_ifaces.Count];
2142 new_ifaces.CopyTo (ret, 0);
2146 static PtrHashtable iface_cache = new PtrHashtable ();
2149 /// This function returns the interfaces in the type `t'. Works with
2150 /// both types and TypeBuilders.
2152 public static Type [] GetInterfaces (Type t)
2155 Type [] cached = iface_cache [t] as Type [];
2160 // The reason for catching the Array case is that Reflection.Emit
2161 // will not return a TypeBuilder for Array types of TypeBuilder types,
2162 // but will still throw an exception if we try to call GetInterfaces
2165 // Since the array interfaces are always constant, we return those for
2170 t = TypeManager.array_type;
2172 if (t is TypeBuilder){
2173 Type [] base_ifaces;
2175 if (t.BaseType == null)
2176 base_ifaces = NoTypes;
2178 base_ifaces = GetInterfaces (t.BaseType);
2179 Type[] type_ifaces = (Type []) builder_to_ifaces [t];
2180 if (type_ifaces == null)
2181 type_ifaces = NoTypes;
2183 int base_count = base_ifaces.Length;
2184 Type [] result = new Type [base_count + type_ifaces.Length];
2185 base_ifaces.CopyTo (result, 0);
2186 type_ifaces.CopyTo (result, base_count);
2188 iface_cache [t] = result;
2190 } else if (t is GenericTypeParameterBuilder){
2191 Type[] type_ifaces = (Type []) builder_to_ifaces [t];
2192 if (type_ifaces == null)
2193 type_ifaces = NoTypes;
2195 iface_cache [t] = type_ifaces;
2198 Type[] ifaces = t.GetInterfaces ();
2199 iface_cache [t] = ifaces;
2205 // gets the interfaces that are declared explicitly on t
2207 public static Type [] GetExplicitInterfaces (TypeBuilder t)
2209 return (Type []) builder_to_ifaces [t];
2213 /// The following is used to check if a given type implements an interface.
2214 /// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
2216 public static bool ImplementsInterface (Type t, Type iface)
2221 // FIXME OPTIMIZATION:
2222 // as soon as we hit a non-TypeBuiler in the interface
2223 // chain, we could return, as the `Type.GetInterfaces'
2224 // will return all the interfaces implement by the type
2228 interfaces = GetInterfaces (t);
2230 if (interfaces != null){
2231 foreach (Type i in interfaces){
2238 } while (t != null);
2243 static NumberFormatInfo nf_provider = CultureInfo.CurrentCulture.NumberFormat;
2245 // This is a custom version of Convert.ChangeType() which works
2246 // with the TypeBuilder defined types when compiling corlib.
2247 public static object ChangeType (object value, Type conversionType, out bool error)
2249 IConvertible convert_value = value as IConvertible;
2251 if (convert_value == null){
2257 // We must use Type.Equals() here since `conversionType' is
2258 // the TypeBuilder created version of a system type and not
2259 // the system type itself. You cannot use Type.GetTypeCode()
2260 // on such a type - it'd always return TypeCode.Object.
2264 if (conversionType.Equals (typeof (Boolean)))
2265 return (object)(convert_value.ToBoolean (nf_provider));
2266 else if (conversionType.Equals (typeof (Byte)))
2267 return (object)(convert_value.ToByte (nf_provider));
2268 else if (conversionType.Equals (typeof (Char)))
2269 return (object)(convert_value.ToChar (nf_provider));
2270 else if (conversionType.Equals (typeof (DateTime)))
2271 return (object)(convert_value.ToDateTime (nf_provider));
2272 else if (conversionType.Equals (TypeManager.decimal_type)) // typeof (Decimal)))
2273 return (object)(convert_value.ToDecimal (nf_provider));
2274 else if (conversionType.Equals (typeof (Double)))
2275 return (object)(convert_value.ToDouble (nf_provider));
2276 else if (conversionType.Equals (typeof (Int16)))
2277 return (object)(convert_value.ToInt16 (nf_provider));
2278 else if (conversionType.Equals (typeof (Int32)))
2279 return (object)(convert_value.ToInt32 (nf_provider));
2280 else if (conversionType.Equals (typeof (Int64)))
2281 return (object)(convert_value.ToInt64 (nf_provider));
2282 else if (conversionType.Equals (typeof (SByte)))
2283 return (object)(convert_value.ToSByte (nf_provider));
2284 else if (conversionType.Equals (typeof (Single)))
2285 return (object)(convert_value.ToSingle (nf_provider));
2286 else if (conversionType.Equals (typeof (String)))
2287 return (object)(convert_value.ToString (nf_provider));
2288 else if (conversionType.Equals (typeof (UInt16)))
2289 return (object)(convert_value.ToUInt16 (nf_provider));
2290 else if (conversionType.Equals (typeof (UInt32)))
2291 return (object)(convert_value.ToUInt32 (nf_provider));
2292 else if (conversionType.Equals (typeof (UInt64)))
2293 return (object)(convert_value.ToUInt64 (nf_provider));
2294 else if (conversionType.Equals (typeof (Object)))
2295 return (object)(value);
2305 // This is needed, because enumerations from assemblies
2306 // do not report their underlyingtype, but they report
2309 public static Type EnumToUnderlying (Type t)
2311 if (t == TypeManager.enum_type)
2314 t = t.UnderlyingSystemType;
2315 if (!TypeManager.IsEnumType (t))
2318 if (t is TypeBuilder) {
2319 // slow path needed to compile corlib
2320 if (t == TypeManager.bool_type ||
2321 t == TypeManager.byte_type ||
2322 t == TypeManager.sbyte_type ||
2323 t == TypeManager.char_type ||
2324 t == TypeManager.short_type ||
2325 t == TypeManager.ushort_type ||
2326 t == TypeManager.int32_type ||
2327 t == TypeManager.uint32_type ||
2328 t == TypeManager.int64_type ||
2329 t == TypeManager.uint64_type)
2331 throw new Exception ("Unhandled typecode in enum " + " from " + t.AssemblyQualifiedName);
2333 TypeCode tc = Type.GetTypeCode (t);
2336 case TypeCode.Boolean:
2337 return TypeManager.bool_type;
2339 return TypeManager.byte_type;
2340 case TypeCode.SByte:
2341 return TypeManager.sbyte_type;
2343 return TypeManager.char_type;
2344 case TypeCode.Int16:
2345 return TypeManager.short_type;
2346 case TypeCode.UInt16:
2347 return TypeManager.ushort_type;
2348 case TypeCode.Int32:
2349 return TypeManager.int32_type;
2350 case TypeCode.UInt32:
2351 return TypeManager.uint32_type;
2352 case TypeCode.Int64:
2353 return TypeManager.int64_type;
2354 case TypeCode.UInt64:
2355 return TypeManager.uint64_type;
2357 throw new Exception ("Unhandled typecode in enum " + tc + " from " + t.AssemblyQualifiedName);
2361 // When compiling corlib and called with one of the core types, return
2362 // the corresponding typebuilder for that type.
2364 public static Type TypeToCoreType (Type t)
2366 if (RootContext.StdLib || (t is TypeBuilder))
2369 TypeCode tc = Type.GetTypeCode (t);
2372 case TypeCode.Boolean:
2373 return TypeManager.bool_type;
2375 return TypeManager.byte_type;
2376 case TypeCode.SByte:
2377 return TypeManager.sbyte_type;
2379 return TypeManager.char_type;
2380 case TypeCode.Int16:
2381 return TypeManager.short_type;
2382 case TypeCode.UInt16:
2383 return TypeManager.ushort_type;
2384 case TypeCode.Int32:
2385 return TypeManager.int32_type;
2386 case TypeCode.UInt32:
2387 return TypeManager.uint32_type;
2388 case TypeCode.Int64:
2389 return TypeManager.int64_type;
2390 case TypeCode.UInt64:
2391 return TypeManager.uint64_type;
2392 case TypeCode.Single:
2393 return TypeManager.float_type;
2394 case TypeCode.Double:
2395 return TypeManager.double_type;
2396 case TypeCode.String:
2397 return TypeManager.string_type;
2398 case TypeCode.Decimal:
2399 return TypeManager.decimal_type;
2401 if (t == typeof (void))
2402 return TypeManager.void_type;
2403 if (t == typeof (object))
2404 return TypeManager.object_type;
2405 if (t == typeof (System.Type))
2406 return TypeManager.type_type;
2407 if (t == typeof (System.IntPtr))
2408 return TypeManager.intptr_type;
2414 /// Utility function that can be used to probe whether a type
2415 /// is managed or not.
2417 public static bool VerifyUnManaged (Type t, Location loc)
2419 if (t.IsValueType || t.IsPointer){
2421 // FIXME: this is more complex, we actually need to
2422 // make sure that the type does not contain any
2428 if (!RootContext.StdLib && (t == TypeManager.decimal_type))
2429 // We need this explicit check here to make it work when
2430 // compiling corlib.
2435 "Cannot take the address or size of a variable of a managed type ('" +
2436 CSharpName (t) + "')");
2441 /// Returns the name of the indexer in a given type.
2444 /// The default is not always `Item'. The user can change this behaviour by
2445 /// using the IndexerNameAttribute in the container.
2447 /// For example, the String class indexer is named `Chars' not `Item'
2449 public static string IndexerPropertyName (Type t)
2451 if (t.IsGenericInstance)
2452 t = t.GetGenericTypeDefinition ();
2454 if (t is TypeBuilder) {
2455 TypeContainer tc = t.IsInterface ? LookupInterface (t) : LookupTypeContainer (t);
2456 return tc == null ? TypeContainer.DefaultIndexerName : tc.IndexerName;
2459 System.Attribute attr = System.Attribute.GetCustomAttribute (
2460 t, TypeManager.default_member_type);
2462 DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
2463 return dma.MemberName;
2466 return TypeContainer.DefaultIndexerName;
2469 static MethodInfo declare_local_method = null;
2471 public static LocalBuilder DeclareLocalPinned (ILGenerator ig, Type t)
2473 if (declare_local_method == null){
2474 declare_local_method = typeof (ILGenerator).GetMethod (
2476 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
2478 new Type [] { typeof (Type), typeof (bool)},
2480 if (declare_local_method == null){
2481 Report.Warning (-24, new Location (-1),
2482 "This version of the runtime does not support making pinned local variables. " +
2483 "This code may cause errors on a runtime with a moving GC");
2484 return ig.DeclareLocal (t);
2487 return (LocalBuilder) declare_local_method.Invoke (ig, new object [] { t, true });
2491 // Returns whether the array of memberinfos contains the given method
2493 public static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method)
2495 Type [] new_args = TypeManager.GetArgumentTypes (new_method);
2497 foreach (MethodBase method in array) {
2498 if (method.Name != new_method.Name)
2501 if (method is MethodInfo && new_method is MethodInfo)
2502 if (((MethodInfo) method).ReturnType != ((MethodInfo) new_method).ReturnType)
2506 Type [] old_args = TypeManager.GetArgumentTypes (method);
2507 int old_count = old_args.Length;
2510 if (new_args.Length != old_count)
2513 for (i = 0; i < old_count; i++){
2514 if (old_args [i] != new_args [i])
2527 // We copy methods from `new_members' into `target_list' if the signature
2528 // for the method from in the new list does not exist in the target_list
2530 // The name is assumed to be the same.
2532 public static ArrayList CopyNewMethods (ArrayList target_list, IList new_members)
2534 if (target_list == null){
2535 target_list = new ArrayList ();
2537 foreach (MemberInfo mi in new_members){
2538 if (mi is MethodBase)
2539 target_list.Add (mi);
2544 MemberInfo [] target_array = new MemberInfo [target_list.Count];
2545 target_list.CopyTo (target_array, 0);
2547 foreach (MemberInfo mi in new_members){
2548 MethodBase new_method = (MethodBase) mi;
2550 if (!ArrayContainsMethod (target_array, new_method))
2551 target_list.Add (new_method);
2556 #region MemberLookup implementation
2559 // Whether we allow private members in the result (since FindMembers
2560 // uses NonPublic for both protected and private), we need to distinguish.
2563 static internal bool FilterNone (MemberInfo m, object filter_criteria)
2568 internal class Closure {
2569 internal bool private_ok;
2571 // Who is invoking us and which type is being queried currently.
2572 internal Type invocation_type;
2573 internal Type qualifier_type;
2575 // The assembly that defines the type is that is calling us
2576 internal Assembly invocation_assembly;
2577 internal IList almost_match;
2579 private bool CheckValidFamilyAccess (bool is_static, MemberInfo m)
2581 if (invocation_type == null)
2584 Debug.Assert (IsNestedFamilyAccessible (invocation_type, m.DeclaringType));
2589 // A nested class has access to all the protected members visible
2591 if (qualifier_type != null
2592 && TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2595 if (invocation_type == m.DeclaringType
2596 || invocation_type.IsSubclassOf (m.DeclaringType)) {
2597 // Although a derived class can access protected members of
2598 // its base class it cannot do so through an instance of the
2599 // base class (CS1540).
2600 // => Ancestry should be: declaring_type ->* invocation_type
2601 // ->* qualified_type
2602 if (qualifier_type == null
2603 || qualifier_type == invocation_type
2604 || qualifier_type.IsSubclassOf (invocation_type))
2608 if (almost_match != null)
2609 almost_match.Add (m);
2613 bool Filter (MethodBase mb, object filter_criteria)
2615 MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
2617 if (ma == MethodAttributes.Private)
2618 return private_ok ||
2619 IsPrivateAccessible (invocation_type, mb.DeclaringType) ||
2620 IsNestedChildOf (invocation_type, mb.DeclaringType);
2623 // FamAndAssem requires that we not only derivate, but we are on the
2626 if (ma == MethodAttributes.FamANDAssem){
2627 if (invocation_assembly != mb.DeclaringType.Assembly)
2631 // Assembly and FamORAssem succeed if we're in the same assembly.
2632 if ((ma == MethodAttributes.Assembly) || (ma == MethodAttributes.FamORAssem)){
2633 if (invocation_assembly == mb.DeclaringType.Assembly)
2637 // We already know that we aren't in the same assembly.
2638 if (ma == MethodAttributes.Assembly)
2641 // Family and FamANDAssem require that we derive.
2642 if ((ma == MethodAttributes.Family) || (ma == MethodAttributes.FamANDAssem)){
2643 if (invocation_type == null)
2646 if (!IsNestedFamilyAccessible (invocation_type, mb.DeclaringType))
2649 // Although a derived class can access protected members of its base class
2650 // it cannot do so through an instance of the base class (CS1540).
2651 if (!mb.IsStatic && (qualifier_type != null) &&
2652 !IsEqualGenericInstance (invocation_type, qualifier_type) &&
2653 TypeManager.IsFamilyAccessible (invocation_type, qualifier_type) &&
2654 !TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2664 bool Filter (FieldInfo fi, object filter_criteria)
2666 FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
2668 if (fa == FieldAttributes.Private)
2669 return private_ok ||
2670 IsPrivateAccessible (invocation_type, fi.DeclaringType) ||
2671 IsNestedChildOf (invocation_type, fi.DeclaringType);
2674 // FamAndAssem requires that we not only derivate, but we are on the
2677 if (fa == FieldAttributes.FamANDAssem){
2678 if (invocation_assembly != fi.DeclaringType.Assembly)
2682 // Assembly and FamORAssem succeed if we're in the same assembly.
2683 if ((fa == FieldAttributes.Assembly) || (fa == FieldAttributes.FamORAssem)){
2684 if (invocation_assembly == fi.DeclaringType.Assembly)
2688 // We already know that we aren't in the same assembly.
2689 if (fa == FieldAttributes.Assembly)
2692 // Family and FamANDAssem require that we derive.
2693 if ((fa == FieldAttributes.Family) || (fa == FieldAttributes.FamANDAssem)){
2694 if (invocation_type == null)
2697 if (!IsNestedFamilyAccessible (invocation_type, fi.DeclaringType))
2700 // Although a derived class can access protected members of its base class
2701 // it cannot do so through an instance of the base class (CS1540).
2702 if (!fi.IsStatic && (qualifier_type != null) &&
2703 !IsEqualGenericInstance (invocation_type, qualifier_type) &&
2704 TypeManager.IsFamilyAccessible (invocation_type, qualifier_type) &&
2705 !TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2716 // This filter filters by name + whether it is ok to include private
2717 // members in the search
2719 internal bool Filter (MemberInfo m, object filter_criteria)
2722 // Hack: we know that the filter criteria will always be in the
2723 // `closure' // fields.
2726 if ((filter_criteria != null) && (m.Name != (string) filter_criteria))
2729 if (((qualifier_type == null) || (qualifier_type == invocation_type)) &&
2730 (invocation_type != null) &&
2731 IsPrivateAccessible (m.DeclaringType, invocation_type))
2735 // Ugly: we need to find out the type of `m', and depending
2736 // on this, tell whether we accept or not
2738 if (m is MethodBase)
2739 return Filter ((MethodBase) m, filter_criteria);
2742 return Filter ((FieldInfo) m, filter_criteria);
2745 // EventInfos and PropertyInfos, return true because they lack
2746 // permission information, so we need to check later on the methods.
2752 static Closure closure = new Closure ();
2753 static MemberFilter FilterWithClosure_delegate = new MemberFilter (closure.Filter);
2756 // Looks up a member called `name' in the `queried_type'. This lookup
2757 // is done by code that is contained in the definition for `invocation_type'
2758 // through a qualifier of type `qualifier_type' (or null if there is no qualifier).
2760 // `invocation_type' is used to check whether we're allowed to access the requested
2761 // member wrt its protection level.
2763 // When called from MemberAccess, `qualifier_type' is the type which is used to access
2764 // the requested member (`class B { A a = new A (); a.foo = 5; }'; here invocation_type
2765 // is B and qualifier_type is A). This is used to do the CS1540 check.
2767 // When resolving a SimpleName, `qualifier_type' is null.
2769 // The `qualifier_type' is used for the CS1540 check; it's normally either null or
2770 // the same than `queried_type' - except when we're being called from BaseAccess;
2771 // in this case, `invocation_type' is the current type and `queried_type' the base
2772 // type, so this'd normally trigger a CS1540.
2774 // The binding flags are `bf' and the kind of members being looked up are `mt'
2776 // The return value always includes private members which code in `invocation_type'
2777 // is allowed to access (using the specified `qualifier_type' if given); only use
2778 // BindingFlags.NonPublic to bypass the permission check.
2780 // The 'almost_match' argument is used for reporting error CS1540.
2782 // Returns an array of a single element for everything but Methods/Constructors
2783 // that might return multiple matches.
2785 public static MemberInfo [] MemberLookup (Type invocation_type, Type qualifier_type,
2786 Type queried_type, MemberTypes mt,
2787 BindingFlags original_bf, string name, IList almost_match)
2789 Timer.StartTimer (TimerType.MemberLookup);
2791 MemberInfo[] retval = RealMemberLookup (invocation_type, qualifier_type,
2792 queried_type, mt, original_bf, name, almost_match);
2794 Timer.StopTimer (TimerType.MemberLookup);
2799 static MemberInfo [] RealMemberLookup (Type invocation_type, Type qualifier_type,
2800 Type queried_type, MemberTypes mt,
2801 BindingFlags original_bf, string name, IList almost_match)
2803 BindingFlags bf = original_bf;
2805 ArrayList method_list = null;
2806 Type current_type = queried_type;
2807 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
2808 bool skip_iface_check = true, used_cache = false;
2809 bool always_ok_flag = false;
2811 closure.invocation_type = invocation_type;
2812 closure.invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
2813 closure.qualifier_type = qualifier_type;
2814 closure.almost_match = almost_match;
2817 // If we are a nested class, we always have access to our container
2820 if (invocation_type != null){
2821 string invocation_name = invocation_type.FullName;
2822 if ((invocation_name != null) && (invocation_name.IndexOf ('+') != -1)){
2823 string container = queried_type.FullName + "+";
2824 int container_length = container.Length;
2826 if (invocation_name.Length > container_length){
2827 string shared = invocation_name.Substring (0, container_length);
2829 if (shared == container)
2830 always_ok_flag = true;
2835 // This is from the first time we find a method
2836 // in most cases, we do not actually find a method in the base class
2837 // so we can just ignore it, and save the arraylist allocation
2838 MemberInfo [] first_members_list = null;
2839 bool use_first_members_list = false;
2845 // `NonPublic' is lame, because it includes both protected and
2846 // private methods, so we need to control this behavior by
2847 // explicitly tracking if a private method is ok or not.
2849 // The possible cases are:
2850 // public, private and protected (internal does not come into the
2853 if ((invocation_type != null) &&
2854 ((invocation_type == current_type) ||
2855 IsNestedChildOf (invocation_type, current_type)) ||
2857 bf = original_bf | BindingFlags.NonPublic;
2861 closure.private_ok = (original_bf & BindingFlags.NonPublic) != 0;
2863 Timer.StopTimer (TimerType.MemberLookup);
2865 list = MemberLookup_FindMembers (
2866 current_type, mt, bf, name, out used_cache);
2868 Timer.StartTimer (TimerType.MemberLookup);
2871 // When queried for an interface type, the cache will automatically check all
2872 // inherited members, so we don't need to do this here. However, this only
2873 // works if we already used the cache in the first iteration of this loop.
2875 // If we used the cache in any further iteration, we can still terminate the
2876 // loop since the cache always looks in all base classes.
2882 skip_iface_check = false;
2884 if (current_type == TypeManager.object_type)
2887 current_type = current_type.BaseType;
2890 // This happens with interfaces, they have a null
2891 // basetype. Look members up in the Object class.
2893 if (current_type == null) {
2894 current_type = TypeManager.object_type;
2899 if (list.Length == 0)
2903 // Events and types are returned by both `static' and `instance'
2904 // searches, which means that our above FindMembers will
2905 // return two copies of the same.
2907 if (list.Length == 1 && !(list [0] is MethodBase)){
2912 // Multiple properties: we query those just to find out the indexer
2915 if (list [0] is PropertyInfo)
2919 // We found an event: the cache lookup returns both the event and
2920 // its private field.
2922 if (list [0] is EventInfo) {
2923 if ((list.Length == 2) && (list [1] is FieldInfo))
2924 return new MemberInfo [] { list [0] };
2931 // We found methods, turn the search into "method scan"
2935 if (first_members_list != null) {
2936 if (use_first_members_list) {
2937 method_list = CopyNewMethods (method_list, first_members_list);
2938 use_first_members_list = false;
2941 method_list = CopyNewMethods (method_list, list);
2943 first_members_list = list;
2944 use_first_members_list = true;
2946 mt &= (MemberTypes.Method | MemberTypes.Constructor);
2948 } while (searching);
2950 if (use_first_members_list) {
2951 foreach (MemberInfo mi in first_members_list) {
2952 if (! (mi is MethodBase)) {
2953 method_list = CopyNewMethods (method_list, first_members_list);
2954 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
2957 return (MemberInfo []) first_members_list;
2960 if (method_list != null && method_list.Count > 0) {
2961 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
2964 // This happens if we already used the cache in the first iteration, in this case
2965 // the cache already looked in all interfaces.
2967 if (skip_iface_check)
2971 // Interfaces do not list members they inherit, so we have to
2974 if (!queried_type.IsInterface)
2977 if (queried_type.IsArray)
2978 queried_type = TypeManager.array_type;
2980 Type [] ifaces = GetInterfaces (queried_type);
2984 foreach (Type itype in ifaces){
2987 x = MemberLookup (null, null, itype, mt, bf, name, null);
2995 // Tests whether external method is really special
2996 public static bool IsSpecialMethod (MethodBase mb)
2998 string name = mb.Name;
2999 if (name.StartsWith ("get_") || name.StartsWith ("set_"))
3000 return mb.DeclaringType.GetProperty (name.Substring (4)) != null;
3002 if (name.StartsWith ("add_"))
3003 return mb.DeclaringType.GetEvent (name.Substring (4)) != null;
3005 if (name.StartsWith ("remove_"))
3006 return mb.DeclaringType.GetEvent (name.Substring (7)) != null;
3008 if (name.StartsWith ("op_")){
3009 foreach (string oname in Unary.oper_names) {
3014 foreach (string oname in Binary.oper_names) {
3027 /// There is exactly one instance of this class per type.
3029 public sealed class TypeHandle : IMemberContainer {
3030 public readonly IMemberContainer BaseType;
3032 readonly int id = ++next_id;
3033 static int next_id = 0;
3036 /// Lookup a TypeHandle instance for the given type. If the type doesn't have
3037 /// a TypeHandle yet, a new instance of it is created. This static method
3038 /// ensures that we'll only have one TypeHandle instance per type.
3040 private static TypeHandle GetTypeHandle (Type t)
3042 TypeHandle handle = (TypeHandle) type_hash [t];
3046 handle = new TypeHandle (t);
3047 type_hash.Add (t, handle);
3051 public static MemberCache GetMemberCache (Type t)
3053 return GetTypeHandle (t).MemberCache;
3056 public static void CleanUp ()
3062 /// Returns the TypeHandle for TypeManager.object_type.
3064 public static IMemberContainer ObjectType {
3066 if (object_type != null)
3069 object_type = GetTypeHandle (TypeManager.object_type);
3076 /// Returns the TypeHandle for TypeManager.array_type.
3078 public static IMemberContainer ArrayType {
3080 if (array_type != null)
3083 array_type = GetTypeHandle (TypeManager.array_type);
3089 private static PtrHashtable type_hash = new PtrHashtable ();
3091 private static TypeHandle object_type = null;
3092 private static TypeHandle array_type = null;
3095 private string full_name;
3096 private bool is_interface;
3097 private MemberCache member_cache;
3098 private MemberCache base_cache;
3100 private TypeHandle (Type type)
3103 full_name = type.FullName != null ? type.FullName : type.Name;
3104 if (type.BaseType != null) {
3105 base_cache = TypeManager.LookupMemberCache (type.BaseType);
3106 BaseType = base_cache.Container;
3107 } else if (type.IsInterface)
3108 base_cache = TypeManager.LookupBaseInterfacesCache (type);
3109 this.is_interface = type.IsInterface || type.IsGenericParameter;
3110 this.member_cache = new MemberCache (this);
3113 // IMemberContainer methods
3115 public string Name {
3127 public MemberCache BaseCache {
3133 public bool IsInterface {
3135 return is_interface;
3139 public MemberList GetMembers (MemberTypes mt, BindingFlags bf)
3141 MemberInfo [] members;
3142 if (type is GenericTypeParameterBuilder)
3143 return MemberList.Empty;
3144 if (mt == MemberTypes.Event)
3145 members = type.GetEvents (bf | BindingFlags.DeclaredOnly);
3147 members = type.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
3149 Array.Reverse (members);
3151 return new MemberList (members);
3154 // IMemberFinder methods
3156 public MemberList FindMembers (MemberTypes mt, BindingFlags bf, string name,
3157 MemberFilter filter, object criteria)
3159 return new MemberList (member_cache.FindMembers (mt, bf, name, filter, criteria));
3162 public MemberCache MemberCache {
3164 return member_cache;
3168 public override string ToString ()
3170 if (BaseType != null)
3171 return "TypeHandle (" + id + "," + Name + " : " + BaseType + ")";
3173 return "TypeHandle (" + id + "," + Name + ")";