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
21 using System.Globalization;
22 using System.Collections;
23 using System.Reflection;
24 using System.Reflection.Emit;
25 using System.Text.RegularExpressions;
26 using System.Runtime.CompilerServices;
27 using System.Diagnostics;
29 namespace Mono.CSharp {
31 public class TypeManager {
33 // A list of core types that the compiler requires or uses
35 static public Type object_type;
36 static public Type value_type;
37 static public Type string_type;
38 static public Type int32_type;
39 static public Type uint32_type;
40 static public Type int64_type;
41 static public Type uint64_type;
42 static public Type float_type;
43 static public Type double_type;
44 static public Type char_type;
45 static public Type char_ptr_type;
46 static public Type short_type;
47 static public Type decimal_type;
48 static public Type bool_type;
49 static public Type sbyte_type;
50 static public Type byte_type;
51 static public Type ushort_type;
52 static public Type enum_type;
53 static public Type delegate_type;
54 static public Type multicast_delegate_type;
55 static public Type void_type;
56 static public Type enumeration_type;
57 static public Type array_type;
58 static public Type runtime_handle_type;
59 static public Type icloneable_type;
60 static public Type type_type;
61 static public Type ienumerator_type;
62 static public Type idisposable_type;
63 static public Type default_member_type;
64 static public Type iasyncresult_type;
65 static public Type asynccallback_type;
66 static public Type intptr_type;
67 static public Type monitor_type;
68 static public Type runtime_field_handle_type;
69 static public Type attribute_type;
70 static public Type attribute_usage_type;
71 static public Type dllimport_type;
72 static public Type unverifiable_code_type;
73 static public Type methodimpl_attr_type;
74 static public Type marshal_as_attr_type;
75 static public Type param_array_type;
76 static public Type void_ptr_type;
77 static public Type indexer_name_type;
78 static public Type exception_type;
79 static public object obsolete_attribute_type;
80 static public object conditional_attribute_type;
83 // An empty array of types
85 static public Type [] NoTypes;
89 // Expressions representing the internal types. Used during declaration
92 static public Expression system_object_expr, system_string_expr;
93 static public Expression system_boolean_expr, system_decimal_expr;
94 static public Expression system_single_expr, system_double_expr;
95 static public Expression system_sbyte_expr, system_byte_expr;
96 static public Expression system_int16_expr, system_uint16_expr;
97 static public Expression system_int32_expr, system_uint32_expr;
98 static public Expression system_int64_expr, system_uint64_expr;
99 static public Expression system_char_expr, system_void_expr;
100 static public Expression system_asynccallback_expr;
101 static public Expression system_iasyncresult_expr;
104 // This is only used when compiling corlib
106 static public Type system_int32_type;
107 static public Type system_array_type;
108 static public Type system_type_type;
109 static public Type system_assemblybuilder_type;
110 static public MethodInfo system_int_array_get_length;
111 static public MethodInfo system_int_array_get_rank;
112 static public MethodInfo system_object_array_clone;
113 static public MethodInfo system_int_array_get_length_int;
114 static public MethodInfo system_int_array_get_lower_bound_int;
115 static public MethodInfo system_int_array_get_upper_bound_int;
116 static public MethodInfo system_void_array_copyto_array_int;
117 static public MethodInfo system_void_set_corlib_type_builders;
121 // Internal, not really used outside
123 static Type runtime_helpers_type;
126 // These methods are called by code generated by the compiler
128 static public MethodInfo string_concat_string_string;
129 static public MethodInfo string_concat_object_object;
130 static public MethodInfo string_isinterneted_string;
131 static public MethodInfo system_type_get_type_from_handle;
132 static public MethodInfo object_getcurrent_void;
133 static public MethodInfo bool_movenext_void;
134 static public MethodInfo void_dispose_void;
135 static public MethodInfo void_monitor_enter_object;
136 static public MethodInfo void_monitor_exit_object;
137 static public MethodInfo void_initializearray_array_fieldhandle;
138 static public MethodInfo int_getlength_int;
139 static public MethodInfo delegate_combine_delegate_delegate;
140 static public MethodInfo delegate_remove_delegate_delegate;
141 static public MethodInfo int_get_offset_to_string_data;
142 static public MethodInfo int_array_get_length;
143 static public MethodInfo int_array_get_rank;
144 static public MethodInfo object_array_clone;
145 static public MethodInfo int_array_get_length_int;
146 static public MethodInfo int_array_get_lower_bound_int;
147 static public MethodInfo int_array_get_upper_bound_int;
148 static public MethodInfo void_array_copyto_array_int;
151 // The attribute constructors.
153 static public ConstructorInfo cons_param_array_attribute;
154 static public ConstructorInfo void_decimal_ctor_five_args;
155 static public ConstructorInfo unverifiable_code_ctor;
158 // Holds the Array of Assemblies that have been loaded
159 // (either because it is the default or the user used the
160 // -r command line option)
162 static Assembly [] assemblies;
165 // Keeps a list of module builders. We used this to do lookups
166 // on the modulebuilder using GetType -- needed for arrays
168 static ModuleBuilder [] modules;
171 // This is the type_cache from the assemblies to avoid
172 // hitting System.Reflection on every lookup.
174 static Hashtable types;
177 // This is used to hotld the corresponding TypeContainer objects
178 // since we need this in FindMembers
180 static Hashtable typecontainers;
183 // Keeps track of those types that are defined by the
186 static ArrayList user_types;
188 static PtrHashtable builder_to_declspace;
191 // Tracks the interfaces implemented by typebuilders. We only
192 // enter those who do implement or or more interfaces
194 static PtrHashtable builder_to_ifaces;
197 // Maps MethodBase.RuntimeTypeHandle to a Type array that contains
198 // the arguments to the method
200 static Hashtable method_arguments;
203 // Maps PropertyBuilder to a Type array that contains
204 // the arguments to the indexer
206 static Hashtable indexer_arguments;
209 // Maybe `method_arguments' should be replaced and only
210 // method_internal_params should be kept?
212 static Hashtable method_internal_params;
215 // Keeps track of attribute types
218 static Hashtable builder_to_attr;
221 // Keeps track of methods
224 static Hashtable builder_to_method;
232 /// A filter for Findmembers that uses the Signature object to
235 static bool SignatureFilter (MemberInfo mi, object criteria)
237 Signature sig = (Signature) criteria;
239 if (!(mi is MethodBase))
242 if (mi.Name != sig.name)
245 int count = sig.args.Length;
247 if (mi is MethodBuilder || mi is ConstructorBuilder){
248 Type [] candidate_args = GetArgumentTypes ((MethodBase) mi);
250 if (candidate_args.Length != count)
253 for (int i = 0; i < count; i++)
254 if (candidate_args [i] != sig.args [i])
259 ParameterInfo [] pars = ((MethodBase) mi).GetParameters ();
261 if (pars.Length != count)
264 for (int i = 0; i < count; i++)
265 if (pars [i].ParameterType != sig.args [i])
271 // A delegate that points to the filter above.
272 static MemberFilter signature_filter;
275 // These are expressions that represent some of the internal data types, used
278 static void InitExpressionTypes ()
280 system_object_expr = new TypeLookupExpression ("System.Object");
281 system_string_expr = new TypeLookupExpression ("System.String");
282 system_boolean_expr = new TypeLookupExpression ("System.Boolean");
283 system_decimal_expr = new TypeLookupExpression ("System.Decimal");
284 system_single_expr = new TypeLookupExpression ("System.Single");
285 system_double_expr = new TypeLookupExpression ("System.Double");
286 system_sbyte_expr = new TypeLookupExpression ("System.SByte");
287 system_byte_expr = new TypeLookupExpression ("System.Byte");
288 system_int16_expr = new TypeLookupExpression ("System.Int16");
289 system_uint16_expr = new TypeLookupExpression ("System.UInt16");
290 system_int32_expr = new TypeLookupExpression ("System.Int32");
291 system_uint32_expr = new TypeLookupExpression ("System.UInt32");
292 system_int64_expr = new TypeLookupExpression ("System.Int64");
293 system_uint64_expr = new TypeLookupExpression ("System.UInt64");
294 system_char_expr = new TypeLookupExpression ("System.Char");
295 system_void_expr = new TypeLookupExpression ("System.Void");
296 system_asynccallback_expr = new TypeLookupExpression ("System.AsyncCallback");
297 system_iasyncresult_expr = new TypeLookupExpression ("System.IAsyncResult");
300 static TypeManager ()
302 assemblies = new Assembly [0];
304 user_types = new ArrayList ();
306 types = new Hashtable ();
307 typecontainers = new Hashtable ();
309 builder_to_declspace = new PtrHashtable ();
310 builder_to_attr = new PtrHashtable ();
311 builder_to_method = new PtrHashtable ();
312 method_arguments = new PtrHashtable ();
313 method_internal_params = new PtrHashtable ();
314 indexer_arguments = new PtrHashtable ();
315 builder_to_ifaces = new PtrHashtable ();
317 NoTypes = new Type [0];
319 signature_filter = new MemberFilter (SignatureFilter);
320 InitExpressionTypes ();
323 public static void AddUserType (string name, TypeBuilder t, Type [] ifaces)
328 Type prev = (Type) types [name];
329 TypeContainer tc = builder_to_declspace [prev] as TypeContainer;
333 // This probably never happens, as we catch this before
335 Report.Error (-17, "The type `" + name + "' has already been defined.");
339 tc = builder_to_declspace [t] as TypeContainer;
342 1595, "The type `" + name + "' is defined in an existing assembly;"+
343 " Using the new definition from: " + tc.Location);
344 Report.Warning (1595, "Previously defined in: " + prev.Assembly.FullName);
352 builder_to_ifaces [t] = ifaces;
356 // This entry point is used by types that we define under the covers
358 public static void RegisterBuilder (TypeBuilder tb, Type [] ifaces)
361 builder_to_ifaces [tb] = ifaces;
364 public static void AddUserType (string name, TypeBuilder t, TypeContainer tc, Type [] ifaces)
366 builder_to_declspace.Add (t, tc);
367 typecontainers.Add (name, tc);
368 AddUserType (name, t, ifaces);
371 public static void AddDelegateType (string name, TypeBuilder t, Delegate del)
374 builder_to_declspace.Add (t, del);
377 public static void AddEnumType (string name, TypeBuilder t, Enum en)
380 builder_to_declspace.Add (t, en);
383 public static void AddUserInterface (string name, TypeBuilder t, Interface i, Type [] ifaces)
385 AddUserType (name, t, ifaces);
386 builder_to_declspace.Add (t, i);
389 public static void AddMethod (MethodBuilder builder, MethodData method)
391 builder_to_method.Add (builder, method);
394 public static void RegisterAttrType (Type t, TypeContainer tc)
396 builder_to_attr.Add (t, tc);
400 /// Returns the TypeContainer whose Type is `t' or null if there is no
401 /// TypeContainer for `t' (ie, the Type comes from a library)
403 public static TypeContainer LookupTypeContainer (Type t)
405 return builder_to_declspace [t] as TypeContainer;
408 public static IMemberContainer LookupMemberContainer (Type t)
410 if (t is TypeBuilder) {
411 IMemberContainer container = builder_to_declspace [t] as IMemberContainer;
412 if (container != null)
416 return TypeHandle.GetTypeHandle (t);
419 public static Interface LookupInterface (Type t)
421 return builder_to_declspace [t] as Interface;
424 public static Delegate LookupDelegate (Type t)
426 return builder_to_declspace [t] as Delegate;
429 public static Enum LookupEnum (Type t)
431 return builder_to_declspace [t] as Enum;
434 public static TypeContainer LookupAttr (Type t)
436 return (TypeContainer) builder_to_attr [t];
440 /// Registers an assembly to load types from.
442 public static void AddAssembly (Assembly a)
444 int top = assemblies.Length;
445 Assembly [] n = new Assembly [top + 1];
447 assemblies.CopyTo (n, 0);
454 /// Registers a module builder to lookup types from
456 public static void AddModule (ModuleBuilder mb)
458 int top = modules != null ? modules.Length : 0;
459 ModuleBuilder [] n = new ModuleBuilder [top + 1];
462 modules.CopyTo (n, 0);
468 // Low-level lookup, cache-less
470 static Type LookupTypeReflection (string name)
474 foreach (Assembly a in assemblies){
475 t = a.GetType (name);
480 foreach (ModuleBuilder mb in modules) {
481 t = mb.GetType (name);
489 static Hashtable negative_hits = new Hashtable ();
492 // This function is used when you want to avoid the lookups, and want to go
493 // directly to the source. This will use the cache.
495 // Notice that bypassing the cache is bad, because on Microsoft.NET runtime
496 // GetType ("DynamicType[]") != GetType ("DynamicType[]"), and there is no
497 // way to test things other than doing a fullname compare
499 public static Type LookupTypeDirect (string name)
501 Type t = (Type) types [name];
505 t = LookupTypeReflection (name);
514 /// Returns the Type associated with @name, takes care of the fact that
515 /// reflection expects nested types to be separated from the main type
516 /// with a "+" instead of a "."
518 public static Type LookupType (string name)
523 // First lookup in user defined and cached values
526 t = (Type) types [name];
531 if (negative_hits.Contains (name))
536 // Optimization: ComposedCast will work with an existing type, and might already have the
537 // full name of the type, so the full system lookup can probably be avoided.
540 string [] elements = name.Split ('.');
541 int count = elements.Length;
543 for (int n = 1; n <= count; n++){
544 string top_level_type = String.Join (".", elements, 0, n);
546 t = (Type) types [top_level_type];
548 t = LookupTypeReflection (top_level_type);
559 // We know that System.Object does not have children, and since its the parent of
560 // all the objects, it always gets probbed for inner classes.
562 if (top_level_type == "System.Object")
565 string newt = top_level_type + "+" + String.Join ("+", elements, n, count - n);
566 t = LookupTypeDirect (newt);
573 negative_hits [name] = true;
579 // Returns a list of all namespaces in the assemblies and types loaded.
581 public static Hashtable GetNamespaces ()
583 Hashtable namespaces = new Hashtable ();
585 foreach (Assembly a in assemblies){
586 foreach (Type t in a.GetTypes ()){
587 string ns = t.Namespace;
589 if (namespaces.Contains (ns))
591 namespaces [ns] = ns;
595 foreach (ModuleBuilder mb in modules){
596 foreach (Type t in mb.GetTypes ()){
597 string ns = t.Namespace;
599 if (namespaces.Contains (ns))
601 namespaces [ns] = ns;
604 Console.WriteLine ("Namespaces: " + namespaces.Count);
608 public static void GetAllTypes ()
610 Hashtable namespaces = new Hashtable ();
612 foreach (Assembly a in assemblies){
613 foreach (Type t in a.GetTypes ()){
617 foreach (ModuleBuilder mb in modules){
618 foreach (Type t in mb.GetTypes ()){
624 /// Returns the C# name of a type if possible, or the full type name otherwise
626 static public string CSharpName (Type t)
628 return Regex.Replace (t.FullName,
630 @"(Int32|UInt32|Int16|Uint16|Int64|UInt64|" +
631 @"Single|Double|Char|Decimal|Byte|SByte|Object|" +
632 @"Boolean|String|Void)" +
634 new MatchEvaluator (CSharpNameMatch));
637 static String CSharpNameMatch (Match match)
639 string s = match.Groups [1].Captures [0].Value;
641 Replace ("int32", "int").
642 Replace ("uint32", "uint").
643 Replace ("int16", "short").
644 Replace ("uint16", "ushort").
645 Replace ("int64", "long").
646 Replace ("uint64", "ulong").
647 Replace ("single", "float").
648 Replace ("boolean", "bool")
649 + match.Groups [2].Captures [0].Value;
653 /// Returns the signature of the method
655 static public string CSharpSignature (MethodBase mb)
660 // FIXME: We should really have a single function to do
661 // everything instead of the following 5 line pattern
663 ParameterData iparams = LookupParametersByBuilder (mb);
665 if (iparams == null){
666 ParameterInfo [] pi = mb.GetParameters ();
667 iparams = new ReflectionParameters (pi);
670 for (int i = 0; i < iparams.Count; i++) {
674 sig += iparams.ParameterDesc(i);
678 return mb.DeclaringType.Name + "." + mb.Name + sig;
682 /// Looks up a type, and aborts if it is not found. This is used
683 /// by types required by the compiler
685 static Type CoreLookupType (string name)
687 Type t = LookupType (name);
690 Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
691 Environment.Exit (0);
698 /// Returns the MethodInfo for a method named `name' defined
699 /// in type `t' which takes arguments of types `args'
701 static MethodInfo GetMethod (Type t, string name, Type [] args)
709 list = FindMembers (t, MemberTypes.Method, instance_and_static | BindingFlags.Public,
710 signature_filter, sig);
711 if (list.Count == 0) {
712 Report.Error (-19, "Can not find the core function `" + name + "'");
716 MethodInfo mi = list [0] as MethodInfo;
718 Report.Error (-19, "Can not find the core function `" + name + "'");
726 /// Returns the ConstructorInfo for "args"
728 static ConstructorInfo GetConstructor (Type t, Type [] args)
736 list = FindMembers (t, MemberTypes.Constructor,
737 instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly,
738 signature_filter, sig);
739 if (list.Count == 0){
740 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
744 ConstructorInfo ci = list [0] as ConstructorInfo;
746 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
753 public static void InitEnumUnderlyingTypes ()
756 int32_type = CoreLookupType ("System.Int32");
757 int64_type = CoreLookupType ("System.Int64");
758 uint32_type = CoreLookupType ("System.UInt32");
759 uint64_type = CoreLookupType ("System.UInt64");
760 byte_type = CoreLookupType ("System.Byte");
761 sbyte_type = CoreLookupType ("System.SByte");
762 short_type = CoreLookupType ("System.Int16");
763 ushort_type = CoreLookupType ("System.UInt16");
767 /// The types have to be initialized after the initial
768 /// population of the type has happened (for example, to
769 /// bootstrap the corlib.dll
771 public static void InitCoreTypes ()
773 object_type = CoreLookupType ("System.Object");
774 value_type = CoreLookupType ("System.ValueType");
776 InitEnumUnderlyingTypes ();
778 char_type = CoreLookupType ("System.Char");
779 string_type = CoreLookupType ("System.String");
780 float_type = CoreLookupType ("System.Single");
781 double_type = CoreLookupType ("System.Double");
782 char_ptr_type = CoreLookupType ("System.Char*");
783 decimal_type = CoreLookupType ("System.Decimal");
784 bool_type = CoreLookupType ("System.Boolean");
785 enum_type = CoreLookupType ("System.Enum");
787 multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
788 delegate_type = CoreLookupType ("System.Delegate");
790 array_type = CoreLookupType ("System.Array");
791 void_type = CoreLookupType ("System.Void");
792 type_type = CoreLookupType ("System.Type");
794 runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
795 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
796 default_member_type = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
797 runtime_handle_type = CoreLookupType ("System.RuntimeTypeHandle");
798 asynccallback_type = CoreLookupType ("System.AsyncCallback");
799 iasyncresult_type = CoreLookupType ("System.IAsyncResult");
800 ienumerator_type = CoreLookupType ("System.Collections.IEnumerator");
801 idisposable_type = CoreLookupType ("System.IDisposable");
802 icloneable_type = CoreLookupType ("System.ICloneable");
803 monitor_type = CoreLookupType ("System.Threading.Monitor");
804 intptr_type = CoreLookupType ("System.IntPtr");
806 attribute_type = CoreLookupType ("System.Attribute");
807 attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
808 dllimport_type = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute");
809 methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute");
810 marshal_as_attr_type = CoreLookupType ("System.Runtime.InteropServices.MarshalAsAttribute");
811 param_array_type = CoreLookupType ("System.ParamArrayAttribute");
813 unverifiable_code_type= CoreLookupType ("System.Security.UnverifiableCodeAttribute");
815 void_ptr_type = CoreLookupType ("System.Void*");
817 indexer_name_type = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute");
819 exception_type = CoreLookupType ("System.Exception");
824 obsolete_attribute_type = CoreLookupType ("System.ObsoleteAttribute");
825 conditional_attribute_type = CoreLookupType ("System.Diagnostics.ConditionalAttribute");
828 // When compiling corlib, store the "real" types here.
830 if (!RootContext.StdLib) {
831 system_int32_type = typeof (System.Int32);
832 system_array_type = typeof (System.Array);
833 system_type_type = typeof (System.Type);
834 system_assemblybuilder_type = typeof (System.Reflection.Emit.AssemblyBuilder);
836 Type [] void_arg = { };
837 system_int_array_get_length = GetMethod (
838 system_array_type, "get_Length", void_arg);
839 system_int_array_get_rank = GetMethod (
840 system_array_type, "get_Rank", void_arg);
841 system_object_array_clone = GetMethod (
842 system_array_type, "Clone", void_arg);
844 Type [] system_int_arg = { system_int32_type };
845 system_int_array_get_length_int = GetMethod (
846 system_array_type, "GetLength", system_int_arg);
847 system_int_array_get_upper_bound_int = GetMethod (
848 system_array_type, "GetUpperBound", system_int_arg);
849 system_int_array_get_lower_bound_int = GetMethod (
850 system_array_type, "GetLowerBound", system_int_arg);
852 Type [] system_array_int_arg = { system_array_type, system_int32_type };
853 system_void_array_copyto_array_int = GetMethod (
854 system_array_type, "CopyTo", system_array_int_arg);
856 Type [] system_type_type_arg = { system_type_type, system_type_type, system_type_type };
859 system_void_set_corlib_type_builders = GetMethod (
860 system_assemblybuilder_type, "SetCorlibTypeBuilders",
861 system_type_type_arg);
863 object[] args = new object [3];
864 args [0] = object_type;
865 args [1] = value_type;
866 args [2] = enum_type;
868 system_void_set_corlib_type_builders.Invoke (CodeGen.AssemblyBuilder, args);
870 Console.WriteLine ("Corlib compilation is not supported in Microsoft.NET due to bugs in it");
876 // The helper methods that are used by the compiler
878 public static void InitCodeHelpers ()
881 // Now load the default methods that we use.
883 Type [] string_string = { string_type, string_type };
884 string_concat_string_string = GetMethod (
885 string_type, "Concat", string_string);
887 Type [] object_object = { object_type, object_type };
888 string_concat_object_object = GetMethod (
889 string_type, "Concat", object_object);
891 Type [] string_ = { string_type };
892 string_isinterneted_string = GetMethod (
893 string_type, "IsInterned", string_);
895 Type [] runtime_type_handle = { runtime_handle_type };
896 system_type_get_type_from_handle = GetMethod (
897 type_type, "GetTypeFromHandle", runtime_type_handle);
899 Type [] delegate_delegate = { delegate_type, delegate_type };
900 delegate_combine_delegate_delegate = GetMethod (
901 delegate_type, "Combine", delegate_delegate);
903 delegate_remove_delegate_delegate = GetMethod (
904 delegate_type, "Remove", delegate_delegate);
909 Type [] void_arg = { };
910 object_getcurrent_void = GetMethod (
911 ienumerator_type, "get_Current", void_arg);
912 bool_movenext_void = GetMethod (
913 ienumerator_type, "MoveNext", void_arg);
914 void_dispose_void = GetMethod (
915 idisposable_type, "Dispose", void_arg);
916 int_get_offset_to_string_data = GetMethod (
917 runtime_helpers_type, "get_OffsetToStringData", void_arg);
918 int_array_get_length = GetMethod (
919 array_type, "get_Length", void_arg);
920 int_array_get_rank = GetMethod (
921 array_type, "get_Rank", void_arg);
926 Type [] int_arg = { int32_type };
927 int_array_get_length_int = GetMethod (
928 array_type, "GetLength", int_arg);
929 int_array_get_upper_bound_int = GetMethod (
930 array_type, "GetUpperBound", int_arg);
931 int_array_get_lower_bound_int = GetMethod (
932 array_type, "GetLowerBound", int_arg);
935 // System.Array methods
937 object_array_clone = GetMethod (
938 array_type, "Clone", void_arg);
939 Type [] array_int_arg = { array_type, int32_type };
940 void_array_copyto_array_int = GetMethod (
941 array_type, "CopyTo", array_int_arg);
946 Type [] object_arg = { object_type };
947 void_monitor_enter_object = GetMethod (
948 monitor_type, "Enter", object_arg);
949 void_monitor_exit_object = GetMethod (
950 monitor_type, "Exit", object_arg);
952 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
954 void_initializearray_array_fieldhandle = GetMethod (
955 runtime_helpers_type, "InitializeArray", array_field_handle_arg);
960 int_getlength_int = GetMethod (
961 array_type, "GetLength", int_arg);
964 // Decimal constructors
966 Type [] dec_arg = { int32_type, int32_type, int32_type, bool_type, byte_type };
967 void_decimal_ctor_five_args = GetConstructor (
968 decimal_type, dec_arg);
973 cons_param_array_attribute = GetConstructor (
974 param_array_type, void_arg);
976 unverifiable_code_ctor = GetConstructor (
977 unverifiable_code_type, void_arg);
981 const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
983 static Hashtable type_hash = new Hashtable ();
986 /// This is the "old", non-cache based FindMembers() function. We cannot use
987 /// the cache here because there is no member name argument.
989 public static MemberList FindMembers (Type t, MemberTypes mt, BindingFlags bf,
990 MemberFilter filter, object criteria)
992 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
995 // `builder_to_declspace' contains all dynamic types.
999 Timer.StartTimer (TimerType.FindMembers);
1000 list = decl.FindMembers (mt, bf, filter, criteria);
1001 Timer.StopTimer (TimerType.FindMembers);
1006 // We have to take care of arrays specially, because GetType on
1007 // a TypeBuilder array will return a Type, not a TypeBuilder,
1008 // and we can not call FindMembers on this type.
1010 if (t.IsSubclassOf (TypeManager.array_type))
1011 return new MemberList (TypeManager.array_type.FindMembers (mt, bf, filter, criteria));
1014 // Since FindMembers will not lookup both static and instance
1015 // members, we emulate this behaviour here.
1017 if ((bf & instance_and_static) == instance_and_static){
1018 MemberInfo [] i_members = t.FindMembers (
1019 mt, bf & ~BindingFlags.Static, filter, criteria);
1021 int i_len = i_members.Length;
1023 MemberInfo one = i_members [0];
1026 // If any of these are present, we are done!
1028 if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
1029 return new MemberList (i_members);
1032 MemberInfo [] s_members = t.FindMembers (
1033 mt, bf & ~BindingFlags.Instance, filter, criteria);
1035 int s_len = s_members.Length;
1036 if (i_len > 0 || s_len > 0)
1037 return new MemberList (i_members, s_members);
1040 return new MemberList (i_members);
1042 return new MemberList (s_members);
1046 return new MemberList (t.FindMembers (mt, bf, filter, criteria));
1051 /// This method is only called from within MemberLookup. It tries to use the member
1052 /// cache if possible and falls back to the normal FindMembers if not. The `used_cache'
1053 /// flag tells the caller whether we used the cache or not. If we used the cache, then
1054 /// our return value will already contain all inherited members and the caller don't need
1055 /// to check base classes and interfaces anymore.
1057 private static MemberList MemberLookup_FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1058 string name, out bool used_cache)
1061 // We have to take care of arrays specially, because GetType on
1062 // a TypeBuilder array will return a Type, not a TypeBuilder,
1063 // and we can not call FindMembers on this type.
1065 if (t.IsSubclassOf (TypeManager.array_type)) {
1067 return TypeHandle.ArrayType.MemberCache.FindMembers (
1068 mt, bf, name, FilterWithClosure_delegate, null);
1072 // If this is a dynamic type, it's always in the `builder_to_declspace' hash table
1073 // and we can ask the DeclSpace for the MemberCache.
1075 if (t is TypeBuilder) {
1076 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1077 MemberCache cache = decl.MemberCache;
1080 // If this DeclSpace has a MemberCache, use it.
1083 if (cache != null) {
1085 return cache.FindMembers (
1086 mt, bf, name, FilterWithClosure_delegate, null);
1089 // If there is no MemberCache, we need to use the "normal" FindMembers.
1092 Timer.StartTimer (TimerType.FindMembers);
1093 list = decl.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1094 FilterWithClosure_delegate, name);
1095 Timer.StopTimer (TimerType.FindMembers);
1101 // This call will always succeed. There is exactly one TypeHandle instance per
1102 // type, TypeHandle.GetTypeHandle() will either return it or create a new one
1103 // if it didn't already exist.
1105 TypeHandle handle = TypeHandle.GetTypeHandle (t);
1108 return handle.MemberCache.FindMembers (mt, bf, name, FilterWithClosure_delegate, null);
1111 public static bool IsBuiltinType (Type t)
1113 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
1114 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1115 t == char_type || t == short_type || t == decimal_type || t == bool_type ||
1116 t == sbyte_type || t == byte_type || t == ushort_type || t == void_type)
1122 public static bool IsDelegateType (Type t)
1124 if (t.IsSubclassOf (TypeManager.delegate_type))
1130 public static bool IsEnumType (Type t)
1132 if (t.IsSubclassOf (TypeManager.enum_type))
1139 // Whether a type is unmanaged. This is used by the unsafe code (25.2)
1141 public static bool IsUnmanagedType (Type t)
1143 if (IsBuiltinType (t) && t != TypeManager.string_type)
1152 if (IsValueType (t)){
1153 if (t is TypeBuilder){
1154 TypeContainer tc = LookupTypeContainer (t);
1156 foreach (Field f in tc.Fields){
1157 if (f.FieldBuilder.IsStatic)
1159 if (!IsUnmanagedType (f.FieldBuilder.FieldType))
1163 FieldInfo [] fields = t.GetFields ();
1165 foreach (FieldInfo f in fields){
1168 if (!IsUnmanagedType (f.FieldType))
1178 public static bool IsValueType (Type t)
1180 if (t.IsSubclassOf (TypeManager.value_type))
1186 public static bool IsInterfaceType (Type t)
1188 Interface iface = builder_to_declspace [t] as Interface;
1197 // Checks whether `type' is a subclass or nested child of `parent'.
1199 public static bool IsSubclassOrNestedChildOf (Type type, Type parent)
1202 if ((type == parent) || type.IsSubclassOf (parent))
1205 // Handle nested types.
1206 type = type.DeclaringType;
1207 } while (type != null);
1213 // Checks whether `type' is a nested child of `parent'.
1215 public static bool IsNestedChildOf (Type type, Type parent)
1217 if ((type == parent) || type.IsSubclassOf (parent))
1220 return IsSubclassOrNestedChildOf (type, parent);
1224 /// Returns the User Defined Types
1226 public static ArrayList UserTypes {
1232 public static Hashtable TypeContainers {
1234 return typecontainers;
1238 static Hashtable builder_to_constant;
1240 public static void RegisterConstant (FieldBuilder fb, Const c)
1242 if (builder_to_constant == null)
1243 builder_to_constant = new PtrHashtable ();
1245 if (builder_to_constant.Contains (fb))
1248 builder_to_constant.Add (fb, c);
1251 public static Const LookupConstant (FieldBuilder fb)
1253 if (builder_to_constant == null)
1256 return (Const) builder_to_constant [fb];
1260 /// Gigantic work around for missing features in System.Reflection.Emit follows.
1264 /// Since System.Reflection.Emit can not return MethodBase.GetParameters
1265 /// for anything which is dynamic, and we need this in a number of places,
1266 /// we register this information here, and use it afterwards.
1268 static public bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
1273 method_arguments.Add (mb, args);
1274 method_internal_params.Add (mb, ip);
1279 static public InternalParameters LookupParametersByBuilder (MethodBase mb)
1281 if (! (mb is ConstructorBuilder || mb is MethodBuilder))
1284 if (method_internal_params.Contains (mb))
1285 return (InternalParameters) method_internal_params [mb];
1287 throw new Exception ("Argument for Method not registered" + mb);
1291 /// Returns the argument types for a method based on its methodbase
1293 /// For dynamic methods, we use the compiler provided types, for
1294 /// methods from existing assemblies we load them from GetParameters,
1295 /// and insert them into the cache
1297 static public Type [] GetArgumentTypes (MethodBase mb)
1299 if (method_arguments.Contains (mb))
1300 return (Type []) method_arguments [mb];
1302 ParameterInfo [] pi = mb.GetParameters ();
1304 Type [] types = new Type [c];
1306 for (int i = 0; i < c; i++)
1307 types [i] = pi [i].ParameterType;
1309 method_arguments.Add (mb, types);
1315 /// Returns the argument types for an indexer based on its PropertyInfo
1317 /// For dynamic indexers, we use the compiler provided types, for
1318 /// indexers from existing assemblies we load them from GetParameters,
1319 /// and insert them into the cache
1321 static public Type [] GetArgumentTypes (PropertyInfo indexer)
1323 if (indexer_arguments.Contains (indexer))
1324 return (Type []) indexer_arguments [indexer];
1325 else if (indexer is PropertyBuilder)
1326 // If we're a PropertyBuilder and not in the
1327 // `indexer_arguments' hash, then we're a property and
1331 ParameterInfo [] pi = indexer.GetIndexParameters ();
1332 // Property, not an indexer.
1336 Type [] types = new Type [c];
1338 for (int i = 0; i < c; i++)
1339 types [i] = pi [i].ParameterType;
1341 indexer_arguments.Add (indexer, types);
1347 // This is a workaround the fact that GetValue is not
1348 // supported for dynamic types
1350 static Hashtable fields = new Hashtable ();
1351 static public bool RegisterFieldValue (FieldBuilder fb, object value)
1353 if (fields.Contains (fb))
1356 fields.Add (fb, value);
1361 static public object GetValue (FieldBuilder fb)
1366 static Hashtable fieldbuilders_to_fields = new Hashtable ();
1367 static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f)
1369 if (fieldbuilders_to_fields.Contains (fb))
1372 fieldbuilders_to_fields.Add (fb, f);
1376 static public FieldBase GetField (FieldInfo fb)
1378 return (FieldBase) fieldbuilders_to_fields [fb];
1381 static Hashtable events;
1383 static public bool RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
1386 events = new Hashtable ();
1388 if (events.Contains (eb))
1391 events.Add (eb, new Pair (add, remove));
1396 static public MethodInfo GetAddMethod (EventInfo ei)
1398 if (ei is MyEventBuilder) {
1399 Pair pair = (Pair) events [ei];
1401 return (MethodInfo) pair.First;
1403 return ei.GetAddMethod ();
1406 static public MethodInfo GetRemoveMethod (EventInfo ei)
1408 if (ei is MyEventBuilder) {
1409 Pair pair = (Pair) events [ei];
1411 return (MethodInfo) pair.Second;
1413 return ei.GetAddMethod ();
1416 static Hashtable priv_fields_events;
1418 static public bool RegisterPrivateFieldOfEvent (EventInfo einfo, FieldBuilder builder)
1420 if (priv_fields_events == null)
1421 priv_fields_events = new Hashtable ();
1423 if (priv_fields_events.Contains (einfo))
1426 priv_fields_events.Add (einfo, builder);
1431 static public MemberInfo GetPrivateFieldOfEvent (EventInfo ei)
1433 return (MemberInfo) priv_fields_events [ei];
1436 static Hashtable properties;
1438 static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
1440 if (properties == null)
1441 properties = new Hashtable ();
1443 if (properties.Contains (pb))
1446 properties.Add (pb, new Pair (get, set));
1451 static public bool RegisterIndexer (PropertyBuilder pb, MethodBase get, MethodBase set, Type[] args)
1453 if (!RegisterProperty (pb, get,set))
1456 indexer_arguments.Add (pb, args);
1462 /// Given an array of interface types, expand and eliminate repeated ocurrences
1463 /// of an interface.
1467 /// This expands in context like: IA; IB : IA; IC : IA, IB; the interface "IC" to
1470 public static Type [] ExpandInterfaces (Type [] base_interfaces)
1472 ArrayList new_ifaces = new ArrayList ();
1474 foreach (Type iface in base_interfaces){
1475 if (!new_ifaces.Contains (iface))
1476 new_ifaces.Add (iface);
1478 Type [] implementing = TypeManager.GetInterfaces (iface);
1480 foreach (Type imp in implementing){
1481 if (!new_ifaces.Contains (imp))
1482 new_ifaces.Add (imp);
1485 Type [] ret = new Type [new_ifaces.Count];
1486 new_ifaces.CopyTo (ret, 0);
1491 /// This function returns the interfaces in the type `t'. Works with
1492 /// both types and TypeBuilders.
1494 public static Type [] GetInterfaces (Type t)
1497 // The reason for catching the Array case is that Reflection.Emit
1498 // will not return a TypeBuilder for Array types of TypeBuilder types,
1499 // but will still throw an exception if we try to call GetInterfaces
1502 // Since the array interfaces are always constant, we return those for
1507 t = TypeManager.array_type;
1509 if (t is TypeBuilder){
1510 Type [] parent_ifaces;
1512 if (t.BaseType == null)
1513 parent_ifaces = NoTypes;
1515 parent_ifaces = GetInterfaces (t.BaseType);
1516 Type [] type_ifaces = (Type []) builder_to_ifaces [t];
1517 if (type_ifaces == null)
1518 type_ifaces = NoTypes;
1520 int parent_count = parent_ifaces.Length;
1521 Type [] result = new Type [parent_count + type_ifaces.Length];
1522 parent_ifaces.CopyTo (result, 0);
1523 type_ifaces.CopyTo (result, parent_count);
1527 return t.GetInterfaces ();
1531 /// The following is used to check if a given type implements an interface.
1532 /// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
1534 public static bool ImplementsInterface (Type t, Type iface)
1539 // FIXME OPTIMIZATION:
1540 // as soon as we hit a non-TypeBuiler in the interface
1541 // chain, we could return, as the `Type.GetInterfaces'
1542 // will return all the interfaces implement by the type
1546 interfaces = GetInterfaces (t);
1548 if (interfaces != null){
1549 foreach (Type i in interfaces){
1556 } while (t != null);
1561 // This is a custom version of Convert.ChangeType() which works
1562 // with the TypeBuilder defined types when compiling corlib.
1563 public static object ChangeType (object value, Type conversionType)
1565 if (!(value is IConvertible))
1566 throw new ArgumentException ();
1568 IConvertible convertValue = (IConvertible) value;
1569 CultureInfo ci = CultureInfo.CurrentCulture;
1570 NumberFormatInfo provider = ci.NumberFormat;
1573 // We must use Type.Equals() here since `conversionType' is
1574 // the TypeBuilder created version of a system type and not
1575 // the system type itself. You cannot use Type.GetTypeCode()
1576 // on such a type - it'd always return TypeCode.Object.
1578 if (conversionType.Equals (typeof (Boolean)))
1579 return (object)(convertValue.ToBoolean (provider));
1580 else if (conversionType.Equals (typeof (Byte)))
1581 return (object)(convertValue.ToByte (provider));
1582 else if (conversionType.Equals (typeof (Char)))
1583 return (object)(convertValue.ToChar (provider));
1584 else if (conversionType.Equals (typeof (DateTime)))
1585 return (object)(convertValue.ToDateTime (provider));
1586 else if (conversionType.Equals (typeof (Decimal)))
1587 return (object)(convertValue.ToDecimal (provider));
1588 else if (conversionType.Equals (typeof (Double)))
1589 return (object)(convertValue.ToDouble (provider));
1590 else if (conversionType.Equals (typeof (Int16)))
1591 return (object)(convertValue.ToInt16 (provider));
1592 else if (conversionType.Equals (typeof (Int32)))
1593 return (object)(convertValue.ToInt32 (provider));
1594 else if (conversionType.Equals (typeof (Int64)))
1595 return (object)(convertValue.ToInt64 (provider));
1596 else if (conversionType.Equals (typeof (SByte)))
1597 return (object)(convertValue.ToSByte (provider));
1598 else if (conversionType.Equals (typeof (Single)))
1599 return (object)(convertValue.ToSingle (provider));
1600 else if (conversionType.Equals (typeof (String)))
1601 return (object)(convertValue.ToString (provider));
1602 else if (conversionType.Equals (typeof (UInt16)))
1603 return (object)(convertValue.ToUInt16 (provider));
1604 else if (conversionType.Equals (typeof (UInt32)))
1605 return (object)(convertValue.ToUInt32 (provider));
1606 else if (conversionType.Equals (typeof (UInt64)))
1607 return (object)(convertValue.ToUInt64 (provider));
1608 else if (conversionType.Equals (typeof (Object)))
1609 return (object)(value);
1611 throw new InvalidCastException ();
1615 // This is needed, because enumerations from assemblies
1616 // do not report their underlyingtype, but they report
1619 public static Type EnumToUnderlying (Type t)
1621 if (t == TypeManager.enum_type)
1624 t = t.UnderlyingSystemType;
1625 if (!TypeManager.IsEnumType (t))
1628 if (t is TypeBuilder) {
1629 // slow path needed to compile corlib
1630 if (t == TypeManager.bool_type ||
1631 t == TypeManager.byte_type ||
1632 t == TypeManager.sbyte_type ||
1633 t == TypeManager.char_type ||
1634 t == TypeManager.short_type ||
1635 t == TypeManager.ushort_type ||
1636 t == TypeManager.int32_type ||
1637 t == TypeManager.uint32_type ||
1638 t == TypeManager.int64_type ||
1639 t == TypeManager.uint64_type)
1641 throw new Exception ("Unhandled typecode in enum " + " from " + t.AssemblyQualifiedName);
1643 TypeCode tc = Type.GetTypeCode (t);
1646 case TypeCode.Boolean:
1647 return TypeManager.bool_type;
1649 return TypeManager.byte_type;
1650 case TypeCode.SByte:
1651 return TypeManager.sbyte_type;
1653 return TypeManager.char_type;
1654 case TypeCode.Int16:
1655 return TypeManager.short_type;
1656 case TypeCode.UInt16:
1657 return TypeManager.ushort_type;
1658 case TypeCode.Int32:
1659 return TypeManager.int32_type;
1660 case TypeCode.UInt32:
1661 return TypeManager.uint32_type;
1662 case TypeCode.Int64:
1663 return TypeManager.int64_type;
1664 case TypeCode.UInt64:
1665 return TypeManager.uint64_type;
1667 throw new Exception ("Unhandled typecode in enum " + tc + " from " + t.AssemblyQualifiedName);
1671 // When compiling corlib and called with one of the core types, return
1672 // the corresponding typebuilder for that type.
1674 public static Type TypeToCoreType (Type t)
1676 if (RootContext.StdLib || (t is TypeBuilder))
1679 TypeCode tc = Type.GetTypeCode (t);
1682 case TypeCode.Boolean:
1683 return TypeManager.bool_type;
1685 return TypeManager.byte_type;
1686 case TypeCode.SByte:
1687 return TypeManager.sbyte_type;
1689 return TypeManager.char_type;
1690 case TypeCode.Int16:
1691 return TypeManager.short_type;
1692 case TypeCode.UInt16:
1693 return TypeManager.ushort_type;
1694 case TypeCode.Int32:
1695 return TypeManager.int32_type;
1696 case TypeCode.UInt32:
1697 return TypeManager.uint32_type;
1698 case TypeCode.Int64:
1699 return TypeManager.int64_type;
1700 case TypeCode.UInt64:
1701 return TypeManager.uint64_type;
1702 case TypeCode.String:
1703 return TypeManager.string_type;
1705 if (t == typeof (void))
1706 return TypeManager.void_type;
1707 if (t == typeof (object))
1708 return TypeManager.object_type;
1709 if (t == typeof (System.Type))
1710 return TypeManager.type_type;
1716 /// Utility function that can be used to probe whether a type
1717 /// is managed or not.
1719 public static bool VerifyUnManaged (Type t, Location loc)
1721 if (t.IsValueType || t.IsPointer){
1723 // FIXME: this is more complex, we actually need to
1724 // make sure that the type does not contain any
1730 if (!RootContext.StdLib && (t == TypeManager.decimal_type))
1731 // We need this explicit check here to make it work when
1732 // compiling corlib.
1737 "Cannot take the address or size of a variable of a managed type ('" +
1738 CSharpName (t) + "')");
1743 /// Returns the name of the indexer in a given type.
1746 /// The default is not always `Item'. The user can change this behaviour by
1747 /// using the DefaultMemberAttribute in the class.
1749 /// For example, the String class indexer is named `Chars' not `Item'
1751 public static string IndexerPropertyName (Type t)
1753 if (t is TypeBuilder) {
1754 if (t.IsInterface) {
1755 Interface i = LookupInterface (t);
1757 if ((i == null) || (i.IndexerName == null))
1760 return i.IndexerName;
1762 TypeContainer tc = LookupTypeContainer (t);
1764 if ((tc == null) || (tc.IndexerName == null))
1767 return tc.IndexerName;
1771 System.Attribute attr = System.Attribute.GetCustomAttribute (
1772 t, TypeManager.default_member_type);
1774 DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
1775 return dma.MemberName;
1781 public static void MakePinned (LocalBuilder builder)
1784 // FIXME: Flag the "LocalBuilder" type as being
1785 // pinned. Figure out API.
1791 // Returns whether the array of memberinfos contains the given method
1793 static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method)
1795 Type [] new_args = TypeManager.GetArgumentTypes (new_method);
1797 foreach (MethodBase method in array){
1798 if (method.Name != new_method.Name)
1801 Type [] old_args = TypeManager.GetArgumentTypes (method);
1802 int old_count = old_args.Length;
1805 if (new_args.Length != old_count)
1808 for (i = 0; i < old_count; i++){
1809 if (old_args [i] != new_args [i])
1821 // We copy methods from `new_members' into `target_list' if the signature
1822 // for the method from in the new list does not exist in the target_list
1824 // The name is assumed to be the same.
1826 public static ArrayList CopyNewMethods (ArrayList target_list, MemberList new_members)
1828 if (target_list == null){
1829 target_list = new ArrayList ();
1831 foreach (MemberInfo mi in new_members){
1832 if (mi is MethodBase)
1833 target_list.Add (mi);
1838 MemberInfo [] target_array = new MemberInfo [target_list.Count];
1839 target_list.CopyTo (target_array, 0);
1841 foreach (MemberInfo mi in new_members){
1842 MethodBase new_method = (MethodBase) mi;
1844 if (!ArrayContainsMethod (target_array, new_method))
1845 target_list.Add (new_method);
1851 public enum MethodFlags {
1853 IsObsoleteError = 2,
1858 // Returns the TypeManager.MethodFlags for this method.
1859 // This emits an error 619 / warning 618 if the method is obsolete.
1860 // In the former case, TypeManager.MethodFlags.IsObsoleteError is returned.
1862 static public MethodFlags GetMethodFlags (MethodBase mb, Location loc)
1864 MethodFlags flags = 0;
1866 if (mb.DeclaringType is TypeBuilder){
1867 MethodData method = (MethodData) builder_to_method [mb];
1868 if (method == null) {
1869 // FIXME: implement Obsolete attribute on Property,
1870 // Indexer and Event.
1874 return method.GetMethodFlags (loc);
1877 object [] attrs = mb.GetCustomAttributes (true);
1878 foreach (object ta in attrs){
1879 if (!(ta is System.Attribute)){
1880 Console.WriteLine ("Unknown type in GetMethodFlags: " + ta);
1883 System.Attribute a = (System.Attribute) ta;
1884 if (a.TypeId == TypeManager.obsolete_attribute_type){
1885 ObsoleteAttribute oa = (ObsoleteAttribute) a;
1887 string method_desc = TypeManager.CSharpSignature (mb);
1890 Report.Error (619, loc, "Method `" + method_desc +
1891 "' is obsolete: `" + oa.Message + "'");
1892 return MethodFlags.IsObsoleteError;
1894 Report.Warning (618, loc, "Method `" + method_desc +
1895 "' is obsolete: `" + oa.Message + "'");
1897 flags |= MethodFlags.IsObsolete;
1903 // Skip over conditional code.
1905 if (a.TypeId == TypeManager.conditional_attribute_type){
1906 ConditionalAttribute ca = (ConditionalAttribute) a;
1908 if (RootContext.AllDefines [ca.ConditionString] == null)
1909 flags |= MethodFlags.ShouldIgnore;
1916 #region MemberLookup implementation
1919 // Name of the member
1921 static string closure_name;
1924 // Whether we allow private members in the result (since FindMembers
1925 // uses NonPublic for both protected and private), we need to distinguish.
1927 static bool closure_private_ok;
1930 // Who is invoking us and which type is being queried currently.
1932 static Type closure_invocation_type;
1933 static Type closure_queried_type;
1934 static Type closure_start_type;
1937 // The assembly that defines the type is that is calling us
1939 static Assembly closure_invocation_assembly;
1942 // This filter filters by name + whether it is ok to include private
1943 // members in the search
1945 static internal bool FilterWithClosure (MemberInfo m, object filter_criteria)
1948 // Hack: we know that the filter criteria will always be in the `closure'
1952 if ((filter_criteria != null) && (m.Name != (string) filter_criteria))
1955 if ((closure_start_type == closure_invocation_type) &&
1956 (m.DeclaringType == closure_invocation_type))
1960 // Ugly: we need to find out the type of `m', and depending
1961 // on this, tell whether we accept or not
1963 if (m is MethodBase){
1964 MethodBase mb = (MethodBase) m;
1965 MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
1967 if (ma == MethodAttributes.Private)
1968 return closure_private_ok || (closure_invocation_type == m.DeclaringType);
1971 // FamAndAssem requires that we not only derivate, but we are on the
1974 if (ma == MethodAttributes.FamANDAssem){
1975 if (closure_invocation_assembly != mb.DeclaringType.Assembly)
1979 // Assembly and FamORAssem succeed if we're in the same assembly.
1980 if ((ma == MethodAttributes.Assembly) || (ma == MethodAttributes.FamORAssem)){
1981 if (closure_invocation_assembly == mb.DeclaringType.Assembly)
1985 // We already know that we aren't in the same assembly.
1986 if (ma == MethodAttributes.Assembly)
1989 // Family and FamANDAssem require that we derive.
1990 if ((ma == MethodAttributes.Family) || (ma == MethodAttributes.FamANDAssem)){
1991 if (closure_invocation_type == null)
1994 if (!IsSubclassOrNestedChildOf (closure_invocation_type, mb.DeclaringType))
1997 // Although a derived class can access protected members of its base class
1998 // it cannot do so through an instance of the base class (CS1540).
1999 if (!mb.IsStatic && (closure_invocation_type != closure_start_type) &&
2000 closure_invocation_type.IsSubclassOf (closure_start_type))
2010 if (m is FieldInfo){
2011 FieldInfo fi = (FieldInfo) m;
2012 FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
2014 if (fa == FieldAttributes.Private)
2015 return closure_private_ok || (closure_invocation_type == m.DeclaringType);
2018 // FamAndAssem requires that we not only derivate, but we are on the
2021 if (fa == FieldAttributes.FamANDAssem){
2022 if (closure_invocation_assembly != fi.DeclaringType.Assembly)
2026 // Assembly and FamORAssem succeed if we're in the same assembly.
2027 if ((fa == FieldAttributes.Assembly) || (fa == FieldAttributes.FamORAssem)){
2028 if (closure_invocation_assembly == fi.DeclaringType.Assembly)
2032 // We already know that we aren't in the same assembly.
2033 if (fa == FieldAttributes.Assembly)
2036 // Family and FamANDAssem require that we derive.
2037 if ((fa == FieldAttributes.Family) || (fa == FieldAttributes.FamANDAssem)){
2038 if (closure_invocation_type == null)
2041 if (!IsSubclassOrNestedChildOf (closure_invocation_type, fi.DeclaringType))
2044 // Although a derived class can access protected members of its base class
2045 // it cannot do so through an instance of the base class (CS1540).
2046 if (!fi.IsStatic && (closure_invocation_type != closure_start_type) &&
2047 closure_invocation_type.IsSubclassOf (closure_start_type))
2058 // EventInfos and PropertyInfos, return true because they lack permission
2059 // informaiton, so we need to check later on the methods.
2064 static MemberFilter FilterWithClosure_delegate = new MemberFilter (FilterWithClosure);
2067 // Looks up a member called `name' in the `queried_type'. This lookup
2068 // is done by code that is contained in the definition for `invocation_type'.
2070 // The binding flags are `bf' and the kind of members being looked up are `mt'
2072 // Returns an array of a single element for everything but Methods/Constructors
2073 // that might return multiple matches.
2075 public static MemberInfo [] MemberLookup (Type invocation_type, Type queried_type,
2076 MemberTypes mt, BindingFlags original_bf, string name)
2078 Timer.StartTimer (TimerType.MemberLookup);
2080 MemberInfo[] retval = RealMemberLookup (invocation_type, queried_type,
2081 mt, original_bf, name);
2083 Timer.StopTimer (TimerType.MemberLookup);
2088 static MemberInfo [] RealMemberLookup (Type invocation_type, Type queried_type,
2089 MemberTypes mt, BindingFlags original_bf, string name)
2091 BindingFlags bf = original_bf;
2093 ArrayList method_list = null;
2094 Type current_type = queried_type;
2095 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
2097 bool always_ok_flag = false;
2098 bool skip_iface_check = true, used_cache = false;
2100 closure_name = name;
2101 closure_invocation_type = invocation_type;
2102 closure_invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
2103 closure_start_type = queried_type;
2106 // If we are a nested class, we always have access to our container
2109 if (invocation_type != null){
2110 string invocation_name = invocation_type.FullName;
2111 if (invocation_name.IndexOf ('+') != -1){
2112 string container = queried_type.FullName + "+";
2113 int container_length = container.Length;
2115 if (invocation_name.Length > container_length){
2116 string shared = invocation_name.Substring (0, container_length);
2118 if (shared == container)
2119 always_ok_flag = true;
2128 // `NonPublic' is lame, because it includes both protected and
2129 // private methods, so we need to control this behavior by
2130 // explicitly tracking if a private method is ok or not.
2132 // The possible cases are:
2133 // public, private and protected (internal does not come into the
2136 if (invocation_type != null){
2137 if (invocation_type == current_type){
2140 private_ok = always_ok_flag;
2142 if (private_ok || invocation_type.IsSubclassOf (current_type))
2143 bf = original_bf | BindingFlags.NonPublic;
2146 bf = original_bf & ~BindingFlags.NonPublic;
2149 closure_private_ok = private_ok;
2150 closure_queried_type = current_type;
2152 Timer.StopTimer (TimerType.MemberLookup);
2154 list = MemberLookup_FindMembers (current_type, mt, bf, name, out used_cache);
2156 Timer.StartTimer (TimerType.MemberLookup);
2159 // When queried for an interface type, the cache will automatically check all
2160 // inherited members, so we don't need to do this here. However, this only
2161 // works if we already used the cache in the first iteration of this loop.
2163 // If we used the cache in any further iteration, we can still terminate the
2164 // loop since the cache always looks in all parent classes.
2170 skip_iface_check = false;
2172 if (current_type == TypeManager.object_type)
2175 current_type = current_type.BaseType;
2178 // This happens with interfaces, they have a null
2179 // basetype. Look members up in the Object class.
2181 if (current_type == null)
2182 current_type = TypeManager.object_type;
2185 if (list.Count == 0)
2189 // Events and types are returned by both `static' and `instance'
2190 // searches, which means that our above FindMembers will
2191 // return two copies of the same.
2193 if (list.Count == 1 && !(list [0] is MethodBase)){
2194 return (MemberInfo []) list;
2198 // Multiple properties: we query those just to find out the indexer
2201 if (list [0] is PropertyInfo)
2202 return (MemberInfo []) list;
2205 // We found methods, turn the search into "method scan"
2209 method_list = CopyNewMethods (method_list, list);
2210 mt &= (MemberTypes.Method | MemberTypes.Constructor);
2211 } while (searching);
2213 if (method_list != null && method_list.Count > 0)
2214 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
2217 // This happens if we already used the cache in the first iteration, in this case
2218 // the cache already looked in all interfaces.
2220 if (skip_iface_check)
2224 // Interfaces do not list members they inherit, so we have to
2227 if (!queried_type.IsInterface)
2230 if (queried_type.IsArray)
2231 queried_type = TypeManager.array_type;
2233 Type [] ifaces = GetInterfaces (queried_type);
2237 foreach (Type itype in ifaces){
2240 x = MemberLookup (null, itype, mt, bf, name);
2252 /// There is exactly one instance of this class per type.
2254 public sealed class TypeHandle : IMemberContainer {
2255 public readonly TypeHandle BaseType;
2257 readonly int id = ++next_id;
2258 static int next_id = 0;
2261 /// Lookup a TypeHandle instance for the given type. If the type doesn't have
2262 /// a TypeHandle yet, a new instance of it is created. This static method
2263 /// ensures that we'll only have one TypeHandle instance per type.
2265 public static TypeHandle GetTypeHandle (Type t)
2267 TypeHandle handle = (TypeHandle) type_hash [t];
2271 handle = new TypeHandle (t);
2272 type_hash.Add (t, handle);
2277 /// Returns the TypeHandle for TypeManager.object_type.
2279 public static IMemberContainer ObjectType {
2281 if (object_type != null)
2284 object_type = GetTypeHandle (TypeManager.object_type);
2291 /// Returns the TypeHandle for TypeManager.array_type.
2293 public static IMemberContainer ArrayType {
2295 if (array_type != null)
2298 array_type = GetTypeHandle (TypeManager.array_type);
2304 private static PtrHashtable type_hash = new PtrHashtable ();
2306 private static TypeHandle object_type = null;
2307 private static TypeHandle array_type = null;
2310 private bool is_interface;
2311 private MemberCache member_cache;
2313 private TypeHandle (Type type)
2316 if (type.BaseType != null)
2317 BaseType = GetTypeHandle (type.BaseType);
2318 else if ((type != TypeManager.object_type) && (type != typeof (object)))
2319 is_interface = true;
2320 this.member_cache = new MemberCache (this);
2323 // IMemberContainer methods
2325 public string Name {
2327 return type.FullName;
2337 public IMemberContainer Parent {
2343 public bool IsInterface {
2345 return is_interface;
2349 public MemberList GetMembers (MemberTypes mt, BindingFlags bf)
2351 if (mt == MemberTypes.Event)
2352 return new MemberList (type.GetEvents (bf | BindingFlags.DeclaredOnly));
2354 return new MemberList (type.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
2358 // IMemberFinder methods
2360 public MemberList FindMembers (MemberTypes mt, BindingFlags bf, string name,
2361 MemberFilter filter, object criteria)
2363 return member_cache.FindMembers (mt, bf, name, filter, criteria);
2366 public MemberCache MemberCache {
2368 return member_cache;
2372 public override string ToString ()
2374 if (BaseType != null)
2375 return "TypeHandle (" + id + "," + Name + " : " + BaseType + ")";
2377 return "TypeHandle (" + id + "," + Name + ")";