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 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 new_constraint_attr_type;
83 static public Type param_array_type;
84 static public Type guid_attr_type;
85 static public Type void_ptr_type;
86 static public Type indexer_name_type;
87 static public Type exception_type;
88 static public Type activator_type;
89 static public Type invalid_operation_exception_type;
90 static public Type not_supported_exception_type;
91 static public Type obsolete_attribute_type;
92 static public Type conditional_attribute_type;
93 static public Type in_attribute_type;
94 static public Type anonymous_method_type;
95 static public Type cls_compliant_attribute_type;
96 static public Type typed_reference_type;
97 static public Type arg_iterator_type;
98 static public Type mbr_type;
99 static public Type struct_layout_attribute_type;
100 static public Type field_offset_attribute_type;
101 static public Type security_attr_type;
103 static public Type generic_ienumerator_type;
104 static public Type generic_ienumerable_type;
107 // An empty array of types
109 static public Type [] NoTypes;
110 static public TypeExpr [] NoTypeExprs;
114 // Expressions representing the internal types. Used during declaration
117 static public TypeExpr system_object_expr, system_string_expr;
118 static public TypeExpr system_boolean_expr, system_decimal_expr;
119 static public TypeExpr system_single_expr, system_double_expr;
120 static public TypeExpr system_sbyte_expr, system_byte_expr;
121 static public TypeExpr system_int16_expr, system_uint16_expr;
122 static public TypeExpr system_int32_expr, system_uint32_expr;
123 static public TypeExpr system_int64_expr, system_uint64_expr;
124 static public TypeExpr system_char_expr, system_void_expr;
125 static public TypeExpr system_asynccallback_expr;
126 static public TypeExpr system_iasyncresult_expr;
127 static public TypeExpr system_valuetype_expr;
128 static public TypeExpr system_intptr_expr;
131 // This is only used when compiling corlib
133 static public Type system_int32_type;
134 static public Type system_array_type;
135 static public Type system_type_type;
136 static public Type system_assemblybuilder_type;
137 static public MethodInfo system_int_array_get_length;
138 static public MethodInfo system_int_array_get_rank;
139 static public MethodInfo system_object_array_clone;
140 static public MethodInfo system_int_array_get_length_int;
141 static public MethodInfo system_int_array_get_lower_bound_int;
142 static public MethodInfo system_int_array_get_upper_bound_int;
143 static public MethodInfo system_void_array_copyto_array_int;
147 // Internal, not really used outside
149 static Type runtime_helpers_type;
152 // These methods are called by code generated by the compiler
154 static public MethodInfo string_concat_string_string;
155 static public MethodInfo string_concat_string_string_string;
156 static public MethodInfo string_concat_string_string_string_string;
157 static public MethodInfo string_concat_string_dot_dot_dot;
158 static public MethodInfo string_concat_object_object;
159 static public MethodInfo string_concat_object_object_object;
160 static public MethodInfo string_concat_object_dot_dot_dot;
161 static public MethodInfo string_isinterneted_string;
162 static public MethodInfo system_type_get_type_from_handle;
163 static public MethodInfo object_getcurrent_void;
164 static public MethodInfo bool_movenext_void;
165 static public MethodInfo ienumerable_getenumerator_void;
166 static public MethodInfo void_reset_void;
167 static public MethodInfo void_dispose_void;
168 static public MethodInfo void_monitor_enter_object;
169 static public MethodInfo void_monitor_exit_object;
170 static public MethodInfo void_initializearray_array_fieldhandle;
171 static public MethodInfo int_getlength_int;
172 static public MethodInfo delegate_combine_delegate_delegate;
173 static public MethodInfo delegate_remove_delegate_delegate;
174 static public MethodInfo int_get_offset_to_string_data;
175 static public MethodInfo int_array_get_length;
176 static public MethodInfo int_array_get_rank;
177 static public MethodInfo object_array_clone;
178 static public MethodInfo int_array_get_length_int;
179 static public MethodInfo int_array_get_lower_bound_int;
180 static public MethodInfo int_array_get_upper_bound_int;
181 static public MethodInfo void_array_copyto_array_int;
182 static public MethodInfo activator_create_instance;
185 // The attribute constructors.
187 static public ConstructorInfo object_ctor;
188 static public ConstructorInfo cons_param_array_attribute;
189 static public ConstructorInfo void_decimal_ctor_five_args;
190 static public ConstructorInfo void_decimal_ctor_int_arg;
191 static public ConstructorInfo unverifiable_code_ctor;
192 static public ConstructorInfo invalid_operation_ctor;
193 static public ConstructorInfo default_member_ctor;
194 static public ConstructorInfo decimal_constant_attribute_ctor;
197 // Holds the Array of Assemblies that have been loaded
198 // (either because it is the default or the user used the
199 // -r command line option)
201 static Assembly [] assemblies;
204 // Keeps a list of modules. We used this to do lookups
205 // on the module using GetType -- needed for arrays
207 static Module [] modules;
210 // This is the type_cache from the assemblies to avoid
211 // hitting System.Reflection on every lookup.
213 static Hashtable types;
216 // This is used to hotld the corresponding TypeContainer objects
217 // since we need this in FindMembers
219 static Hashtable typecontainers;
222 // Keeps track of those types that are defined by the
225 static ArrayList user_types;
227 static PtrHashtable builder_to_declspace;
229 static PtrHashtable builder_to_member_cache;
232 // Tracks the interfaces implemented by typebuilders. We only
233 // enter those who do implement or or more interfaces
235 static PtrHashtable builder_to_ifaces;
238 // Tracks the generic parameters.
240 static PtrHashtable builder_to_type_param;
243 // Maps MethodBase.RuntimeTypeHandle to a Type array that contains
244 // the arguments to the method
246 static Hashtable method_arguments;
249 // Maps PropertyBuilder to a Type array that contains
250 // the arguments to the indexer
252 static Hashtable indexer_arguments;
255 // Maybe `method_arguments' should be replaced and only
256 // method_internal_params should be kept?
258 static Hashtable method_internal_params;
261 // Keeps track of methods
264 static Hashtable builder_to_method;
267 // Contains all public types from referenced assemblies.
268 // This member is used only if CLS Compliance verification is required.
270 public static Hashtable all_imported_types;
277 public static void CleanUp ()
279 // Lets get everything clean so that we can collect before generating code
283 typecontainers = null;
285 builder_to_declspace = null;
286 builder_to_member_cache = null;
287 builder_to_ifaces = null;
288 method_arguments = null;
289 indexer_arguments = null;
290 method_internal_params = null;
291 builder_to_method = null;
292 builder_to_type_param = null;
296 negative_hits = null;
297 builder_to_constant = null;
298 fieldbuilders_to_fields = null;
300 priv_fields_events = null;
303 TypeHandle.CleanUp ();
307 /// A filter for Findmembers that uses the Signature object to
310 static bool SignatureFilter (MemberInfo mi, object criteria)
312 Signature sig = (Signature) criteria;
314 if (!(mi is MethodBase))
317 if (mi.Name != sig.name)
320 int count = sig.args.Length;
322 if (mi is MethodBuilder || mi is ConstructorBuilder){
323 Type [] candidate_args = GetArgumentTypes ((MethodBase) mi);
325 if (candidate_args.Length != count)
328 for (int i = 0; i < count; i++)
329 if (candidate_args [i] != sig.args [i])
334 ParameterInfo [] pars = ((MethodBase) mi).GetParameters ();
336 if (pars.Length != count)
339 for (int i = 0; i < count; i++)
340 if (pars [i].ParameterType != sig.args [i])
346 // A delegate that points to the filter above.
347 static MemberFilter signature_filter;
350 // These are expressions that represent some of the internal data types, used
353 static void InitExpressionTypes ()
355 system_object_expr = new TypeLookupExpression ("System.Object");
356 system_string_expr = new TypeLookupExpression ("System.String");
357 system_boolean_expr = new TypeLookupExpression ("System.Boolean");
358 system_decimal_expr = new TypeLookupExpression ("System.Decimal");
359 system_single_expr = new TypeLookupExpression ("System.Single");
360 system_double_expr = new TypeLookupExpression ("System.Double");
361 system_sbyte_expr = new TypeLookupExpression ("System.SByte");
362 system_byte_expr = new TypeLookupExpression ("System.Byte");
363 system_int16_expr = new TypeLookupExpression ("System.Int16");
364 system_uint16_expr = new TypeLookupExpression ("System.UInt16");
365 system_int32_expr = new TypeLookupExpression ("System.Int32");
366 system_uint32_expr = new TypeLookupExpression ("System.UInt32");
367 system_int64_expr = new TypeLookupExpression ("System.Int64");
368 system_uint64_expr = new TypeLookupExpression ("System.UInt64");
369 system_char_expr = new TypeLookupExpression ("System.Char");
370 system_void_expr = new TypeLookupExpression ("System.Void");
371 system_asynccallback_expr = new TypeLookupExpression ("System.AsyncCallback");
372 system_iasyncresult_expr = new TypeLookupExpression ("System.IAsyncResult");
373 system_valuetype_expr = new TypeLookupExpression ("System.ValueType");
374 system_intptr_expr = new TypeLookupExpression ("System.IntPtr");
377 static TypeManager ()
379 assemblies = new Assembly [0];
381 user_types = new ArrayList ();
383 types = new Hashtable ();
384 typecontainers = new Hashtable ();
386 builder_to_declspace = new PtrHashtable ();
387 builder_to_member_cache = new PtrHashtable ();
388 builder_to_method = new PtrHashtable ();
389 method_arguments = new PtrHashtable ();
390 method_internal_params = new PtrHashtable ();
391 indexer_arguments = new PtrHashtable ();
392 builder_to_ifaces = new PtrHashtable ();
393 builder_to_type_param = new PtrHashtable ();
395 NoTypes = new Type [0];
396 NoTypeExprs = new TypeExpr [0];
398 signature_filter = new MemberFilter (SignatureFilter);
399 InitExpressionTypes ();
402 public static void HandleDuplicate (string name, Type t)
404 Type prev = (Type) types [name];
405 TypeContainer tc = builder_to_declspace [prev] as TypeContainer;
409 // This probably never happens, as we catch this before
411 Report.Error (-17, "The type `" + name + "' has already been defined.");
415 tc = builder_to_declspace [t] as TypeContainer;
418 1595, "The type `" + name + "' is defined in an existing assembly;"+
419 " Using the new definition from: " + tc.Location);
422 1595, "The type `" + name + "' is defined in an existing assembly;");
425 Report.Warning (1595, "Previously defined in: " + prev.Assembly.FullName);
431 public static void AddUserType (string name, TypeBuilder t)
436 HandleDuplicate (name, t);
442 // This entry point is used by types that we define under the covers
444 public static void RegisterBuilder (Type tb, Type [] ifaces)
447 builder_to_ifaces [tb] = ifaces;
450 public static void AddUserType (string name, TypeBuilder t, TypeContainer tc)
452 builder_to_declspace.Add (t, tc);
453 typecontainers.Add (name, tc);
454 AddUserType (name, t);
457 public static void AddDelegateType (string name, TypeBuilder t, Delegate del)
462 HandleDuplicate (name, t);
465 builder_to_declspace.Add (t, del);
468 public static void AddEnumType (string name, TypeBuilder t, Enum en)
473 HandleDuplicate (name, t);
475 builder_to_declspace.Add (t, en);
478 public static void AddMethod (MethodBase builder, IMethodData method)
480 builder_to_method.Add (builder, method);
483 public static IMethodData GetMethod (MethodBase builder)
485 return (IMethodData) builder_to_method [builder];
488 public static void AddTypeParameter (Type t, TypeParameter tparam)
490 if (!builder_to_type_param.Contains (t))
491 builder_to_type_param.Add (t, tparam);
495 /// Returns the DeclSpace whose Type is `t' or null if there is no
496 /// DeclSpace for `t' (ie, the Type comes from a library)
498 public static DeclSpace LookupDeclSpace (Type t)
500 return builder_to_declspace [t] as DeclSpace;
504 /// Returns the TypeContainer whose Type is `t' or null if there is no
505 /// TypeContainer for `t' (ie, the Type comes from a library)
507 public static TypeContainer LookupTypeContainer (Type t)
509 return builder_to_declspace [t] as TypeContainer;
512 public static TypeContainer LookupGenericTypeContainer (Type t)
514 while (t.IsGenericInstance)
515 t = t.GetGenericTypeDefinition ();
517 return LookupTypeContainer (t);
520 public static MemberCache LookupMemberCache (Type t)
522 if (t is TypeBuilder) {
523 IMemberContainer container = builder_to_declspace [t] as IMemberContainer;
524 if (container != null)
525 return container.MemberCache;
528 if (t is GenericTypeParameterBuilder) {
529 IMemberContainer container = builder_to_type_param [t] as IMemberContainer;
531 if (container != null)
532 return container.MemberCache;
535 return TypeHandle.GetMemberCache (t);
538 public static MemberCache LookupParentInterfacesCache (Type t)
540 Type [] ifaces = t.GetInterfaces ();
542 if (ifaces != null && ifaces.Length == 1)
543 return LookupMemberCache (ifaces [0]);
545 // TODO: the builder_to_member_cache should be indexed by 'ifaces', not 't'
546 MemberCache cache = builder_to_member_cache [t] as MemberCache;
550 cache = new MemberCache (ifaces);
551 builder_to_member_cache.Add (t, cache);
555 public static TypeContainer LookupInterface (Type t)
557 TypeContainer tc = (TypeContainer) builder_to_declspace [t];
558 if ((tc == null) || (tc.Kind != Kind.Interface))
564 public static Delegate LookupDelegate (Type t)
566 return builder_to_declspace [t] as Delegate;
569 public static Enum LookupEnum (Type t)
571 return builder_to_declspace [t] as Enum;
574 public static Class LookupClass (Type t)
576 return (Class) builder_to_declspace [t];
579 public static TypeParameter LookupTypeParameter (Type t)
581 return (TypeParameter) builder_to_type_param [t];
584 public static bool HasConstructorConstraint (Type t)
586 GenericConstraints gc = GetTypeParameterConstraints (t);
590 return (gc.Attributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0;
593 public static GenericConstraints GetTypeParameterConstraints (Type t)
595 if (!t.IsGenericParameter)
596 throw new InvalidOperationException ();
598 TypeParameter tparam = LookupTypeParameter (t);
600 return tparam.GenericConstraints;
602 return new ReflectionConstraints (t);
606 /// Registers an assembly to load types from.
608 public static void AddAssembly (Assembly a)
610 foreach (Assembly assembly in assemblies) {
615 int top = assemblies.Length;
616 Assembly [] n = new Assembly [top + 1];
618 assemblies.CopyTo (n, 0);
624 public static Assembly [] GetAssemblies ()
630 /// Registers a module builder to lookup types from
632 public static void AddModule (Module mb)
634 int top = modules != null ? modules.Length : 0;
635 Module [] n = new Module [top + 1];
638 modules.CopyTo (n, 0);
643 public static Module[] Modules {
649 static Hashtable references = new Hashtable ();
652 // Gets the reference to T version of the Type (T&)
654 public static Type GetReferenceType (Type t)
656 return t.MakeByRefType ();
659 static Hashtable pointers = new Hashtable ();
662 // Gets the pointer to T version of the Type (T*)
664 public static Type GetPointerType (Type t)
666 string tname = t.FullName + "*";
668 Type ret = t.Assembly.GetType (tname);
671 // If the type comes from the assembly we are building
672 // We need the Hashtable, because .NET 1.1 will return different instance types
673 // every time we call ModuleBuilder.GetType.
676 if (pointers [t] == null)
677 pointers [t] = CodeGen.Module.Builder.GetType (tname);
679 ret = (Type) pointers [t];
686 // Low-level lookup, cache-less
688 static Type LookupTypeReflection (string name)
692 foreach (Assembly a in assemblies){
693 t = a.GetType (name);
698 TypeAttributes ta = t.Attributes & TypeAttributes.VisibilityMask;
699 if (ta == TypeAttributes.NotPublic ||
700 ta == TypeAttributes.NestedPrivate ||
701 ta == TypeAttributes.NestedAssembly ||
702 ta == TypeAttributes.NestedFamANDAssem){
705 // In .NET pointers turn out to be private, even if their
706 // element type is not
709 t = t.GetElementType ();
719 foreach (Module mb in modules) {
720 t = mb.GetType (name);
728 static Hashtable negative_hits = new Hashtable ();
731 // This function is used when you want to avoid the lookups, and want to go
732 // directly to the source. This will use the cache.
734 // Notice that bypassing the cache is bad, because on Microsoft.NET runtime
735 // GetType ("DynamicType[]") != GetType ("DynamicType[]"), and there is no
736 // way to test things other than doing a fullname compare
738 public static Type LookupTypeDirect (string name)
740 Type t = (Type) types [name];
744 t = LookupTypeReflection (name);
752 static readonly char [] dot_array = { '.' };
755 /// Returns the Type associated with @name, takes care of the fact that
756 /// reflection expects nested types to be separated from the main type
757 /// with a "+" instead of a "."
759 public static Type LookupType (string name)
764 // First lookup in user defined and cached values
767 t = (Type) types [name];
771 // Two thirds of the failures are caught here.
772 if (negative_hits.Contains (name))
775 // Sadly, split takes a param array, so this ends up allocating *EVERY TIME*
776 string [] elements = name.Split (dot_array);
777 int count = elements.Length;
779 for (int n = 1; n <= count; n++){
780 string top_level_type = String.Join (".", elements, 0, n);
782 // One third of the failures are caught here.
783 if (negative_hits.Contains (top_level_type))
786 t = (Type) types [top_level_type];
788 t = LookupTypeReflection (top_level_type);
790 negative_hits [top_level_type] = null;
801 // We know that System.Object does not have children, and since its the parent of
802 // all the objects, it always gets probbed for inner classes.
804 if (top_level_type == "System.Object")
807 string newt = top_level_type + "+" + String.Join ("+", elements, n, count - n);
808 //Console.WriteLine ("Looking up: " + newt + " " + name);
809 t = LookupTypeReflection (newt);
811 negative_hits [name] = null;
816 negative_hits [name] = null;
821 /// Computes the namespaces that we import from the assemblies we reference.
823 public static void ComputeNamespaces ()
825 MethodInfo assembly_get_namespaces = typeof (Assembly).GetMethod ("GetNamespaces", BindingFlags.Instance|BindingFlags.NonPublic);
828 // First add the assembly namespaces
830 if (assembly_get_namespaces != null){
831 int count = assemblies.Length;
833 for (int i = 0; i < count; i++){
834 Assembly a = assemblies [i];
835 string [] namespaces = (string []) assembly_get_namespaces.Invoke (a, null);
836 foreach (string ns in namespaces){
839 Namespace.LookupNamespace (ns, true);
843 Hashtable cache = new Hashtable ();
844 cache.Add ("", null);
845 foreach (Assembly a in assemblies) {
846 foreach (Type t in a.GetExportedTypes ()) {
847 string ns = t.Namespace;
848 if (ns == null || cache.Contains (ns))
851 Namespace.LookupNamespace (ns, true);
852 cache.Add (ns, null);
859 /// Fills static table with exported types from all referenced assemblies.
860 /// This information is required for CLS Compliance tests.
862 public static void LoadAllImportedTypes ()
864 all_imported_types = new Hashtable ();
865 foreach (Assembly a in assemblies) {
866 foreach (Type t in a.GetExportedTypes ()) {
867 all_imported_types [t.FullName] = t;
872 public static bool NamespaceClash (string name, Location loc)
874 if (Namespace.LookupNamespace (name, false) == null)
877 Report.Error (519, loc, String.Format ("`{0}' clashes with a predefined namespace", name));
882 /// Returns the C# name of a type if possible, or the full type name otherwise
884 static public string CSharpName (Type t)
886 if (t.FullName == null)
889 return Regex.Replace (t.FullName,
891 @"(Int32|UInt32|Int16|UInt16|Int64|UInt64|" +
892 @"Single|Double|Char|Decimal|Byte|SByte|Object|" +
893 @"Boolean|String|Void|Null)" +
895 new MatchEvaluator (CSharpNameMatch));
898 static String CSharpNameMatch (Match match)
900 string s = match.Groups [1].Captures [0].Value;
902 Replace ("int32", "int").
903 Replace ("uint32", "uint").
904 Replace ("int16", "short").
905 Replace ("uint16", "ushort").
906 Replace ("int64", "long").
907 Replace ("uint64", "ulong").
908 Replace ("single", "float").
909 Replace ("boolean", "bool")
910 + match.Groups [2].Captures [0].Value;
914 /// Returns the signature of the method with full namespace classification
916 static public string GetFullNameSignature (MemberInfo mi)
918 return mi.DeclaringType.FullName.Replace ('+', '.') + '.' + mi.Name;
921 static public string GetFullNameSignature (MethodBase mb)
923 string name = mb.Name;
925 name = mb.DeclaringType.Name;
927 if (mb.IsSpecialName) {
928 if (name.StartsWith ("get_") || name.StartsWith ("set_")) {
929 name = name.Remove (0, 4);
936 return mb.DeclaringType.FullName.Replace ('+', '.') + '.' + name;
939 static public string GetFullName (Type t)
941 if (t.FullName == null)
944 string name = t.FullName.Replace ('+', '.');
946 DeclSpace tc = LookupDeclSpace (t);
947 if ((tc != null) && tc.IsGeneric) {
948 TypeParameter[] tparam = tc.TypeParameters;
950 StringBuilder sb = new StringBuilder (name);
952 for (int i = 0; i < tparam.Length; i++) {
955 sb.Append (tparam [i].Name);
958 return sb.ToString ();
959 } else if (t.HasGenericArguments && !t.IsGenericInstance) {
960 Type[] tparam = t.GetGenericArguments ();
962 StringBuilder sb = new StringBuilder (name);
964 for (int i = 0; i < tparam.Length; i++) {
967 sb.Append (tparam [i].Name);
970 return sb.ToString ();
977 /// Returns the signature of the property and indexer
979 static public string CSharpSignature (PropertyBuilder pb, bool is_indexer)
982 return GetFullNameSignature (pb);
985 MethodBase mb = pb.GetSetMethod (true) != null ? pb.GetSetMethod (true) : pb.GetGetMethod (true);
986 string signature = GetFullNameSignature (mb);
987 string arg = TypeManager.LookupParametersByBuilder (mb).ParameterDesc (0);
988 return String.Format ("{0}.this[{1}]", signature.Substring (0, signature.LastIndexOf ('.')), arg);
992 /// Returns the signature of the method
994 static public string CSharpSignature (MethodBase mb)
996 StringBuilder sig = new StringBuilder ("(");
999 // FIXME: We should really have a single function to do
1000 // everything instead of the following 5 line pattern
1002 ParameterData iparams = LookupParametersByBuilder (mb);
1004 if (iparams == null)
1005 iparams = new ReflectionParameters (mb);
1008 if (mb.IsSpecialName && iparams.Count == 0 && !mb.IsConstructor)
1009 return GetFullNameSignature (mb);
1011 for (int i = 0; i < iparams.Count; i++) {
1015 sig.Append (iparams.ParameterDesc (i));
1020 if (mb.IsSpecialName && iparams.Count == 1 && !mb.IsConstructor) {
1021 sig.Replace ('(', '[');
1022 sig.Replace (')', ']');
1025 return GetFullNameSignature (mb) + sig.ToString ();
1028 public static string GetMethodName (MethodInfo m)
1030 if (!IsGenericMethod (m))
1033 return MemberName.MakeName (m.Name, m.GetGenericArguments ().Length);
1037 /// Looks up a type, and aborts if it is not found. This is used
1038 /// by types required by the compiler
1040 static Type CoreLookupType (string name)
1042 Type t = LookupTypeDirect (name);
1045 Report.Error (518, "The predefined type `" + name + "' is not defined or imported");
1046 Environment.Exit (1);
1053 /// Returns the MethodInfo for a method named `name' defined
1054 /// in type `t' which takes arguments of types `args'
1056 static MethodInfo GetMethod (Type t, string name, Type [] args, bool is_private, bool report_errors)
1060 BindingFlags flags = instance_and_static | BindingFlags.Public;
1066 flags |= BindingFlags.NonPublic;
1068 list = FindMembers (t, MemberTypes.Method, flags, signature_filter, sig);
1069 if (list.Count == 0) {
1071 Report.Error (-19, "Can not find the core function `" + name + "'");
1075 MethodInfo mi = list [0] as MethodInfo;
1078 Report.Error (-19, "Can not find the core function `" + name + "'");
1085 static MethodInfo GetMethod (Type t, string name, Type [] args, bool report_errors)
1087 return GetMethod (t, name, args, false, report_errors);
1090 static MethodInfo GetMethod (Type t, string name, Type [] args)
1092 return GetMethod (t, name, args, true);
1097 /// Returns the ConstructorInfo for "args"
1099 static ConstructorInfo GetConstructor (Type t, Type [] args)
1107 list = FindMembers (t, MemberTypes.Constructor,
1108 instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly,
1109 signature_filter, sig);
1110 if (list.Count == 0){
1111 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
1115 ConstructorInfo ci = list [0] as ConstructorInfo;
1117 Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'");
1124 public static void InitEnumUnderlyingTypes ()
1127 int32_type = CoreLookupType ("System.Int32");
1128 int64_type = CoreLookupType ("System.Int64");
1129 uint32_type = CoreLookupType ("System.UInt32");
1130 uint64_type = CoreLookupType ("System.UInt64");
1131 byte_type = CoreLookupType ("System.Byte");
1132 sbyte_type = CoreLookupType ("System.SByte");
1133 short_type = CoreLookupType ("System.Int16");
1134 ushort_type = CoreLookupType ("System.UInt16");
1138 /// The types have to be initialized after the initial
1139 /// population of the type has happened (for example, to
1140 /// bootstrap the corlib.dll
1142 public static void InitCoreTypes ()
1144 object_type = CoreLookupType ("System.Object");
1145 value_type = CoreLookupType ("System.ValueType");
1147 InitEnumUnderlyingTypes ();
1149 char_type = CoreLookupType ("System.Char");
1150 string_type = CoreLookupType ("System.String");
1151 float_type = CoreLookupType ("System.Single");
1152 double_type = CoreLookupType ("System.Double");
1153 char_ptr_type = CoreLookupType ("System.Char*");
1154 decimal_type = CoreLookupType ("System.Decimal");
1155 bool_type = CoreLookupType ("System.Boolean");
1156 enum_type = CoreLookupType ("System.Enum");
1158 multicast_delegate_type = CoreLookupType ("System.MulticastDelegate");
1159 delegate_type = CoreLookupType ("System.Delegate");
1161 array_type = CoreLookupType ("System.Array");
1162 void_type = CoreLookupType ("System.Void");
1163 type_type = CoreLookupType ("System.Type");
1165 runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle");
1166 runtime_argument_handle_type = CoreLookupType ("System.RuntimeArgumentHandle");
1167 runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices.RuntimeHelpers");
1168 default_member_type = CoreLookupType ("System.Reflection.DefaultMemberAttribute");
1169 runtime_handle_type = CoreLookupType ("System.RuntimeTypeHandle");
1170 asynccallback_type = CoreLookupType ("System.AsyncCallback");
1171 iasyncresult_type = CoreLookupType ("System.IAsyncResult");
1172 ienumerator_type = CoreLookupType ("System.Collections.IEnumerator");
1173 ienumerable_type = CoreLookupType ("System.Collections.IEnumerable");
1174 idisposable_type = CoreLookupType ("System.IDisposable");
1175 icloneable_type = CoreLookupType ("System.ICloneable");
1176 iconvertible_type = CoreLookupType ("System.IConvertible");
1177 monitor_type = CoreLookupType ("System.Threading.Monitor");
1178 intptr_type = CoreLookupType ("System.IntPtr");
1180 attribute_type = CoreLookupType ("System.Attribute");
1181 attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute");
1182 dllimport_type = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute");
1183 methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute");
1184 marshal_as_attr_type = CoreLookupType ("System.Runtime.InteropServices.MarshalAsAttribute");
1185 new_constraint_attr_type = CoreLookupType ("System.Runtime.CompilerServices.NewConstraintAttribute");
1186 param_array_type = CoreLookupType ("System.ParamArrayAttribute");
1187 in_attribute_type = CoreLookupType ("System.Runtime.InteropServices.InAttribute");
1188 typed_reference_type = CoreLookupType ("System.TypedReference");
1189 arg_iterator_type = CoreLookupType ("System.ArgIterator");
1190 mbr_type = CoreLookupType ("System.MarshalByRefObject");
1191 decimal_constant_attribute_type = CoreLookupType ("System.Runtime.CompilerServices.DecimalConstantAttribute");
1194 // Sigh. Remove this before the release. Wonder what versions of Mono
1195 // people are running.
1197 guid_attr_type = LookupType ("System.Runtime.InteropServices.GuidAttribute");
1199 unverifiable_code_type= CoreLookupType ("System.Security.UnverifiableCodeAttribute");
1201 void_ptr_type = CoreLookupType ("System.Void*");
1203 indexer_name_type = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute");
1205 exception_type = CoreLookupType ("System.Exception");
1206 activator_type = CoreLookupType ("System.Activator");
1207 invalid_operation_exception_type = CoreLookupType ("System.InvalidOperationException");
1208 not_supported_exception_type = CoreLookupType ("System.NotSupportedException");
1213 obsolete_attribute_type = CoreLookupType ("System.ObsoleteAttribute");
1214 conditional_attribute_type = CoreLookupType ("System.Diagnostics.ConditionalAttribute");
1215 cls_compliant_attribute_type = CoreLookupType ("System.CLSCompliantAttribute");
1216 struct_layout_attribute_type = CoreLookupType ("System.Runtime.InteropServices.StructLayoutAttribute");
1217 field_offset_attribute_type = CoreLookupType ("System.Runtime.InteropServices.FieldOffsetAttribute");
1218 security_attr_type = CoreLookupType ("System.Security.Permissions.SecurityAttribute");
1223 generic_ienumerator_type = CoreLookupType (MemberName.MakeName ("System.Collections.Generic.IEnumerator", 1));
1224 generic_ienumerable_type = CoreLookupType (MemberName.MakeName ("System.Collections.Generic.IEnumerable", 1));
1228 // When compiling corlib, store the "real" types here.
1230 if (!RootContext.StdLib) {
1231 system_int32_type = typeof (System.Int32);
1232 system_array_type = typeof (System.Array);
1233 system_type_type = typeof (System.Type);
1234 system_assemblybuilder_type = typeof (System.Reflection.Emit.AssemblyBuilder);
1236 Type [] void_arg = { };
1237 system_int_array_get_length = GetMethod (
1238 system_array_type, "get_Length", void_arg);
1239 system_int_array_get_rank = GetMethod (
1240 system_array_type, "get_Rank", void_arg);
1241 system_object_array_clone = GetMethod (
1242 system_array_type, "Clone", void_arg);
1244 Type [] system_int_arg = { system_int32_type };
1245 system_int_array_get_length_int = GetMethod (
1246 system_array_type, "GetLength", system_int_arg);
1247 system_int_array_get_upper_bound_int = GetMethod (
1248 system_array_type, "GetUpperBound", system_int_arg);
1249 system_int_array_get_lower_bound_int = GetMethod (
1250 system_array_type, "GetLowerBound", system_int_arg);
1252 Type [] system_array_int_arg = { system_array_type, system_int32_type };
1253 system_void_array_copyto_array_int = GetMethod (
1254 system_array_type, "CopyTo", system_array_int_arg);
1256 Type [] system_3_type_arg = {
1257 system_type_type, system_type_type, system_type_type };
1258 Type [] system_4_type_arg = {
1259 system_type_type, system_type_type, system_type_type, system_type_type };
1261 MethodInfo set_corlib_type_builders = GetMethod (
1262 system_assemblybuilder_type, "SetCorlibTypeBuilders",
1263 system_4_type_arg, true, false);
1265 if (set_corlib_type_builders != null) {
1266 object[] args = new object [4];
1267 args [0] = object_type;
1268 args [1] = value_type;
1269 args [2] = enum_type;
1270 args [3] = void_type;
1272 set_corlib_type_builders.Invoke (CodeGen.Assembly.Builder, args);
1274 // Compatibility for an older version of the class libs.
1275 set_corlib_type_builders = GetMethod (
1276 system_assemblybuilder_type, "SetCorlibTypeBuilders",
1277 system_3_type_arg, true, true);
1279 if (set_corlib_type_builders == null) {
1280 Report.Error (-26, "Corlib compilation is not supported in Microsoft.NET due to bugs in it");
1284 object[] args = new object [3];
1285 args [0] = object_type;
1286 args [1] = value_type;
1287 args [2] = enum_type;
1289 set_corlib_type_builders.Invoke (CodeGen.Assembly.Builder, args);
1293 system_object_expr.Type = object_type;
1294 system_string_expr.Type = string_type;
1295 system_boolean_expr.Type = bool_type;
1296 system_decimal_expr.Type = decimal_type;
1297 system_single_expr.Type = float_type;
1298 system_double_expr.Type = double_type;
1299 system_sbyte_expr.Type = sbyte_type;
1300 system_byte_expr.Type = byte_type;
1301 system_int16_expr.Type = short_type;
1302 system_uint16_expr.Type = ushort_type;
1303 system_int32_expr.Type = int32_type;
1304 system_uint32_expr.Type = uint32_type;
1305 system_int64_expr.Type = int64_type;
1306 system_uint64_expr.Type = uint64_type;
1307 system_char_expr.Type = char_type;
1308 system_void_expr.Type = void_type;
1309 system_asynccallback_expr.Type = asynccallback_type;
1310 system_iasyncresult_expr.Type = iasyncresult_type;
1311 system_valuetype_expr.Type = value_type;
1314 // These are only used for compare purposes
1316 anonymous_method_type = typeof (AnonymousMethod);
1317 null_type = typeof (NullType);
1321 // The helper methods that are used by the compiler
1323 public static void InitCodeHelpers ()
1326 // Now load the default methods that we use.
1328 Type [] string_string = { string_type, string_type };
1329 string_concat_string_string = GetMethod (
1330 string_type, "Concat", string_string);
1331 Type [] string_string_string = { string_type, string_type, string_type };
1332 string_concat_string_string_string = GetMethod (
1333 string_type, "Concat", string_string_string);
1334 Type [] string_string_string_string = { string_type, string_type, string_type, string_type };
1335 string_concat_string_string_string_string = GetMethod (
1336 string_type, "Concat", string_string_string_string);
1337 Type[] params_string = { TypeManager.LookupType ("System.String[]") };
1338 string_concat_string_dot_dot_dot = GetMethod (
1339 string_type, "Concat", params_string);
1341 Type [] object_object = { object_type, object_type };
1342 string_concat_object_object = GetMethod (
1343 string_type, "Concat", object_object);
1344 Type [] object_object_object = { object_type, object_type, object_type };
1345 string_concat_object_object_object = GetMethod (
1346 string_type, "Concat", object_object_object);
1347 Type[] params_object = { TypeManager.LookupType ("System.Object[]") };
1348 string_concat_object_dot_dot_dot = GetMethod (
1349 string_type, "Concat", params_object);
1351 Type [] string_ = { string_type };
1352 string_isinterneted_string = GetMethod (
1353 string_type, "IsInterned", string_);
1355 Type [] runtime_type_handle = { runtime_handle_type };
1356 system_type_get_type_from_handle = GetMethod (
1357 type_type, "GetTypeFromHandle", runtime_type_handle);
1359 Type [] delegate_delegate = { delegate_type, delegate_type };
1360 delegate_combine_delegate_delegate = GetMethod (
1361 delegate_type, "Combine", delegate_delegate);
1363 delegate_remove_delegate_delegate = GetMethod (
1364 delegate_type, "Remove", delegate_delegate);
1369 Type [] void_arg = { };
1370 object_getcurrent_void = GetMethod (
1371 ienumerator_type, "get_Current", void_arg);
1372 bool_movenext_void = GetMethod (
1373 ienumerator_type, "MoveNext", void_arg);
1374 void_reset_void = GetMethod (
1375 ienumerator_type, "Reset", void_arg);
1376 void_dispose_void = GetMethod (
1377 idisposable_type, "Dispose", void_arg);
1378 int_get_offset_to_string_data = GetMethod (
1379 runtime_helpers_type, "get_OffsetToStringData", void_arg);
1380 int_array_get_length = GetMethod (
1381 array_type, "get_Length", void_arg);
1382 int_array_get_rank = GetMethod (
1383 array_type, "get_Rank", void_arg);
1384 ienumerable_getenumerator_void = GetMethod (
1385 ienumerable_type, "GetEnumerator", void_arg);
1390 Type [] int_arg = { int32_type };
1391 int_array_get_length_int = GetMethod (
1392 array_type, "GetLength", int_arg);
1393 int_array_get_upper_bound_int = GetMethod (
1394 array_type, "GetUpperBound", int_arg);
1395 int_array_get_lower_bound_int = GetMethod (
1396 array_type, "GetLowerBound", int_arg);
1399 // System.Array methods
1401 object_array_clone = GetMethod (
1402 array_type, "Clone", void_arg);
1403 Type [] array_int_arg = { array_type, int32_type };
1404 void_array_copyto_array_int = GetMethod (
1405 array_type, "CopyTo", array_int_arg);
1410 Type [] object_arg = { object_type };
1411 void_monitor_enter_object = GetMethod (
1412 monitor_type, "Enter", object_arg);
1413 void_monitor_exit_object = GetMethod (
1414 monitor_type, "Exit", object_arg);
1416 Type [] array_field_handle_arg = { array_type, runtime_field_handle_type };
1418 void_initializearray_array_fieldhandle = GetMethod (
1419 runtime_helpers_type, "InitializeArray", array_field_handle_arg);
1424 int_getlength_int = GetMethod (
1425 array_type, "GetLength", int_arg);
1428 // Decimal constructors
1430 Type [] dec_arg = { int32_type, int32_type, int32_type, bool_type, byte_type };
1431 void_decimal_ctor_five_args = GetConstructor (
1432 decimal_type, dec_arg);
1434 void_decimal_ctor_int_arg = GetConstructor (decimal_type, int_arg);
1439 cons_param_array_attribute = GetConstructor (
1440 param_array_type, void_arg);
1442 unverifiable_code_ctor = GetConstructor (
1443 unverifiable_code_type, void_arg);
1445 decimal_constant_attribute_ctor = GetConstructor (decimal_constant_attribute_type, new Type []
1446 { byte_type, byte_type, uint32_type, uint32_type, uint32_type } );
1448 default_member_ctor = GetConstructor (default_member_type, string_);
1451 // InvalidOperationException
1453 invalid_operation_ctor = GetConstructor (
1454 invalid_operation_exception_type, void_arg);
1458 object_ctor = GetConstructor (object_type, void_arg);
1461 Type [] type_arg = { type_type };
1462 activator_create_instance = GetMethod (
1463 activator_type, "CreateInstance", type_arg);
1466 const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance;
1469 /// This is the "old", non-cache based FindMembers() function. We cannot use
1470 /// the cache here because there is no member name argument.
1472 public static MemberList FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1473 MemberFilter filter, object criteria)
1475 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1478 // `builder_to_declspace' contains all dynamic types.
1482 Timer.StartTimer (TimerType.FindMembers);
1483 list = decl.FindMembers (mt, bf, filter, criteria);
1484 Timer.StopTimer (TimerType.FindMembers);
1489 // We have to take care of arrays specially, because GetType on
1490 // a TypeBuilder array will return a Type, not a TypeBuilder,
1491 // and we can not call FindMembers on this type.
1493 if (t.IsSubclassOf (TypeManager.array_type))
1494 return new MemberList (TypeManager.array_type.FindMembers (mt, bf, filter, criteria));
1496 if (t is GenericTypeParameterBuilder) {
1497 TypeParameter tparam = (TypeParameter) builder_to_type_param [t];
1499 Timer.StartTimer (TimerType.FindMembers);
1500 MemberList list = tparam.FindMembers (
1501 mt, bf | BindingFlags.DeclaredOnly, filter, criteria);
1502 Timer.StopTimer (TimerType.FindMembers);
1507 // Since FindMembers will not lookup both static and instance
1508 // members, we emulate this behaviour here.
1510 if ((bf & instance_and_static) == instance_and_static){
1511 MemberInfo [] i_members = t.FindMembers (
1512 mt, bf & ~BindingFlags.Static, filter, criteria);
1514 int i_len = i_members.Length;
1516 MemberInfo one = i_members [0];
1519 // If any of these are present, we are done!
1521 if ((one is Type) || (one is EventInfo) || (one is FieldInfo))
1522 return new MemberList (i_members);
1525 MemberInfo [] s_members = t.FindMembers (
1526 mt, bf & ~BindingFlags.Instance, filter, criteria);
1528 int s_len = s_members.Length;
1529 if (i_len > 0 || s_len > 0)
1530 return new MemberList (i_members, s_members);
1533 return new MemberList (i_members);
1535 return new MemberList (s_members);
1539 return new MemberList (t.FindMembers (mt, bf, filter, criteria));
1544 /// This method is only called from within MemberLookup. It tries to use the member
1545 /// cache if possible and falls back to the normal FindMembers if not. The `used_cache'
1546 /// flag tells the caller whether we used the cache or not. If we used the cache, then
1547 /// our return value will already contain all inherited members and the caller don't need
1548 /// to check base classes and interfaces anymore.
1550 private static MemberInfo [] MemberLookup_FindMembers (Type t, MemberTypes mt, BindingFlags bf,
1551 string name, out bool used_cache)
1556 // We have to take care of arrays specially, because GetType on
1557 // a TypeBuilder array will return a Type, not a TypeBuilder,
1558 // and we can not call FindMembers on this type.
1560 if (t == TypeManager.array_type || t.IsSubclassOf (TypeManager.array_type)) {
1562 return TypeHandle.ArrayType.MemberCache.FindMembers (
1563 mt, bf, name, FilterWithClosure_delegate, null);
1567 // If this is a dynamic type, it's always in the `builder_to_declspace' hash table
1568 // and we can ask the DeclSpace for the MemberCache.
1570 if (t is TypeBuilder) {
1571 DeclSpace decl = (DeclSpace) builder_to_declspace [t];
1572 cache = decl.MemberCache;
1575 // If this DeclSpace has a MemberCache, use it.
1578 if (cache != null) {
1580 return cache.FindMembers (
1581 mt, bf, name, FilterWithClosure_delegate, null);
1584 // If there is no MemberCache, we need to use the "normal" FindMembers.
1585 // Note, this is a VERY uncommon route!
1588 Timer.StartTimer (TimerType.FindMembers);
1589 list = decl.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1590 FilterWithClosure_delegate, name);
1591 Timer.StopTimer (TimerType.FindMembers);
1593 return (MemberInfo []) list;
1596 if (t is GenericTypeParameterBuilder) {
1597 TypeParameter tparam = (TypeParameter) builder_to_type_param [t];
1600 Timer.StartTimer (TimerType.FindMembers);
1601 list = tparam.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
1602 FilterWithClosure_delegate, name);
1603 Timer.StopTimer (TimerType.FindMembers);
1605 return (MemberInfo []) list;
1609 // This call will always succeed. There is exactly one TypeHandle instance per
1610 // type, TypeHandle.GetMemberCache() will, if necessary, create a new one, and return
1611 // the corresponding MemberCache.
1613 cache = TypeHandle.GetMemberCache (t);
1616 return cache.FindMembers (mt, bf, name, FilterWithClosure_delegate, null);
1619 public static bool IsBuiltinType (Type t)
1621 if (t == object_type || t == string_type || t == int32_type || t == uint32_type ||
1622 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1623 t == char_type || t == short_type || t == decimal_type || t == bool_type ||
1624 t == sbyte_type || t == byte_type || t == ushort_type || t == void_type)
1630 public static bool IsBuiltinType (TypeContainer tc)
1632 return IsBuiltinType (tc.TypeBuilder);
1636 // This is like IsBuiltinType, but lacks decimal_type, we should also clean up
1637 // the pieces in the code where we use IsBuiltinType and special case decimal_type.
1639 public static bool IsCLRType (Type t)
1641 if (t == object_type || t == int32_type || t == uint32_type ||
1642 t == int64_type || t == uint64_type || t == float_type || t == double_type ||
1643 t == char_type || t == short_type || t == bool_type ||
1644 t == sbyte_type || t == byte_type || t == ushort_type)
1650 public static bool IsDelegateType (Type t)
1652 if (t.IsGenericInstance)
1653 t = t.GetGenericTypeDefinition ();
1655 if (t.IsSubclassOf (TypeManager.delegate_type))
1661 public static bool IsEnumType (Type t)
1663 if (t.IsSubclassOf (TypeManager.enum_type))
1668 public static bool IsBuiltinOrEnum (Type t)
1670 if (IsBuiltinType (t))
1679 public static bool IsNullType (Type t)
1681 return t == null_type;
1685 // Only a quick hack to get things moving, while real runtime support appears
1687 public static bool IsGeneric (Type t)
1689 DeclSpace ds = (DeclSpace) builder_to_declspace [t];
1691 return ds.IsGeneric;
1694 public static bool HasGenericArguments (Type t)
1696 return GetNumberOfTypeArguments (t) > 0;
1699 public static int GetNumberOfTypeArguments (Type t)
1701 DeclSpace tc = LookupDeclSpace (t);
1703 return tc.IsGeneric ? tc.CountTypeParameters : 0;
1705 return t.HasGenericArguments ? t.GetGenericArguments ().Length : 0;
1708 public static Type[] GetTypeArguments (Type t)
1710 DeclSpace tc = LookupDeclSpace (t);
1713 return Type.EmptyTypes;
1715 TypeParameter[] tparam = tc.TypeParameters;
1716 Type[] ret = new Type [tparam.Length];
1717 for (int i = 0; i < tparam.Length; i++) {
1718 ret [i] = tparam [i].Type;
1719 if (ret [i] == null)
1720 throw new InternalErrorException ();
1725 return t.GetGenericArguments ();
1729 // Whether a type is unmanaged. This is used by the unsafe code (25.2)
1731 public static bool IsUnmanagedType (Type t)
1733 if (IsBuiltinType (t) && t != TypeManager.string_type)
1742 if (IsValueType (t)){
1743 if (t is TypeBuilder){
1744 TypeContainer tc = LookupTypeContainer (t);
1746 if (tc.Fields != null){
1747 foreach (Field f in tc.Fields){
1748 if (f.FieldBuilder.IsStatic)
1750 if (!IsUnmanagedType (f.FieldBuilder.FieldType))
1756 FieldInfo [] fields = t.GetFields ();
1758 foreach (FieldInfo f in fields){
1761 if (!IsUnmanagedType (f.FieldType))
1771 public static bool IsValueType (Type t)
1773 return t.IsGenericParameter || t.IsValueType;
1776 public static bool IsInterfaceType (Type t)
1778 TypeContainer tc = (TypeContainer) builder_to_declspace [t];
1782 return tc.Kind == Kind.Interface;
1785 public static bool IsEqual (Type a, Type b)
1790 if ((a is TypeBuilder) && a.IsGenericTypeDefinition && b.IsGenericInstance) {
1792 // `a' is a generic type definition's TypeBuilder and `b' is a
1793 // generic instance of the same type.
1799 // void Test (Stack<T> stack) { }
1802 // The first argument of `Test' will be the generic instance
1803 // "Stack<!0>" - which is the same type than the "Stack" TypeBuilder.
1806 // We hit this via Closure.Filter() for gen-82.cs.
1808 if (a != b.GetGenericTypeDefinition ())
1811 Type[] aparams = a.GetGenericArguments ();
1812 Type[] bparams = b.GetGenericArguments ();
1814 if (aparams.Length != bparams.Length)
1817 for (int i = 0; i < aparams.Length; i++)
1818 if (!IsEqual (aparams [i], bparams [i]))
1824 if (a.IsGenericParameter && b.IsGenericParameter) {
1825 if ((a.DeclaringMethod == null) || (b.DeclaringMethod == null))
1827 return a.GenericParameterPosition == b.GenericParameterPosition;
1830 if (a.IsArray && b.IsArray) {
1831 if (a.GetArrayRank () != b.GetArrayRank ())
1833 return IsEqual (a.GetElementType (), b.GetElementType ());
1836 if (a.IsGenericInstance && b.IsGenericInstance) {
1837 Type at = a.GetGenericTypeDefinition ();
1838 Type bt = b.GetGenericTypeDefinition ();
1840 if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ())
1843 Type[] aargs = a.GetGenericArguments ();
1844 Type[] bargs = b.GetGenericArguments ();
1846 if (aargs.Length != bargs.Length)
1849 for (int i = 0; i < aargs.Length; i++) {
1850 if (!IsEqual (aargs [i], bargs [i]))
1860 public static bool MayBecomeEqualGenericTypes (Type a, Type b)
1862 if (a.IsGenericParameter) {
1864 // If a is an array of a's type, they may never
1868 b = b.GetElementType ();
1874 // If b is a generic parameter or an actual type,
1875 // they may become equal:
1877 // class X<T,U> : I<T>, I<U>
1878 // class X<T> : I<T>, I<float>
1880 if (b.IsGenericParameter || !b.IsGenericInstance)
1884 // We're now comparing a type parameter with a
1885 // generic instance. They may become equal unless
1886 // the type parameter appears anywhere in the
1887 // generic instance:
1889 // class X<T,U> : I<T>, I<X<U>>
1890 // -> error because you could instanciate it as
1893 // class X<T> : I<T>, I<X<T>> -> ok
1896 Type[] bargs = GetTypeArguments (b);
1897 for (int i = 0; i < bargs.Length; i++) {
1898 if (a.Equals (bargs [i]))
1905 if (b.IsGenericParameter)
1906 return MayBecomeEqualGenericTypes (b, a);
1909 // At this point, neither a nor b are a type parameter.
1911 // If one of them is a generic instance, let
1912 // MayBecomeEqualGenericInstances() compare them (if the
1913 // other one is not a generic instance, they can never
1917 if (a.IsGenericInstance || b.IsGenericInstance)
1918 return MayBecomeEqualGenericInstances (a, b);
1921 // If both of them are arrays.
1924 if (a.IsArray && b.IsArray) {
1925 if (a.GetArrayRank () != b.GetArrayRank ())
1928 a = a.GetElementType ();
1929 b = b.GetElementType ();
1931 return MayBecomeEqualGenericTypes (a, b);
1935 // Ok, two ordinary types.
1938 return a.Equals (b);
1942 // Checks whether two generic instances may become equal for some
1943 // particular instantiation (26.3.1).
1945 public static bool MayBecomeEqualGenericInstances (Type a, Type b)
1947 if (!a.IsGenericInstance || !b.IsGenericInstance)
1949 if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ())
1952 Type[] aargs = GetTypeArguments (a);
1953 Type[] bargs = GetTypeArguments (b);
1955 if (aargs.Length != bargs.Length)
1958 for (int i = 0; i < aargs.Length; i++) {
1959 if (MayBecomeEqualGenericTypes (aargs [i], bargs [i]))
1966 public static bool IsEqualGenericInstance (Type type, Type parent)
1968 int tcount = GetNumberOfTypeArguments (type);
1969 int pcount = GetNumberOfTypeArguments (parent);
1971 if (type.IsGenericInstance)
1972 type = type.GetGenericTypeDefinition ();
1973 if (parent.IsGenericInstance)
1974 parent = parent.GetGenericTypeDefinition ();
1976 if (tcount != pcount)
1979 return type.Equals (parent);
1982 public static bool IsSubclassOf (Type type, Type parent)
1984 TypeParameter tparam = LookupTypeParameter (type);
1985 TypeParameter pparam = LookupTypeParameter (parent);
1987 if ((tparam != null) && (pparam != null)) {
1988 if (tparam == pparam)
1991 return tparam.IsSubclassOf (parent);
1995 if (type.Equals (parent))
1998 type = type.BaseType;
1999 } while (type != null);
2004 public static bool IsPrivateAccessible (Type type, Type parent)
2006 if (type.Equals (parent))
2009 if ((type is TypeBuilder) && type.IsGenericTypeDefinition && parent.IsGenericInstance) {
2011 // `a' is a generic type definition's TypeBuilder and `b' is a
2012 // generic instance of the same type.
2018 // void Test (Stack<T> stack) { }
2021 // The first argument of `Test' will be the generic instance
2022 // "Stack<!0>" - which is the same type than the "Stack" TypeBuilder.
2025 // We hit this via Closure.Filter() for gen-82.cs.
2027 if (type != parent.GetGenericTypeDefinition ())
2033 if (type.IsGenericInstance && parent.IsGenericInstance) {
2034 Type tdef = type.GetGenericTypeDefinition ();
2035 Type pdef = parent.GetGenericTypeDefinition ();
2037 if (type.GetGenericTypeDefinition () != parent.GetGenericTypeDefinition ())
2046 public static bool IsFamilyAccessible (Type type, Type parent)
2048 TypeParameter tparam = LookupTypeParameter (type);
2049 TypeParameter pparam = LookupTypeParameter (parent);
2051 if ((tparam != null) && (pparam != null)) {
2052 if (tparam == pparam)
2055 return tparam.IsSubclassOf (parent);
2059 if (IsEqualGenericInstance (type, parent))
2062 type = type.BaseType;
2063 } while (type != null);
2069 // Checks whether `type' is a subclass or nested child of `parent'.
2071 public static bool IsNestedFamilyAccessible (Type type, Type parent)
2074 if (IsFamilyAccessible (type, parent))
2077 // Handle nested types.
2078 type = type.DeclaringType;
2079 } while (type != null);
2085 // Checks whether `type' is a nested child of `parent'.
2087 public static bool IsNestedChildOf (Type type, Type parent)
2089 if (IsEqual (type, parent))
2092 type = type.DeclaringType;
2093 while (type != null) {
2094 if (IsEqual (type, parent))
2097 type = type.DeclaringType;
2104 // Do the right thing when returning the element type of an
2105 // array type based on whether we are compiling corlib or not
2107 public static Type GetElementType (Type t)
2109 if (RootContext.StdLib)
2110 return t.GetElementType ();
2112 return TypeToCoreType (t.GetElementType ());
2116 /// Returns the User Defined Types
2118 public static ArrayList UserTypes {
2124 public static Hashtable TypeContainers {
2126 return typecontainers;
2130 static Hashtable builder_to_constant;
2132 public static void RegisterConstant (FieldBuilder fb, Const c)
2134 if (builder_to_constant == null)
2135 builder_to_constant = new PtrHashtable ();
2137 if (builder_to_constant.Contains (fb))
2140 builder_to_constant.Add (fb, c);
2143 public static Const LookupConstant (FieldBuilder fb)
2145 if (builder_to_constant == null)
2148 return (Const) builder_to_constant [fb];
2152 /// Gigantic work around for missing features in System.Reflection.Emit follows.
2156 /// Since System.Reflection.Emit can not return MethodBase.GetParameters
2157 /// for anything which is dynamic, and we need this in a number of places,
2158 /// we register this information here, and use it afterwards.
2160 static public void RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
2165 method_arguments.Add (mb, args);
2166 method_internal_params.Add (mb, ip);
2169 static public InternalParameters LookupParametersByBuilder (MethodBase mb)
2171 if (! (mb is ConstructorBuilder || mb is MethodBuilder))
2174 if (method_internal_params.Contains (mb))
2175 return (InternalParameters) method_internal_params [mb];
2177 throw new Exception ("Argument for Method not registered" + mb);
2181 /// Returns the argument types for a method based on its methodbase
2183 /// For dynamic methods, we use the compiler provided types, for
2184 /// methods from existing assemblies we load them from GetParameters,
2185 /// and insert them into the cache
2187 static public Type [] GetArgumentTypes (MethodBase mb)
2189 object t = method_arguments [mb];
2193 ParameterInfo [] pi = mb.GetParameters ();
2200 types = new Type [c];
2201 for (int i = 0; i < c; i++)
2202 types [i] = pi [i].ParameterType;
2204 method_arguments.Add (mb, types);
2209 /// Returns the argument types for an indexer based on its PropertyInfo
2211 /// For dynamic indexers, we use the compiler provided types, for
2212 /// indexers from existing assemblies we load them from GetParameters,
2213 /// and insert them into the cache
2215 static public Type [] GetArgumentTypes (PropertyInfo indexer)
2217 if (indexer_arguments.Contains (indexer))
2218 return (Type []) indexer_arguments [indexer];
2219 else if (indexer is PropertyBuilder)
2220 // If we're a PropertyBuilder and not in the
2221 // `indexer_arguments' hash, then we're a property and
2225 ParameterInfo [] pi = indexer.GetIndexParameters ();
2226 // Property, not an indexer.
2230 Type [] types = new Type [c];
2232 for (int i = 0; i < c; i++)
2233 types [i] = pi [i].ParameterType;
2235 indexer_arguments.Add (indexer, types);
2241 // This is a workaround the fact that GetValue is not
2242 // supported for dynamic types
2244 static Hashtable fields = new Hashtable ();
2245 static public bool RegisterFieldValue (FieldBuilder fb, object value)
2247 if (fields.Contains (fb))
2250 fields.Add (fb, value);
2255 static public object GetValue (FieldBuilder fb)
2260 static Hashtable fieldbuilders_to_fields = new Hashtable ();
2261 static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f)
2263 if (fieldbuilders_to_fields.Contains (fb))
2266 fieldbuilders_to_fields.Add (fb, f);
2271 // The return value can be null; This will be the case for
2272 // auxiliary FieldBuilders created by the compiler that have no
2273 // real field being declared on the source code
2275 static public FieldBase GetField (FieldInfo fb)
2277 return (FieldBase) fieldbuilders_to_fields [fb];
2280 static Hashtable events;
2282 static public void RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove)
2285 events = new Hashtable ();
2287 if (!events.Contains (eb)) {
2288 events.Add (eb, new Pair (add, remove));
2292 static public MethodInfo GetAddMethod (EventInfo ei)
2294 if (ei is MyEventBuilder) {
2295 Pair pair = (Pair) events [ei];
2297 return (MethodInfo) pair.First;
2299 return ei.GetAddMethod (true);
2302 static public MethodInfo GetRemoveMethod (EventInfo ei)
2304 if (ei is MyEventBuilder) {
2305 Pair pair = (Pair) events [ei];
2307 return (MethodInfo) pair.Second;
2309 return ei.GetRemoveMethod (true);
2312 static Hashtable priv_fields_events;
2314 static public bool RegisterPrivateFieldOfEvent (EventInfo einfo, FieldBuilder builder)
2316 if (priv_fields_events == null)
2317 priv_fields_events = new Hashtable ();
2319 if (priv_fields_events.Contains (einfo))
2322 priv_fields_events.Add (einfo, builder);
2327 static public MemberInfo GetPrivateFieldOfEvent (EventInfo ei)
2329 if (priv_fields_events == null)
2332 return (MemberInfo) priv_fields_events [ei];
2335 static Hashtable properties;
2337 static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set)
2339 if (properties == null)
2340 properties = new Hashtable ();
2342 if (properties.Contains (pb))
2345 properties.Add (pb, new Pair (get, set));
2350 static public bool RegisterIndexer (PropertyBuilder pb, MethodBase get,
2351 MethodBase set, Type[] args)
2353 if (!RegisterProperty (pb, get,set))
2356 indexer_arguments.Add (pb, args);
2361 public static bool CheckStructCycles (TypeContainer tc, Hashtable seen)
2363 Hashtable hash = new Hashtable ();
2364 return CheckStructCycles (tc, seen, hash);
2367 public static bool CheckStructCycles (TypeContainer tc, Hashtable seen,
2370 if ((tc.Kind != Kind.Struct) || IsBuiltinType (tc))
2374 // `seen' contains all types we've already visited.
2376 if (seen.Contains (tc))
2378 seen.Add (tc, null);
2380 if (tc.Fields == null)
2383 foreach (Field field in tc.Fields) {
2384 if (field.FieldBuilder.IsStatic)
2387 Type ftype = field.FieldBuilder.FieldType;
2388 TypeContainer ftc = LookupTypeContainer (ftype);
2392 if (hash.Contains (ftc)) {
2393 Report.Error (523, tc.Location,
2394 "Struct member `{0}.{1}' of type `{2}' " +
2395 "causes a cycle in the struct layout",
2396 tc.Name, field.Name, ftc.Name);
2401 // `hash' contains all types in the current path.
2403 hash.Add (tc, null);
2405 bool ok = CheckStructCycles (ftc, seen, hash);
2412 if (!seen.Contains (ftc))
2413 seen.Add (ftc, null);
2420 /// Given an array of interface types, expand and eliminate repeated ocurrences
2421 /// of an interface.
2425 /// This expands in context like: IA; IB : IA; IC : IA, IB; the interface "IC" to
2428 public static Type[] ExpandInterfaces (EmitContext ec, TypeExpr [] base_interfaces)
2430 ArrayList new_ifaces = new ArrayList ();
2432 foreach (TypeExpr iface in base_interfaces){
2433 TypeExpr texpr = iface.ResolveAsTypeTerminal (ec);
2437 if (!new_ifaces.Contains (texpr.Type))
2438 new_ifaces.Add (texpr.Type);
2440 Type [] implementing = texpr.Type.GetInterfaces ();
2442 foreach (Type imp in implementing){
2443 if (!new_ifaces.Contains (imp))
2444 new_ifaces.Add (imp);
2447 Type [] ret = new Type [new_ifaces.Count];
2448 new_ifaces.CopyTo (ret, 0);
2452 static PtrHashtable iface_cache = new PtrHashtable ();
2455 /// This function returns the interfaces in the type `t'. Works with
2456 /// both types and TypeBuilders.
2458 public static Type [] GetInterfaces (Type t)
2461 Type [] cached = iface_cache [t] as Type [];
2466 // The reason for catching the Array case is that Reflection.Emit
2467 // will not return a TypeBuilder for Array types of TypeBuilder types,
2468 // but will still throw an exception if we try to call GetInterfaces
2471 // Since the array interfaces are always constant, we return those for
2476 t = TypeManager.array_type;
2478 if (t is TypeBuilder){
2479 Type[] parent_ifaces;
2481 if (t.BaseType == null)
2482 parent_ifaces = NoTypes;
2484 parent_ifaces = GetInterfaces (t.BaseType);
2485 Type[] type_ifaces = (Type []) builder_to_ifaces [t];
2486 if (type_ifaces == null)
2487 type_ifaces = NoTypes;
2489 int parent_count = parent_ifaces.Length;
2490 Type[] result = new Type [parent_count + type_ifaces.Length];
2491 parent_ifaces.CopyTo (result, 0);
2492 type_ifaces.CopyTo (result, parent_count);
2494 iface_cache [t] = result;
2496 } else if (t is GenericTypeParameterBuilder){
2497 Type[] type_ifaces = (Type []) builder_to_ifaces [t];
2498 if (type_ifaces == null)
2499 type_ifaces = NoTypes;
2501 iface_cache [t] = type_ifaces;
2504 Type[] ifaces = t.GetInterfaces ();
2505 iface_cache [t] = ifaces;
2511 // gets the interfaces that are declared explicitly on t
2513 public static Type [] GetExplicitInterfaces (TypeBuilder t)
2515 return (Type []) builder_to_ifaces [t];
2519 /// The following is used to check if a given type implements an interface.
2520 /// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime.
2522 public static bool ImplementsInterface (Type t, Type iface)
2527 // FIXME OPTIMIZATION:
2528 // as soon as we hit a non-TypeBuiler in the interface
2529 // chain, we could return, as the `Type.GetInterfaces'
2530 // will return all the interfaces implement by the type
2534 interfaces = GetInterfaces (t);
2536 if (interfaces != null){
2537 foreach (Type i in interfaces){
2544 } while (t != null);
2549 static NumberFormatInfo nf_provider = CultureInfo.CurrentCulture.NumberFormat;
2551 // This is a custom version of Convert.ChangeType() which works
2552 // with the TypeBuilder defined types when compiling corlib.
2553 public static object ChangeType (object value, Type conversionType, out bool error)
2555 IConvertible convert_value = value as IConvertible;
2557 if (convert_value == null){
2563 // We must use Type.Equals() here since `conversionType' is
2564 // the TypeBuilder created version of a system type and not
2565 // the system type itself. You cannot use Type.GetTypeCode()
2566 // on such a type - it'd always return TypeCode.Object.
2570 if (conversionType.Equals (typeof (Boolean)))
2571 return (object)(convert_value.ToBoolean (nf_provider));
2572 else if (conversionType.Equals (typeof (Byte)))
2573 return (object)(convert_value.ToByte (nf_provider));
2574 else if (conversionType.Equals (typeof (Char)))
2575 return (object)(convert_value.ToChar (nf_provider));
2576 else if (conversionType.Equals (typeof (DateTime)))
2577 return (object)(convert_value.ToDateTime (nf_provider));
2578 else if (conversionType.Equals (TypeManager.decimal_type)) // typeof (Decimal)))
2579 return (object)(convert_value.ToDecimal (nf_provider));
2580 else if (conversionType.Equals (typeof (Double)))
2581 return (object)(convert_value.ToDouble (nf_provider));
2582 else if (conversionType.Equals (typeof (Int16)))
2583 return (object)(convert_value.ToInt16 (nf_provider));
2584 else if (conversionType.Equals (typeof (Int32)))
2585 return (object)(convert_value.ToInt32 (nf_provider));
2586 else if (conversionType.Equals (typeof (Int64)))
2587 return (object)(convert_value.ToInt64 (nf_provider));
2588 else if (conversionType.Equals (typeof (SByte)))
2589 return (object)(convert_value.ToSByte (nf_provider));
2590 else if (conversionType.Equals (typeof (Single)))
2591 return (object)(convert_value.ToSingle (nf_provider));
2592 else if (conversionType.Equals (typeof (String)))
2593 return (object)(convert_value.ToString (nf_provider));
2594 else if (conversionType.Equals (typeof (UInt16)))
2595 return (object)(convert_value.ToUInt16 (nf_provider));
2596 else if (conversionType.Equals (typeof (UInt32)))
2597 return (object)(convert_value.ToUInt32 (nf_provider));
2598 else if (conversionType.Equals (typeof (UInt64)))
2599 return (object)(convert_value.ToUInt64 (nf_provider));
2600 else if (conversionType.Equals (typeof (Object)))
2601 return (object)(value);
2611 // This is needed, because enumerations from assemblies
2612 // do not report their underlyingtype, but they report
2615 public static Type EnumToUnderlying (Type t)
2617 if (t == TypeManager.enum_type)
2620 t = t.UnderlyingSystemType;
2621 if (!TypeManager.IsEnumType (t))
2624 if (t is TypeBuilder) {
2625 // slow path needed to compile corlib
2626 if (t == TypeManager.bool_type ||
2627 t == TypeManager.byte_type ||
2628 t == TypeManager.sbyte_type ||
2629 t == TypeManager.char_type ||
2630 t == TypeManager.short_type ||
2631 t == TypeManager.ushort_type ||
2632 t == TypeManager.int32_type ||
2633 t == TypeManager.uint32_type ||
2634 t == TypeManager.int64_type ||
2635 t == TypeManager.uint64_type)
2637 throw new Exception ("Unhandled typecode in enum " + " from " + t.AssemblyQualifiedName);
2639 TypeCode tc = Type.GetTypeCode (t);
2642 case TypeCode.Boolean:
2643 return TypeManager.bool_type;
2645 return TypeManager.byte_type;
2646 case TypeCode.SByte:
2647 return TypeManager.sbyte_type;
2649 return TypeManager.char_type;
2650 case TypeCode.Int16:
2651 return TypeManager.short_type;
2652 case TypeCode.UInt16:
2653 return TypeManager.ushort_type;
2654 case TypeCode.Int32:
2655 return TypeManager.int32_type;
2656 case TypeCode.UInt32:
2657 return TypeManager.uint32_type;
2658 case TypeCode.Int64:
2659 return TypeManager.int64_type;
2660 case TypeCode.UInt64:
2661 return TypeManager.uint64_type;
2663 throw new Exception ("Unhandled typecode in enum " + tc + " from " + t.AssemblyQualifiedName);
2667 // When compiling corlib and called with one of the core types, return
2668 // the corresponding typebuilder for that type.
2670 public static Type TypeToCoreType (Type t)
2672 if (RootContext.StdLib || (t is TypeBuilder))
2675 TypeCode tc = Type.GetTypeCode (t);
2678 case TypeCode.Boolean:
2679 return TypeManager.bool_type;
2681 return TypeManager.byte_type;
2682 case TypeCode.SByte:
2683 return TypeManager.sbyte_type;
2685 return TypeManager.char_type;
2686 case TypeCode.Int16:
2687 return TypeManager.short_type;
2688 case TypeCode.UInt16:
2689 return TypeManager.ushort_type;
2690 case TypeCode.Int32:
2691 return TypeManager.int32_type;
2692 case TypeCode.UInt32:
2693 return TypeManager.uint32_type;
2694 case TypeCode.Int64:
2695 return TypeManager.int64_type;
2696 case TypeCode.UInt64:
2697 return TypeManager.uint64_type;
2698 case TypeCode.Single:
2699 return TypeManager.float_type;
2700 case TypeCode.Double:
2701 return TypeManager.double_type;
2702 case TypeCode.String:
2703 return TypeManager.string_type;
2704 case TypeCode.Decimal:
2705 return TypeManager.decimal_type;
2707 if (t == typeof (void))
2708 return TypeManager.void_type;
2709 if (t == typeof (object))
2710 return TypeManager.object_type;
2711 if (t == typeof (System.Type))
2712 return TypeManager.type_type;
2713 if (t == typeof (System.IntPtr))
2714 return TypeManager.intptr_type;
2720 /// Utility function that can be used to probe whether a type
2721 /// is managed or not.
2723 public static bool VerifyUnManaged (Type t, Location loc)
2725 if (t.IsValueType || t.IsPointer){
2727 // FIXME: this is more complex, we actually need to
2728 // make sure that the type does not contain any
2734 if (!RootContext.StdLib && (t == TypeManager.decimal_type))
2735 // We need this explicit check here to make it work when
2736 // compiling corlib.
2741 "Cannot take the address or size of a variable of a managed type ('" +
2742 CSharpName (t) + "')");
2747 /// Returns the name of the indexer in a given type.
2750 /// The default is not always `Item'. The user can change this behaviour by
2751 /// using the IndexerNameAttribute in the container.
2753 /// For example, the String class indexer is named `Chars' not `Item'
2755 public static string IndexerPropertyName (Type t)
2757 if (t.IsGenericInstance)
2758 t = t.GetGenericTypeDefinition ();
2760 if (t is TypeBuilder) {
2761 TypeContainer tc = t.IsInterface ? LookupInterface (t) : LookupTypeContainer (t);
2762 return tc == null ? TypeContainer.DefaultIndexerName : tc.IndexerName;
2765 System.Attribute attr = System.Attribute.GetCustomAttribute (
2766 t, TypeManager.default_member_type);
2768 DefaultMemberAttribute dma = (DefaultMemberAttribute) attr;
2769 return dma.MemberName;
2772 return TypeContainer.DefaultIndexerName;
2775 static MethodInfo declare_local_method = null;
2777 public static LocalBuilder DeclareLocalPinned (ILGenerator ig, Type t)
2779 if (declare_local_method == null){
2780 declare_local_method = typeof (ILGenerator).GetMethod (
2782 BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
2784 new Type [] { typeof (Type), typeof (bool)},
2786 if (declare_local_method == null){
2787 Report.Warning (-24, new Location (-1),
2788 "This version of the runtime does not support making pinned local variables. " +
2789 "This code may cause errors on a runtime with a moving GC");
2790 return ig.DeclareLocal (t);
2793 return (LocalBuilder) declare_local_method.Invoke (ig, new object [] { t, true });
2797 // Returns whether the array of memberinfos contains the given method
2799 public static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method)
2801 Type [] new_args = TypeManager.GetArgumentTypes (new_method);
2803 foreach (MethodBase method in array) {
2804 if (method.Name != new_method.Name)
2807 if (method is MethodInfo && new_method is MethodInfo)
2808 if (((MethodInfo) method).ReturnType != ((MethodInfo) new_method).ReturnType)
2812 Type [] old_args = TypeManager.GetArgumentTypes (method);
2813 int old_count = old_args.Length;
2816 if (new_args.Length != old_count)
2819 for (i = 0; i < old_count; i++){
2820 if (old_args [i] != new_args [i])
2833 // We copy methods from `new_members' into `target_list' if the signature
2834 // for the method from in the new list does not exist in the target_list
2836 // The name is assumed to be the same.
2838 public static ArrayList CopyNewMethods (ArrayList target_list, IList new_members)
2840 if (target_list == null){
2841 target_list = new ArrayList ();
2843 foreach (MemberInfo mi in new_members){
2844 if (mi is MethodBase)
2845 target_list.Add (mi);
2850 MemberInfo [] target_array = new MemberInfo [target_list.Count];
2851 target_list.CopyTo (target_array, 0);
2853 foreach (MemberInfo mi in new_members){
2854 MethodBase new_method = (MethodBase) mi;
2856 if (!ArrayContainsMethod (target_array, new_method))
2857 target_list.Add (new_method);
2862 static public bool IsGenericMethod (MethodBase mb)
2864 if (mb.DeclaringType is TypeBuilder) {
2865 IMethodData method = (IMethodData) builder_to_method [mb];
2869 return method.GenericMethod != null;
2872 return mb.IsGenericMethodDefinition;
2875 #region MemberLookup implementation
2878 // Whether we allow private members in the result (since FindMembers
2879 // uses NonPublic for both protected and private), we need to distinguish.
2882 static internal bool FilterNone (MemberInfo m, object filter_criteria)
2887 internal class Closure {
2888 internal bool private_ok;
2890 // Who is invoking us and which type is being queried currently.
2891 internal Type invocation_type;
2892 internal Type qualifier_type;
2894 // The assembly that defines the type is that is calling us
2895 internal Assembly invocation_assembly;
2896 internal IList almost_match;
2898 private bool CheckValidFamilyAccess (bool is_static, MemberInfo m)
2900 if (invocation_type == null)
2906 // A nested class has access to all the protected members visible
2908 if (qualifier_type != null
2909 && TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2912 if (invocation_type == m.DeclaringType
2913 || invocation_type.IsSubclassOf (m.DeclaringType)) {
2914 // Although a derived class can access protected members of
2915 // its base class it cannot do so through an instance of the
2916 // base class (CS1540).
2917 // => Ancestry should be: declaring_type ->* invocation_type
2918 // ->* qualified_type
2919 if (qualifier_type == null
2920 || qualifier_type == invocation_type
2921 || qualifier_type.IsSubclassOf (invocation_type))
2925 if (almost_match != null)
2926 almost_match.Add (m);
2930 bool Filter (MethodBase mb, object filter_criteria)
2932 MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask;
2934 if (ma == MethodAttributes.Private)
2935 return private_ok ||
2936 IsPrivateAccessible (invocation_type, mb.DeclaringType) ||
2937 IsNestedChildOf (invocation_type, mb.DeclaringType);
2940 // FamAndAssem requires that we not only derivate, but we are on the
2943 if (ma == MethodAttributes.FamANDAssem){
2944 if (invocation_assembly != mb.DeclaringType.Assembly)
2948 // Assembly and FamORAssem succeed if we're in the same assembly.
2949 if ((ma == MethodAttributes.Assembly) || (ma == MethodAttributes.FamORAssem)){
2950 if (invocation_assembly == mb.DeclaringType.Assembly)
2954 // We already know that we aren't in the same assembly.
2955 if (ma == MethodAttributes.Assembly)
2958 // Family and FamANDAssem require that we derive.
2959 if ((ma == MethodAttributes.Family) || (ma == MethodAttributes.FamANDAssem)){
2960 if (invocation_type == null)
2963 if (!IsNestedFamilyAccessible (invocation_type, mb.DeclaringType))
2966 // Although a derived class can access protected members of its base class
2967 // it cannot do so through an instance of the base class (CS1540).
2968 if (!mb.IsStatic && (qualifier_type != null) &&
2969 !IsEqualGenericInstance (invocation_type, qualifier_type) &&
2970 TypeManager.IsFamilyAccessible (invocation_type, qualifier_type) &&
2971 !TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
2981 bool Filter (FieldInfo fi, object filter_criteria)
2983 FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask;
2985 if (fa == FieldAttributes.Private)
2986 return private_ok ||
2987 IsPrivateAccessible (invocation_type, fi.DeclaringType) ||
2988 IsNestedChildOf (invocation_type, fi.DeclaringType);
2991 // FamAndAssem requires that we not only derivate, but we are on the
2994 if (fa == FieldAttributes.FamANDAssem){
2995 if (invocation_assembly != fi.DeclaringType.Assembly)
2999 // Assembly and FamORAssem succeed if we're in the same assembly.
3000 if ((fa == FieldAttributes.Assembly) || (fa == FieldAttributes.FamORAssem)){
3001 if (invocation_assembly == fi.DeclaringType.Assembly)
3005 // We already know that we aren't in the same assembly.
3006 if (fa == FieldAttributes.Assembly)
3009 // Family and FamANDAssem require that we derive.
3010 if ((fa == FieldAttributes.Family) || (fa == FieldAttributes.FamANDAssem)){
3011 if (invocation_type == null)
3014 if (!IsNestedFamilyAccessible (invocation_type, fi.DeclaringType))
3017 // Although a derived class can access protected members of its base class
3018 // it cannot do so through an instance of the base class (CS1540).
3019 if (!fi.IsStatic && (qualifier_type != null) &&
3020 !IsEqualGenericInstance (invocation_type, qualifier_type) &&
3021 TypeManager.IsFamilyAccessible (invocation_type, qualifier_type) &&
3022 !TypeManager.IsNestedChildOf (invocation_type, qualifier_type))
3033 // This filter filters by name + whether it is ok to include private
3034 // members in the search
3036 internal bool Filter (MemberInfo m, object filter_criteria)
3039 // Hack: we know that the filter criteria will always be in the
3040 // `closure' // fields.
3043 if ((filter_criteria != null) && (m.Name != (string) filter_criteria))
3046 if (((qualifier_type == null) || (qualifier_type == invocation_type)) &&
3047 (invocation_type != null) &&
3048 IsPrivateAccessible (m.DeclaringType, invocation_type))
3052 // Ugly: we need to find out the type of `m', and depending
3053 // on this, tell whether we accept or not
3055 if (m is MethodBase)
3056 return Filter ((MethodBase) m, filter_criteria);
3059 return Filter ((FieldInfo) m, filter_criteria);
3062 // EventInfos and PropertyInfos, return true because they lack
3063 // permission information, so we need to check later on the methods.
3069 static Closure closure = new Closure ();
3070 static MemberFilter FilterWithClosure_delegate = new MemberFilter (closure.Filter);
3073 // Looks up a member called `name' in the `queried_type'. This lookup
3074 // is done by code that is contained in the definition for `invocation_type'
3075 // through a qualifier of type `qualifier_type' (or null if there is no qualifier).
3077 // `invocation_type' is used to check whether we're allowed to access the requested
3078 // member wrt its protection level.
3080 // When called from MemberAccess, `qualifier_type' is the type which is used to access
3081 // the requested member (`class B { A a = new A (); a.foo = 5; }'; here invocation_type
3082 // is B and qualifier_type is A). This is used to do the CS1540 check.
3084 // When resolving a SimpleName, `qualifier_type' is null.
3086 // The `qualifier_type' is used for the CS1540 check; it's normally either null or
3087 // the same than `queried_type' - except when we're being called from BaseAccess;
3088 // in this case, `invocation_type' is the current type and `queried_type' the base
3089 // type, so this'd normally trigger a CS1540.
3091 // The binding flags are `bf' and the kind of members being looked up are `mt'
3093 // The return value always includes private members which code in `invocation_type'
3094 // is allowed to access (using the specified `qualifier_type' if given); only use
3095 // BindingFlags.NonPublic to bypass the permission check.
3097 // The 'almost_match' argument is used for reporting error CS1540.
3099 // Returns an array of a single element for everything but Methods/Constructors
3100 // that might return multiple matches.
3102 public static MemberInfo [] MemberLookup (Type invocation_type, Type qualifier_type,
3103 Type queried_type, MemberTypes mt,
3104 BindingFlags original_bf, string name, IList almost_match)
3106 Timer.StartTimer (TimerType.MemberLookup);
3108 MemberInfo[] retval = RealMemberLookup (invocation_type, qualifier_type,
3109 queried_type, mt, original_bf, name, almost_match);
3111 Timer.StopTimer (TimerType.MemberLookup);
3116 static MemberInfo [] RealMemberLookup (Type invocation_type, Type qualifier_type,
3117 Type queried_type, MemberTypes mt,
3118 BindingFlags original_bf, string name, IList almost_match)
3120 BindingFlags bf = original_bf;
3122 ArrayList method_list = null;
3123 Type current_type = queried_type;
3124 bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0;
3125 bool skip_iface_check = true, used_cache = false;
3126 bool always_ok_flag = false;
3128 closure.invocation_type = invocation_type;
3129 closure.invocation_assembly = invocation_type != null ? invocation_type.Assembly : null;
3130 closure.qualifier_type = qualifier_type;
3131 closure.almost_match = almost_match;
3134 // If we are a nested class, we always have access to our container
3137 if (invocation_type != null){
3138 string invocation_name = invocation_type.FullName;
3139 if ((invocation_name != null) && (invocation_name.IndexOf ('+') != -1)){
3140 string container = queried_type.FullName + "+";
3141 int container_length = container.Length;
3143 if (invocation_name.Length > container_length){
3144 string shared = invocation_name.Substring (0, container_length);
3146 if (shared == container)
3147 always_ok_flag = true;
3152 // This is from the first time we find a method
3153 // in most cases, we do not actually find a method in the base class
3154 // so we can just ignore it, and save the arraylist allocation
3155 MemberInfo [] first_members_list = null;
3156 bool use_first_members_list = false;
3162 // `NonPublic' is lame, because it includes both protected and
3163 // private methods, so we need to control this behavior by
3164 // explicitly tracking if a private method is ok or not.
3166 // The possible cases are:
3167 // public, private and protected (internal does not come into the
3170 if ((invocation_type != null) &&
3171 ((invocation_type == current_type) ||
3172 IsNestedChildOf (invocation_type, current_type)) ||
3174 bf = original_bf | BindingFlags.NonPublic;
3178 closure.private_ok = (original_bf & BindingFlags.NonPublic) != 0;
3180 Timer.StopTimer (TimerType.MemberLookup);
3182 list = MemberLookup_FindMembers (
3183 current_type, mt, bf, name, out used_cache);
3185 Timer.StartTimer (TimerType.MemberLookup);
3188 // When queried for an interface type, the cache will automatically check all
3189 // inherited members, so we don't need to do this here. However, this only
3190 // works if we already used the cache in the first iteration of this loop.
3192 // If we used the cache in any further iteration, we can still terminate the
3193 // loop since the cache always looks in all parent classes.
3199 skip_iface_check = false;
3201 if (current_type == TypeManager.object_type)
3204 current_type = current_type.BaseType;
3207 // This happens with interfaces, they have a null
3208 // basetype. Look members up in the Object class.
3210 if (current_type == null) {
3211 current_type = TypeManager.object_type;
3216 if (list.Length == 0)
3220 // Events and types are returned by both `static' and `instance'
3221 // searches, which means that our above FindMembers will
3222 // return two copies of the same.
3224 if (list.Length == 1 && !(list [0] is MethodBase)){
3229 // Multiple properties: we query those just to find out the indexer
3232 if (list [0] is PropertyInfo)
3236 // We found an event: the cache lookup returns both the event and
3237 // its private field.
3239 if (list [0] is EventInfo) {
3240 if ((list.Length == 2) && (list [1] is FieldInfo))
3241 return new MemberInfo [] { list [0] };
3248 // We found methods, turn the search into "method scan"
3252 if (first_members_list != null) {
3253 if (use_first_members_list) {
3254 method_list = CopyNewMethods (method_list, first_members_list);
3255 use_first_members_list = false;
3258 method_list = CopyNewMethods (method_list, list);
3260 first_members_list = list;
3261 use_first_members_list = true;
3263 mt &= (MemberTypes.Method | MemberTypes.Constructor);
3265 } while (searching);
3267 if (use_first_members_list) {
3268 foreach (MemberInfo mi in first_members_list) {
3269 if (! (mi is MethodBase)) {
3270 method_list = CopyNewMethods (method_list, first_members_list);
3271 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
3274 return (MemberInfo []) first_members_list;
3277 if (method_list != null && method_list.Count > 0) {
3278 return (MemberInfo []) method_list.ToArray (typeof (MemberInfo));
3281 // This happens if we already used the cache in the first iteration, in this case
3282 // the cache already looked in all interfaces.
3284 if (skip_iface_check)
3288 // Interfaces do not list members they inherit, so we have to
3291 if (!queried_type.IsInterface)
3294 if (queried_type.IsArray)
3295 queried_type = TypeManager.array_type;
3297 Type [] ifaces = GetInterfaces (queried_type);
3301 foreach (Type itype in ifaces){
3304 x = MemberLookup (null, null, itype, mt, bf, name, null);
3312 // Tests whether external method is really special
3313 public static bool IsSpecialMethod (MethodBase mb)
3315 string name = mb.Name;
3316 if (name.StartsWith ("get_") || name.StartsWith ("set_"))
3317 return mb.DeclaringType.GetProperty (name.Substring (4)) != null;
3319 if (name.StartsWith ("add_"))
3320 return mb.DeclaringType.GetEvent (name.Substring (4)) != null;
3322 if (name.StartsWith ("remove_"))
3323 return mb.DeclaringType.GetEvent (name.Substring (7)) != null;
3325 if (name.StartsWith ("op_")){
3326 foreach (string oname in Unary.oper_names) {
3331 foreach (string oname in Binary.oper_names) {
3344 /// There is exactly one instance of this class per type.
3346 public sealed class TypeHandle : IMemberContainer {
3347 public readonly TypeHandle BaseType;
3349 readonly int id = ++next_id;
3350 static int next_id = 0;
3353 /// Lookup a TypeHandle instance for the given type. If the type doesn't have
3354 /// a TypeHandle yet, a new instance of it is created. This static method
3355 /// ensures that we'll only have one TypeHandle instance per type.
3357 private static TypeHandle GetTypeHandle (Type t)
3359 TypeHandle handle = (TypeHandle) type_hash [t];
3363 handle = new TypeHandle (t);
3364 type_hash.Add (t, handle);
3368 public static MemberCache GetMemberCache (Type t)
3370 return GetTypeHandle (t).MemberCache;
3373 public static void CleanUp ()
3379 /// Returns the TypeHandle for TypeManager.object_type.
3381 public static IMemberContainer ObjectType {
3383 if (object_type != null)
3386 object_type = GetTypeHandle (TypeManager.object_type);
3393 /// Returns the TypeHandle for TypeManager.array_type.
3395 public static IMemberContainer ArrayType {
3397 if (array_type != null)
3400 array_type = GetTypeHandle (TypeManager.array_type);
3406 private static PtrHashtable type_hash = new PtrHashtable ();
3408 private static TypeHandle object_type = null;
3409 private static TypeHandle array_type = null;
3412 private string full_name;
3413 private bool is_interface;
3414 private MemberCache member_cache;
3415 private MemberCache parent_cache;
3417 private TypeHandle (Type type)
3420 full_name = type.FullName != null ? type.FullName : type.Name;
3421 if (type.BaseType != null) {
3422 BaseType = GetTypeHandle (type.BaseType);
3423 parent_cache = BaseType.MemberCache;
3424 } else if (type.IsInterface)
3425 parent_cache = TypeManager.LookupParentInterfacesCache (type);
3426 this.is_interface = type.IsInterface || type.IsGenericParameter;
3427 this.member_cache = new MemberCache (this);
3430 // IMemberContainer methods
3432 public string Name {
3444 public MemberCache ParentCache {
3446 return parent_cache;
3450 public bool IsInterface {
3452 return is_interface;
3456 public MemberList GetMembers (MemberTypes mt, BindingFlags bf)
3458 MemberInfo [] members;
3459 if (type is GenericTypeParameterBuilder)
3460 return MemberList.Empty;
3461 if (mt == MemberTypes.Event)
3462 members = type.GetEvents (bf | BindingFlags.DeclaredOnly);
3464 members = type.FindMembers (mt, bf | BindingFlags.DeclaredOnly,
3466 Array.Reverse (members);
3468 return new MemberList (members);
3471 // IMemberFinder methods
3473 public MemberList FindMembers (MemberTypes mt, BindingFlags bf, string name,
3474 MemberFilter filter, object criteria)
3476 return new MemberList (member_cache.FindMembers (mt, bf, name, filter, criteria));
3479 public MemberCache MemberCache {
3481 return member_cache;
3485 public override string ToString ()
3487 if (BaseType != null)
3488 return "TypeHandle (" + id + "," + Name + " : " + BaseType + ")";
3490 return "TypeHandle (" + id + "," + Name + ")";