// // typemanager.cs: C# type manager // // Author: Miguel de Icaza (miguel@gnu.org) // Ravi Pratap (ravi@ximian.com) // Marek Safar (marek.safar@seznam.cz) // // Dual licensed under the terms of the MIT X11 or GNU GPL // // Copyright 2001-2003 Ximian, Inc (http://www.ximian.com) // Copyright 2003-2008 Novell, Inc. // // // We will eventually remove the SIMPLE_SPEEDUP, and should never change // the behavior of the compilation. This can be removed if we rework // the code to get a list of namespaces available. // #define SIMPLE_SPEEDUP using System; using System.IO; using System.Globalization; using System.Collections; using System.Reflection; using System.Reflection.Emit; using System.Text; using System.Runtime.CompilerServices; using System.Diagnostics; namespace Mono.CSharp { partial class TypeManager { // // A list of core types that the compiler requires or uses // static public Type object_type; static public Type value_type; static public Type string_type; static public Type int32_type; static public Type uint32_type; static public Type int64_type; static public Type uint64_type; static public Type float_type; static public Type double_type; static public Type char_type; static public Type short_type; static public Type decimal_type; static public Type bool_type; static public Type sbyte_type; static public Type byte_type; static public Type ushort_type; static public Type enum_type; static public Type delegate_type; static public Type multicast_delegate_type; static public Type void_type; static public Type null_type; static public Type array_type; static public Type runtime_handle_type; static public Type type_type; static public Type ienumerator_type; static public Type ienumerable_type; static public Type idisposable_type; static public Type iasyncresult_type; static public Type asynccallback_type; static public Type intptr_type; static public Type uintptr_type; static public Type runtime_field_handle_type; static public Type runtime_argument_handle_type; static public Type attribute_type; static public Type void_ptr_type; static public Type exception_type; static public Type typed_reference_type; static public Type arg_iterator_type; static public Type mbr_type; public static Type runtime_helpers_type; // // C# 2.0 // static internal Type isvolatile_type; static public Type generic_ilist_type; static public Type generic_icollection_type; static public Type generic_ienumerator_type; static public Type generic_ienumerable_type; static public Type generic_nullable_type; // // C# 3.0 // static internal Type expression_type; public static Type parameter_expression_type; public static Type fieldinfo_type; public static Type methodinfo_type; public static Type ctorinfo_type; // // C# 4.0 // public static Type call_site_type; public static Type generic_call_site_type; // // Expressions representing the internal types. Used during declaration // definition. // static public TypeExpr system_object_expr, system_string_expr; static public TypeExpr system_boolean_expr, system_decimal_expr; static public TypeExpr system_single_expr, system_double_expr; static public TypeExpr system_sbyte_expr, system_byte_expr; static public TypeExpr system_int16_expr, system_uint16_expr; static public TypeExpr system_int32_expr, system_uint32_expr; static public TypeExpr system_int64_expr, system_uint64_expr; static public TypeExpr system_char_expr, system_void_expr; static public TypeExpr system_valuetype_expr; static public TypeExpr system_intptr_expr; public static TypeExpr expression_type_expr; // // These methods are called by code generated by the compiler // static public FieldInfo string_empty; static public MethodInfo system_type_get_type_from_handle; static public MethodInfo bool_movenext_void; static public MethodInfo void_dispose_void; static public MethodInfo void_monitor_enter_object; static public MethodInfo void_monitor_exit_object; static public MethodInfo void_initializearray_array_fieldhandle; static public MethodInfo delegate_combine_delegate_delegate; static public MethodInfo delegate_remove_delegate_delegate; static public PropertyInfo int_get_offset_to_string_data; static public MethodInfo int_interlocked_compare_exchange; static public PropertyInfo ienumerator_getcurrent; public static MethodInfo methodbase_get_type_from_handle; public static MethodInfo methodbase_get_type_from_handle_generic; public static MethodInfo fieldinfo_get_field_from_handle; public static MethodInfo fieldinfo_get_field_from_handle_generic; static public MethodInfo activator_create_instance; // // The constructors. // static public ConstructorInfo void_decimal_ctor_five_args; static public ConstructorInfo void_decimal_ctor_int_arg; static PtrHashtable builder_to_declspace; static PtrHashtable builder_to_member_cache; // // Tracks the interfaces implemented by typebuilders. We only // enter those who do implement or or more interfaces // static PtrHashtable builder_to_ifaces; // // Maps a MethodBase to its ParameterData (either InternalParameters or ReflectionParameters) // static Hashtable method_params; // // A hash table from override methods to their base virtual method. // static Hashtable method_overrides; // // Keeps track of methods // static Hashtable builder_to_method; // // Contains all public types from referenced assemblies. // This member is used only if CLS Compliance verification is required. // public static Hashtable AllClsTopLevelTypes; static Hashtable fieldbuilders_to_fields; static Hashtable propertybuilder_to_property; static Hashtable fields; static Hashtable events; static PtrHashtable assembly_internals_vis_attrs; public static void CleanUp () { // Lets get everything clean so that we can collect before generating code builder_to_declspace = null; builder_to_member_cache = null; builder_to_ifaces = null; builder_to_type_param = null; method_params = null; builder_to_method = null; fields = null; events = null; type_hash = null; propertybuilder_to_property = null; TypeHandle.CleanUp (); } // // These are expressions that represent some of the internal data types, used // elsewhere // static void InitExpressionTypes () { system_object_expr = new TypeLookupExpression ("System", "Object"); system_string_expr = new TypeLookupExpression ("System", "String"); system_boolean_expr = new TypeLookupExpression ("System", "Boolean"); system_decimal_expr = new TypeLookupExpression ("System", "Decimal"); system_single_expr = new TypeLookupExpression ("System", "Single"); system_double_expr = new TypeLookupExpression ("System", "Double"); system_sbyte_expr = new TypeLookupExpression ("System", "SByte"); system_byte_expr = new TypeLookupExpression ("System", "Byte"); system_int16_expr = new TypeLookupExpression ("System", "Int16"); system_uint16_expr = new TypeLookupExpression ("System", "UInt16"); system_int32_expr = new TypeLookupExpression ("System", "Int32"); system_uint32_expr = new TypeLookupExpression ("System", "UInt32"); system_int64_expr = new TypeLookupExpression ("System", "Int64"); system_uint64_expr = new TypeLookupExpression ("System", "UInt64"); system_char_expr = new TypeLookupExpression ("System", "Char"); system_void_expr = new TypeLookupExpression ("System", "Void"); system_valuetype_expr = new TypeLookupExpression ("System", "ValueType"); system_intptr_expr = new TypeLookupExpression ("System", "IntPtr"); } static TypeManager () { Reset (); } static public void Reset () { InitExpressionTypes (); builder_to_declspace = new PtrHashtable (); builder_to_member_cache = new PtrHashtable (); builder_to_method = new PtrHashtable (); builder_to_type_param = new PtrHashtable (); method_params = new PtrHashtable (); method_overrides = new PtrHashtable (); builder_to_ifaces = new PtrHashtable (); fieldbuilders_to_fields = new Hashtable (); propertybuilder_to_property = new Hashtable (); fields = new Hashtable (); type_hash = new DoubleHash (); assembly_internals_vis_attrs = new PtrHashtable (); iface_cache = new PtrHashtable (); closure = new Closure (); FilterWithClosure_delegate = new MemberFilter (closure.Filter); // TODO: I am really bored by all this static stuff system_type_get_type_from_handle = bool_movenext_void = void_dispose_void = void_monitor_enter_object = void_monitor_exit_object = void_initializearray_array_fieldhandle = delegate_combine_delegate_delegate = delegate_remove_delegate_delegate = int_interlocked_compare_exchange = methodbase_get_type_from_handle = methodbase_get_type_from_handle_generic = fieldinfo_get_field_from_handle = fieldinfo_get_field_from_handle_generic = activator_create_instance = null; int_get_offset_to_string_data = ienumerator_getcurrent = null; void_decimal_ctor_five_args = void_decimal_ctor_int_arg = null; isvolatile_type = null; // to uncover regressions AllClsTopLevelTypes = null; } public static void AddUserType (DeclSpace ds) { builder_to_declspace.Add (ds.TypeBuilder, ds); } // // This entry point is used by types that we define under the covers // public static void RegisterBuilder (Type tb, Type [] ifaces) { if (ifaces != null) builder_to_ifaces [tb] = ifaces; } public static void AddMethod (MethodBase builder, IMethodData method) { builder_to_method.Add (builder, method); method_params.Add (builder, method.ParameterInfo); } public static IMethodData GetMethod (MethodBase builder) { return (IMethodData) builder_to_method [builder]; } /// /// Returns the DeclSpace whose Type is `t' or null if there is no /// DeclSpace for `t' (ie, the Type comes from a library) /// public static DeclSpace LookupDeclSpace (Type t) { return builder_to_declspace [t] as DeclSpace; } /// /// Returns the TypeContainer whose Type is `t' or null if there is no /// TypeContainer for `t' (ie, the Type comes from a library) /// public static TypeContainer LookupTypeContainer (Type t) { return builder_to_declspace [t] as TypeContainer; } public static MemberCache LookupMemberCache (Type t) { if (t.Module == RootContext.ToplevelTypes.Builder) { DeclSpace container = (DeclSpace)builder_to_declspace [t]; if (container != null) return container.MemberCache; } #if GMCS_SOURCE if (t is GenericTypeParameterBuilder) { TypeParameter container = builder_to_type_param [t] as TypeParameter; if (container != null) return container.MemberCache; } #endif return TypeHandle.GetMemberCache (t); } public static MemberCache LookupBaseInterfacesCache (Type t) { Type [] ifaces = GetInterfaces (t); if (ifaces != null && ifaces.Length == 1) return LookupMemberCache (ifaces [0]); // TODO: the builder_to_member_cache should be indexed by 'ifaces', not 't' MemberCache cache = builder_to_member_cache [t] as MemberCache; if (cache != null) return cache; cache = new MemberCache (ifaces); builder_to_member_cache.Add (t, cache); return cache; } public static TypeContainer LookupInterface (Type t) { TypeContainer tc = (TypeContainer) builder_to_declspace [t]; if ((tc == null) || (tc.Kind != Kind.Interface)) return null; return tc; } public static Delegate LookupDelegate (Type t) { return builder_to_declspace [t] as Delegate; } public static Class LookupClass (Type t) { return (Class) builder_to_declspace [t]; } // // We use this hash for multiple kinds of constructed types: // // (T, "&") Given T, get T & // (T, "*") Given T, get T * // (T, "[]") Given T and a array dimension, get T [] // (T, X) Given a type T and a simple name X, get the type T+X // // Accessibility tests, if necessary, should be done by the user // static DoubleHash type_hash = new DoubleHash (); // // Gets the reference to T version of the Type (T&) // public static Type GetReferenceType (Type t) { #if GMCS_SOURCE return t.MakeByRefType (); #else return GetConstructedType (t, "&"); #endif } // // Gets the pointer to T version of the Type (T*) // public static Type GetPointerType (Type t) { return GetConstructedType (t, "*"); } public static Type GetConstructedType (Type t, string dim) { object ret = null; if (type_hash.Lookup (t, dim, out ret)) return (Type) ret; ret = t.Module.GetType (t.ToString () + dim); if (ret != null) { type_hash.Insert (t, dim, ret); return (Type) ret; } if (dim == "&") { ret = GetReferenceType (t); type_hash.Insert (t, dim, ret); return (Type) ret; } #if GMCS_SOURCE if (t.IsGenericParameter || t.IsGenericType) { int pos = 0; Type result = t; while ((pos < dim.Length) && (dim [pos] == '[')) { pos++; if (dim [pos] == ']') { result = result.MakeArrayType (); pos++; if (pos < dim.Length) continue; type_hash.Insert (t, dim, result); return result; } int rank = 0; while (dim [pos] == ',') { pos++; rank++; } if ((dim [pos] != ']') || (pos != dim.Length-1)) break; result = result.MakeArrayType (rank + 1); type_hash.Insert (t, dim, result); return result; } } #endif type_hash.Insert (t, dim, null); return null; } public static Type GetNestedType (Type t, string name) { object ret = null; if (!type_hash.Lookup (t, name, out ret)) { ret = t.GetNestedType (name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly); type_hash.Insert (t, name, ret); } return (Type) ret; } /// /// Fills static table with exported types from all referenced assemblies. /// This information is required for CLS Compliance tests. /// public static void LoadAllImportedTypes () { AllClsTopLevelTypes = new Hashtable (1500); foreach (Assembly a in GlobalRootNamespace.Instance.Assemblies) { foreach (Type t in a.GetExportedTypes ()) { AllClsTopLevelTypes [t.FullName.ToLower (System.Globalization.CultureInfo.InvariantCulture)] = null; } } } public static bool NamespaceClash (string name, Location loc) { if (!GlobalRootNamespace.Instance.IsNamespace (name)) return false; Report.Error (519, loc, String.Format ("`{0}' clashes with a predefined namespace", name)); return true; } /// /// Returns the C# name of a type if possible, or the full type name otherwise /// static public string CSharpName (Type t) { if (t == null_type) return "null"; if (t == typeof (ArglistAccess)) return "__arglist"; if (t == typeof (AnonymousMethodBody)) return "anonymous method"; if (t == typeof (MethodGroupExpr)) return "method group"; if (t == null) return "internal error"; return CSharpName (GetFullName (t), t); } static readonly char [] elements = new char [] { '*', '[' }; public static string CSharpName (string name, Type type) { if (name.Length > 10) { string s; switch (name) { case "System.Int32": s = "int"; break; case "System.Int64": s = "long"; break; case "System.String": s = "string"; break; case "System.Boolean": s = "bool"; break; case "System.Void": s = "void"; break; case "System.Object": s = "object"; break; case "System.UInt32": s = "uint"; break; case "System.Int16": s = "short"; break; case "System.UInt16": s = "ushort"; break; case "System.UInt64": s = "ulong"; break; case "System.Single": s = "float"; break; case "System.Double": s = "double"; break; case "System.Decimal": s = "decimal"; break; case "System.Char": s = "char"; break; case "System.Byte": s = "byte"; break; case "System.SByte": s = "sbyte"; break; default: s = null; break; } if (s != null) { // // Predefined names can come from mscorlib only // if (type == null || type.Module.Name == "mscorlib.dll" || !RootContext.StdLib) return s; return name; } if (name [0] == AnonymousTypeClass.ClassNamePrefix [0] && name.StartsWith (AnonymousTypeClass.ClassNamePrefix)) return AnonymousTypeClass.SignatureForError; int idx = name.IndexOfAny (elements, 10); if (idx > 0) return CSharpName (name.Substring (0, idx), type) + name.Substring (idx); } return name.Replace ('+', '.'); } static public string CSharpName (Type[] types) { if (types.Length == 0) return string.Empty; StringBuilder sb = new StringBuilder (); for (int i = 0; i < types.Length; ++i) { if (i > 0) sb.Append (", "); sb.Append (CSharpName (types [i])); } return sb.ToString (); } /// /// Returns the signature of the method with full namespace classification /// static public string GetFullNameSignature (MemberInfo mi) { PropertyInfo pi = mi as PropertyInfo; if (pi != null) { MethodBase pmi = pi.GetGetMethod (true); if (pmi == null) pmi = pi.GetSetMethod (true); if (GetParameterData (pmi).Count > 0) mi = pmi; } return (mi is MethodBase) ? CSharpSignature (mi as MethodBase) : CSharpName (mi.DeclaringType) + '.' + mi.Name; } #if GMCS_SOURCE private static int GetFullName (Type t, StringBuilder sb) { int pos = 0; if (!t.IsGenericType) { sb.Append (t.FullName); return 0; } if (t.DeclaringType != null) { pos = GetFullName (t.DeclaringType, sb); sb.Append ('.'); } else if (t.Namespace != null && t.Namespace.Length != 0) { sb.Append (t.Namespace); sb.Append ('.'); } sb.Append (RemoveGenericArity (t.Name)); Type[] this_args = GetTypeArguments (t); if (this_args.Length < pos) throw new InternalErrorException ( "Enclosing class " + t.DeclaringType + " has more type arguments than " + t); if (this_args.Length == pos) return pos; sb.Append ('<'); for (;;) { sb.Append (CSharpName (this_args [pos++])); if (pos == this_args.Length) break; sb.Append (','); } sb.Append ('>'); return pos; } static string GetFullName (Type t) { if (t.IsArray) { string dimension = t.Name.Substring (t.Name.LastIndexOf ('[')); return GetFullName (GetElementType (t)) + dimension; } if (IsNullableType (t) && !t.IsGenericTypeDefinition) { t = TypeToCoreType (GetTypeArguments (t)[0]); return CSharpName (t) + "?"; } if (t.IsGenericParameter) return t.Name; if (!t.IsGenericType) return t.FullName; StringBuilder sb = new StringBuilder (); int pos = GetFullName (t, sb); if (pos <= 0) throw new InternalErrorException ("Generic Type " + t + " doesn't have type arguments"); return sb.ToString (); } #else public static string GetFullName (Type t) { return t.FullName; } #endif public static string RemoveGenericArity (string from) { int i = from.IndexOf ('`'); if (i > 0) return from.Substring (0, i); return from; } /// /// When we need to report accessors as well /// static public string CSharpSignature (MethodBase mb) { return CSharpSignature (mb, false); } /// /// Returns the signature of the method /// static public string CSharpSignature (MethodBase mb, bool show_accessor) { StringBuilder sig = new StringBuilder (CSharpName (mb.DeclaringType)); sig.Append ('.'); AParametersCollection iparams = GetParameterData (mb); string parameters = iparams.GetSignatureForError (); int accessor_end = 0; if (!mb.IsConstructor && TypeManager.IsSpecialMethod (mb)) { string op_name = Operator.GetName (mb.Name); if (op_name != null) { if (op_name == "explicit" || op_name == "implicit") { sig.Append (op_name); sig.Append (" operator "); sig.Append (CSharpName (((MethodInfo)mb).ReturnType)); } else { sig.Append ("operator "); sig.Append (op_name); } sig.Append (parameters); return sig.ToString (); } bool is_getter = mb.Name.StartsWith ("get_"); bool is_setter = mb.Name.StartsWith ("set_"); if (is_getter || is_setter || mb.Name.StartsWith ("add_")) { accessor_end = 3; } else if (mb.Name.StartsWith ("remove_")) { accessor_end = 6; } // Is indexer if (iparams.Count > (is_getter ? 0 : 1)) { sig.Append ("this["); if (is_getter) sig.Append (parameters.Substring (1, parameters.Length - 2)); else sig.Append (parameters.Substring (1, parameters.LastIndexOf (',') - 1)); sig.Append (']'); } else { sig.Append (mb.Name.Substring (accessor_end + 1)); } } else { if (mb.Name == ".ctor") sig.Append (RemoveGenericArity (mb.DeclaringType.Name)); else { sig.Append (mb.Name); if (IsGenericMethod (mb)) { Type[] args = GetGenericArguments (mb); sig.Append ('<'); for (int i = 0; i < args.Length; i++) { if (i > 0) sig.Append (','); sig.Append (CSharpName (args [i])); } sig.Append ('>'); } } sig.Append (parameters); } if (show_accessor && accessor_end > 0) { sig.Append ('.'); sig.Append (mb.Name.Substring (0, accessor_end)); } return sig.ToString (); } public static string GetMethodName (MethodInfo m) { if (!IsGenericMethodDefinition (m) && !IsGenericMethod (m)) return m.Name; return MemberName.MakeName (m.Name, TypeManager.GetGenericArguments (m).Length); } static public string CSharpSignature (EventInfo ei) { return CSharpName (ei.DeclaringType) + "." + ei.Name; } // // Looks up a type, and aborts if it is not found. This is used // by predefined types required by the compiler // public static Type CoreLookupType (string ns_name, string name, Kind type_kind, bool required) { Namespace ns = GlobalRootNamespace.Instance.GetNamespace (ns_name, true); Expression expr = ns.Lookup (RootContext.ToplevelTypes, name, Location.Null); if (expr == null) { if (required) { Report.Error (518, "The predefined type `{0}.{1}' is not defined or imported", ns_name, name); } return null; } Type t = expr.Type; if (RootContext.StdLib || t == null || !required) return t; // TODO: All predefined imported types have to have correct signature if (t.Module != RootContext.ToplevelTypes.Builder) return t; DeclSpace ds = (DeclSpace)RootContext.ToplevelTypes.GetDefinition (t.FullName); if (ds is Delegate) { if (type_kind == Kind.Delegate) return t; } else { TypeContainer tc = (TypeContainer)ds; if (tc.Kind == type_kind) return t; } Report.Error (520, ds.Location, "The predefined type `{0}.{1}' is not declared correctly", ns_name, name); return null; } static MemberInfo GetPredefinedMember (Type t, string name, MemberTypes mt, Location loc, params Type [] args) { const BindingFlags flags = instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly; MemberInfo [] members = MemberLookup (null, null, t, mt, flags, name, null); if (members != null) { for (int i = 0; i < members.Length; ++i) { MemberInfo member = members [i]; if (mt == MemberTypes.Method || mt == MemberTypes.Constructor) { MethodBase mb = member as MethodBase; if (mb == null) continue; AParametersCollection pd = TypeManager.GetParameterData (mb); if (IsEqual (pd.Types, args)) return member; } if (mt == MemberTypes.Field) { FieldInfo fi = member as FieldInfo; if (fi == null) continue; if (args.Length >= 1 && !IsEqual (TypeToCoreType (fi.FieldType), args [0])) continue; return member; } if (mt == MemberTypes.Property) { PropertyInfo pi = member as PropertyInfo; if (pi == null) continue; if (args.Length >= 1 && !IsEqual (TypeToCoreType (pi.PropertyType), args [0])) continue; return member; } } } string method_args = null; if (mt == MemberTypes.Method || mt == MemberTypes.Constructor) method_args = "(" + TypeManager.CSharpName (args) + ")"; Report.Error (656, loc, "The compiler required member `{0}.{1}{2}' could not be found or is inaccessible", TypeManager.CSharpName (t), name, method_args); return null; } // // Returns the ConstructorInfo for "args" // public static ConstructorInfo GetPredefinedConstructor (Type t, Location loc, params Type [] args) { return (ConstructorInfo) GetPredefinedMember (t, ConstructorInfo.ConstructorName, MemberTypes.Constructor, loc, args); } // // Returns the MethodInfo for a method named `name' defined // in type `t' which takes arguments of types `args' // public static MethodInfo GetPredefinedMethod (Type t, string name, Location loc, params Type [] args) { return (MethodInfo)GetPredefinedMember (t, name, MemberTypes.Method, loc, args); } public static FieldInfo GetPredefinedField (Type t, string name, Location loc, params Type [] args) { return (FieldInfo) GetPredefinedMember (t, name, MemberTypes.Field, loc, args); } public static PropertyInfo GetPredefinedProperty (Type t, string name, Location loc, params Type [] args) { return (PropertyInfo) GetPredefinedMember (t, name, MemberTypes.Property, loc, args); } /// /// The types have to be initialized after the initial /// population of the type has happened (for example, to /// bootstrap the corlib.dll /// public static bool InitCoreTypes () { object_type = CoreLookupType ("System", "Object", Kind.Class, true); system_object_expr.Type = object_type; value_type = CoreLookupType ("System", "ValueType", Kind.Class, true); system_valuetype_expr.Type = value_type; attribute_type = CoreLookupType ("System", "Attribute", Kind.Class, true); int32_type = CoreLookupType ("System", "Int32", Kind.Struct, true); system_int32_expr.Type = int32_type; int64_type = CoreLookupType ("System", "Int64", Kind.Struct, true); system_int64_expr.Type = int64_type; uint32_type = CoreLookupType ("System", "UInt32", Kind.Struct, true); system_uint32_expr.Type = uint32_type; uint64_type = CoreLookupType ("System", "UInt64", Kind.Struct, true); system_uint64_expr.Type = uint64_type; byte_type = CoreLookupType ("System", "Byte", Kind.Struct, true); system_byte_expr.Type = byte_type; sbyte_type = CoreLookupType ("System", "SByte", Kind.Struct, true); system_sbyte_expr.Type = sbyte_type; short_type = CoreLookupType ("System", "Int16", Kind.Struct, true); system_int16_expr.Type = short_type; ushort_type = CoreLookupType ("System", "UInt16", Kind.Struct, true); system_uint16_expr.Type = ushort_type; ienumerator_type = CoreLookupType ("System.Collections", "IEnumerator", Kind.Interface, true); ienumerable_type = CoreLookupType ("System.Collections", "IEnumerable", Kind.Interface, true); idisposable_type = CoreLookupType ("System", "IDisposable", Kind.Interface, true); // HACK: DefineType immediately resolves iterators (very wrong) generic_ienumerator_type = CoreLookupType ("System.Collections.Generic", "IEnumerator`1", Kind.Interface, false); char_type = CoreLookupType ("System", "Char", Kind.Struct, true); system_char_expr.Type = char_type; string_type = CoreLookupType ("System", "String", Kind.Class, true); system_string_expr.Type = string_type; float_type = CoreLookupType ("System", "Single", Kind.Struct, true); system_single_expr.Type = float_type; double_type = CoreLookupType ("System", "Double", Kind.Struct, true); system_double_expr.Type = double_type; decimal_type = CoreLookupType ("System", "Decimal", Kind.Struct, true); system_decimal_expr.Type = decimal_type; bool_type = CoreLookupType ("System", "Boolean", Kind.Struct, true); system_boolean_expr.Type = bool_type; intptr_type = CoreLookupType ("System", "IntPtr", Kind.Struct, true); system_intptr_expr.Type = intptr_type; uintptr_type = CoreLookupType ("System", "UIntPtr", Kind.Struct, true); multicast_delegate_type = CoreLookupType ("System", "MulticastDelegate", Kind.Class, true); delegate_type = CoreLookupType ("System", "Delegate", Kind.Class, true); enum_type = CoreLookupType ("System", "Enum", Kind.Class, true); array_type = CoreLookupType ("System", "Array", Kind.Class, true); void_type = CoreLookupType ("System", "Void", Kind.Struct, true); system_void_expr.Type = void_type; type_type = CoreLookupType ("System", "Type", Kind.Class, true); exception_type = CoreLookupType ("System", "Exception", Kind.Class, true); runtime_field_handle_type = CoreLookupType ("System", "RuntimeFieldHandle", Kind.Struct, true); runtime_handle_type = CoreLookupType ("System", "RuntimeTypeHandle", Kind.Struct, true); PredefinedAttributes.Get.ParamArray.Resolve (false); PredefinedAttributes.Get.Out.Resolve (false); return Report.Errors == 0; } // // Initializes optional core types // public static void InitOptionalCoreTypes () { // // These are only used for compare purposes // null_type = typeof (NullLiteral); void_ptr_type = GetPointerType (void_type); // // Initialize InternalsVisibleTo as the very first optional type. Otherwise we would populate // types cache with incorrect accessiblity when any of optional types is internal. // PredefinedAttributes.Get.Initialize (); runtime_argument_handle_type = CoreLookupType ("System", "RuntimeArgumentHandle", Kind.Struct, false); asynccallback_type = CoreLookupType ("System", "AsyncCallback", Kind.Delegate, false); iasyncresult_type = CoreLookupType ("System", "IAsyncResult", Kind.Interface, false); typed_reference_type = CoreLookupType ("System", "TypedReference", Kind.Struct, false); arg_iterator_type = CoreLookupType ("System", "ArgIterator", Kind.Struct, false); mbr_type = CoreLookupType ("System", "MarshalByRefObject", Kind.Class, false); // // Optional attributes, used for error reporting only // //if (PredefinedAttributes.Get.Obsolete.IsDefined) { // Class c = TypeManager.LookupClass (PredefinedAttributes.Get.Obsolete.Type); // if (c != null) // c.Define (); //} generic_ilist_type = CoreLookupType ("System.Collections.Generic", "IList`1", Kind.Interface, false); generic_icollection_type = CoreLookupType ("System.Collections.Generic", "ICollection`1", Kind.Interface, false); generic_ienumerable_type = CoreLookupType ("System.Collections.Generic", "IEnumerable`1", Kind.Interface, false); generic_nullable_type = CoreLookupType ("System", "Nullable`1", Kind.Struct, false); // // Optional types which are used as types and for member lookup // runtime_helpers_type = CoreLookupType ("System.Runtime.CompilerServices", "RuntimeHelpers", Kind.Class, false); // New in .NET 3.5 // Note: extension_attribute_type is already loaded expression_type = CoreLookupType ("System.Linq.Expressions", "Expression`1", Kind.Class, false); if (!RootContext.StdLib) { // // HACK: When building Mono corlib mcs uses loaded mscorlib which // has different predefined types and this method sets mscorlib types // to be same to avoid any type check errors. // Type type = typeof (Type); Type [] system_4_type_arg = { type, type, type, type }; MethodInfo set_corlib_type_builders = typeof (System.Reflection.Emit.AssemblyBuilder).GetMethod ( "SetCorlibTypeBuilders", BindingFlags.NonPublic | BindingFlags.Instance, null, system_4_type_arg, null); if (set_corlib_type_builders != null) { object[] args = new object [4]; args [0] = object_type; args [1] = value_type; args [2] = enum_type; args [3] = void_type; set_corlib_type_builders.Invoke (CodeGen.Assembly.Builder, args); } else { Report.Warning (-26, 3, "The compilation may fail due to missing `{0}.SetCorlibTypeBuilders({1})' method", TypeManager.CSharpName (typeof (System.Reflection.Emit.AssemblyBuilder)), TypeManager.CSharpName (system_4_type_arg)); } } } const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance; /// /// This is the "old", non-cache based FindMembers() function. We cannot use /// the cache here because there is no member name argument. /// public static MemberList FindMembers (Type t, MemberTypes mt, BindingFlags bf, MemberFilter filter, object criteria) { #if MS_COMPATIBLE && GMCS_SOURCE if (t.IsGenericType) t = t.GetGenericTypeDefinition (); #endif DeclSpace decl = (DeclSpace) builder_to_declspace [t]; // // `builder_to_declspace' contains all dynamic types. // if (decl != null) { MemberList list; Timer.StartTimer (TimerType.FindMembers); list = decl.FindMembers (mt, bf, filter, criteria); Timer.StopTimer (TimerType.FindMembers); return list; } // // We have to take care of arrays specially, because GetType on // a TypeBuilder array will return a Type, not a TypeBuilder, // and we can not call FindMembers on this type. // if ( #if MS_COMPATIBLE && GMCS_SOURCE !t.IsGenericType && #endif t.IsSubclassOf (TypeManager.array_type)) return new MemberList (TypeManager.array_type.FindMembers (mt, bf, filter, criteria)); #if GMCS_SOURCE if (t is GenericTypeParameterBuilder) { TypeParameter tparam = (TypeParameter) builder_to_type_param [t]; Timer.StartTimer (TimerType.FindMembers); MemberList list = tparam.FindMembers ( mt, bf | BindingFlags.DeclaredOnly, filter, criteria); Timer.StopTimer (TimerType.FindMembers); return list; } #endif // // Since FindMembers will not lookup both static and instance // members, we emulate this behaviour here. // if ((bf & instance_and_static) == instance_and_static){ MemberInfo [] i_members = t.FindMembers ( mt, bf & ~BindingFlags.Static, filter, criteria); int i_len = i_members.Length; if (i_len == 1){ MemberInfo one = i_members [0]; // // If any of these are present, we are done! // if ((one is Type) || (one is EventInfo) || (one is FieldInfo)) return new MemberList (i_members); } MemberInfo [] s_members = t.FindMembers ( mt, bf & ~BindingFlags.Instance, filter, criteria); int s_len = s_members.Length; if (i_len > 0 || s_len > 0) return new MemberList (i_members, s_members); else { if (i_len > 0) return new MemberList (i_members); else return new MemberList (s_members); } } return new MemberList (t.FindMembers (mt, bf, filter, criteria)); } /// /// This method is only called from within MemberLookup. It tries to use the member /// cache if possible and falls back to the normal FindMembers if not. The `used_cache' /// flag tells the caller whether we used the cache or not. If we used the cache, then /// our return value will already contain all inherited members and the caller don't need /// to check base classes and interfaces anymore. /// private static MemberInfo [] MemberLookup_FindMembers (Type t, MemberTypes mt, BindingFlags bf, string name, out bool used_cache) { MemberCache cache; // // If this is a dynamic type, it's always in the `builder_to_declspace' hash table // and we can ask the DeclSpace for the MemberCache. // #if MS_COMPATIBLE if (t.Assembly == CodeGen.Assembly.Builder) { if (t.IsGenericParameter) { TypeParameter tparam = (TypeParameter) builder_to_type_param[t]; used_cache = true; if (tparam.MemberCache == null) return new MemberInfo[0]; return tparam.MemberCache.FindMembers ( mt, bf, name, FilterWithClosure_delegate, null); } // // We have to take care of arrays specially, because GetType on // a TypeBuilder array will return a Type, not a TypeBuilder, // and we can not call FindMembers on this type. // if (t.IsArray) { used_cache = true; return TypeHandle.ArrayType.MemberCache.FindMembers ( mt, bf, name, FilterWithClosure_delegate, null); } if (t.IsGenericType && !t.IsGenericTypeDefinition) t = t.GetGenericTypeDefinition (); #else if (t is TypeBuilder) { #endif DeclSpace decl = (DeclSpace) builder_to_declspace [t]; cache = decl.MemberCache; // // If this DeclSpace has a MemberCache, use it. // if (cache != null) { used_cache = true; return cache.FindMembers ( mt, bf, name, FilterWithClosure_delegate, null); } // If there is no MemberCache, we need to use the "normal" FindMembers. // Note, this is a VERY uncommon route! MemberList list; Timer.StartTimer (TimerType.FindMembers); list = decl.FindMembers (mt, bf | BindingFlags.DeclaredOnly, FilterWithClosure_delegate, name); Timer.StopTimer (TimerType.FindMembers); used_cache = false; return (MemberInfo []) list; } // // We have to take care of arrays specially, because GetType on // a TypeBuilder array will return a Type, not a TypeBuilder, // and we can not call FindMembers on this type. // if (t.IsArray) { used_cache = true; return TypeHandle.ArrayType.MemberCache.FindMembers ( mt, bf, name, FilterWithClosure_delegate, null); } #if GMCS_SOURCE if (t is GenericTypeParameterBuilder) { TypeParameter tparam = (TypeParameter) builder_to_type_param [t]; used_cache = true; if (tparam.MemberCache == null) return new MemberInfo [0]; return tparam.MemberCache.FindMembers ( mt, bf, name, FilterWithClosure_delegate, null); } #endif if (IsGenericType (t) && (mt == MemberTypes.NestedType)) { // // This happens if we're resolving a class'es base class and interfaces // in TypeContainer.DefineType(). At this time, the types aren't // populated yet, so we can't use the cache. // MemberInfo[] info = t.FindMembers (mt, bf | BindingFlags.DeclaredOnly, FilterWithClosure_delegate, name); used_cache = false; return info; } // // This call will always succeed. There is exactly one TypeHandle instance per // type, TypeHandle.GetMemberCache() will, if necessary, create a new one, and return // the corresponding MemberCache. // cache = TypeHandle.GetMemberCache (t); used_cache = true; return cache.FindMembers (mt, bf, name, FilterWithClosure_delegate, null); } public static bool IsBuiltinType (Type t) { t = TypeToCoreType (t); if (t == object_type || t == string_type || t == int32_type || t == uint32_type || t == int64_type || t == uint64_type || t == float_type || t == double_type || t == char_type || t == short_type || t == decimal_type || t == bool_type || t == sbyte_type || t == byte_type || t == ushort_type || t == void_type) return true; else return false; } // // This is like IsBuiltinType, but lacks decimal_type, we should also clean up // the pieces in the code where we use IsBuiltinType and special case decimal_type. // public static bool IsPrimitiveType (Type t) { return (t == int32_type || t == uint32_type || t == int64_type || t == uint64_type || t == float_type || t == double_type || t == char_type || t == short_type || t == bool_type || t == sbyte_type || t == byte_type || t == ushort_type); } public static bool IsDelegateType (Type t) { if (TypeManager.IsGenericParameter (t)) return false; if (t == TypeManager.delegate_type || t == TypeManager.multicast_delegate_type) return false; t = DropGenericTypeArguments (t); return IsSubclassOf (t, TypeManager.delegate_type); } // // Is a type of dynamic type // public static bool IsDynamicType (Type t) { if (t == InternalType.Dynamic) return true; if (t != object_type) return false; if (t.Module == RootContext.ToplevelTypes.Builder) return false; PredefinedAttribute pa = PredefinedAttributes.Get.Dynamic; if (pa == null) return false; object[] res = t.GetCustomAttributes (pa.Type, false); return res != null && res.Length != 0; } public static bool IsEnumType (Type t) { t = DropGenericTypeArguments (t); return t.BaseType == TypeManager.enum_type; } public static bool IsBuiltinOrEnum (Type t) { if (IsBuiltinType (t)) return true; if (IsEnumType (t)) return true; return false; } public static bool IsAttributeType (Type t) { return t == attribute_type && t.BaseType != null || IsSubclassOf (t, attribute_type); } // // Whether a type is unmanaged. This is used by the unsafe code (25.2) // // mcs4: delete, DeclSpace.IsUnmanagedType is replacement public static bool IsUnmanagedType (Type t) { DeclSpace ds = TypeManager.LookupDeclSpace (t); if (ds != null) return ds.IsUnmanagedType (); // builtins that are not unmanaged types if (t == TypeManager.object_type || t == TypeManager.string_type) return false; if (IsGenericType (t) || IsGenericParameter (t)) return false; if (IsBuiltinOrEnum (t)) return true; // Someone did the work of checking if the ElementType of t is unmanaged. Let's not repeat it. if (t.IsPointer) return IsUnmanagedType (GetElementType (t)); // Arrays are disallowed, even if we mark them with [MarshalAs(UnmanagedType.ByValArray, ...)] if (t.IsArray) return false; if (!IsValueType (t)) return false; for (Type p = t.DeclaringType; p != null; p = p.DeclaringType) { if (IsGenericTypeDefinition (p)) return false; } bool retval = true; { FieldInfo [] fields = t.GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); foreach (FieldInfo f in fields){ if (!IsUnmanagedType (f.FieldType)){ retval = false; } } } return retval; } // // Null is considered to be a reference type // public static bool IsReferenceType (Type t) { if (TypeManager.IsGenericParameter (t)) { GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t); if (constraints == null) return false; return constraints.IsReferenceType; } return !IsStruct (t) && !IsEnumType (t); } public static bool IsValueType (Type t) { if (TypeManager.IsGenericParameter (t)) { GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t); if (constraints == null) return false; return constraints.IsValueType; } return IsStruct (t) || IsEnumType (t); } public static bool IsStruct (Type t) { return t.BaseType == value_type && t != enum_type && t.IsSealed; } public static bool IsInterfaceType (Type t) { TypeContainer tc = (TypeContainer) builder_to_declspace [t]; if (tc == null) return false; return tc.Kind == Kind.Interface; } public static bool IsSubclassOf (Type type, Type base_type) { TypeParameter tparam = LookupTypeParameter (type); TypeParameter pparam = LookupTypeParameter (base_type); if ((tparam != null) && (pparam != null)) { if (tparam == pparam) return true; return tparam.IsSubclassOf (base_type); } #if MS_COMPATIBLE && GMCS_SOURCE if (type.IsGenericType) type = type.GetGenericTypeDefinition (); #endif if (type.IsSubclassOf (base_type)) return true; do { if (IsEqual (type, base_type)) return true; type = type.BaseType; } while (type != null); return false; } public static bool IsPrivateAccessible (Type type, Type parent) { if (type == null) return false; if (type.Equals (parent)) return true; return DropGenericTypeArguments (type) == DropGenericTypeArguments (parent); } public static bool IsFamilyAccessible (Type type, Type parent) { TypeParameter tparam = LookupTypeParameter (type); TypeParameter pparam = LookupTypeParameter (parent); if ((tparam != null) && (pparam != null)) { if (tparam == pparam) return true; return tparam.IsSubclassOf (parent); } do { if (IsInstantiationOfSameGenericType (type, parent)) return true; type = type.BaseType; } while (type != null); return false; } // // Checks whether `type' is a subclass or nested child of `base_type'. // public static bool IsNestedFamilyAccessible (Type type, Type base_type) { do { if (IsFamilyAccessible (type, base_type)) return true; // Handle nested types. type = type.DeclaringType; } while (type != null); return false; } // // Checks whether `type' is a nested child of `parent'. // public static bool IsNestedChildOf (Type type, Type parent) { if (type == null) return false; type = DropGenericTypeArguments (type); parent = DropGenericTypeArguments (parent); if (IsEqual (type, parent)) return false; type = type.DeclaringType; while (type != null) { if (IsEqual (type, parent)) return true; type = type.DeclaringType; } return false; } public static bool IsSpecialType (Type t) { return t == arg_iterator_type || t == typed_reference_type; } // // Checks whether `extern_type' is friend of the output assembly // public static bool IsThisOrFriendAssembly (Assembly assembly) { if (assembly == CodeGen.Assembly.Builder) return true; if (assembly_internals_vis_attrs.Contains (assembly)) return (bool)(assembly_internals_vis_attrs [assembly]); PredefinedAttribute pa = PredefinedAttributes.Get.InternalsVisibleTo; // HACK: Do very early resolve of SRE type checking if (pa.Type == null) pa.Resolve (true); if (!pa.IsDefined) return false; object [] attrs = assembly.GetCustomAttributes (pa.Type, false); if (attrs.Length == 0) { assembly_internals_vis_attrs.Add (assembly, false); return false; } bool is_friend = false; AssemblyName this_name = CodeGen.Assembly.Name; byte [] this_token = this_name.GetPublicKeyToken (); foreach (InternalsVisibleToAttribute attr in attrs) { if (attr.AssemblyName == null || attr.AssemblyName.Length == 0) continue; AssemblyName aname = null; try { #if GMCS_SOURCE aname = new AssemblyName (attr.AssemblyName); #else throw new NotSupportedException (); #endif } catch (FileLoadException) { } catch (ArgumentException) { } if (aname == null || aname.Name != this_name.Name) continue; byte [] key_token = aname.GetPublicKeyToken (); if (key_token != null) { if (this_token.Length == 0) { // Same name, but assembly is not strongnamed Error_FriendAccessNameNotMatching (aname.FullName); break; } if (!CompareKeyTokens (this_token, key_token)) continue; } is_friend = true; break; } assembly_internals_vis_attrs.Add (assembly, is_friend); return is_friend; } static bool CompareKeyTokens (byte [] token1, byte [] token2) { for (int i = 0; i < token1.Length; i++) if (token1 [i] != token2 [i]) return false; return true; } static void Error_FriendAccessNameNotMatching (string other_name) { Report.Error (281, "Friend access was granted to `{0}', but the output assembly is named `{1}'. Try adding a reference to `{0}' or change the output assembly name to match it", other_name, CodeGen.Assembly.Name.FullName); } // // Do the right thing when returning the element type of an // array type based on whether we are compiling corlib or not // public static Type GetElementType (Type t) { if (RootContext.StdLib) return t.GetElementType (); else return TypeToCoreType (t.GetElementType ()); } /// /// This method is not implemented by MS runtime for dynamic types /// public static bool HasElementType (Type t) { return t.IsArray || t.IsPointer || t.IsByRef; } public static Type GetEnumUnderlyingType (Type t) { t = DropGenericTypeArguments (t); Enum e = LookupTypeContainer (t) as Enum; if (e != null) return e.UnderlyingType; // TODO: cache it ? FieldInfo fi = GetPredefinedField (t, Enum.UnderlyingValueField, Location.Null, Type.EmptyTypes); if (fi == null) return TypeManager.int32_type; return TypeToCoreType (fi.FieldType); } /// /// Gigantic work around for missing features in System.Reflection.Emit follows. /// /// /// /// Since System.Reflection.Emit can not return MethodBase.GetParameters /// for anything which is dynamic, and we need this in a number of places, /// we register this information here, and use it afterwards. /// static public void RegisterMethod (MethodBase mb, AParametersCollection ip) { method_params.Add (mb, ip); } static public void RegisterIndexer (PropertyBuilder pb, AParametersCollection p) { method_params.Add (pb, p); } static public AParametersCollection GetParameterData (MethodBase mb) { AParametersCollection pd = (AParametersCollection) method_params [mb]; if (pd == null) { #if MS_COMPATIBLE if (mb.IsGenericMethod && !mb.IsGenericMethodDefinition) { MethodInfo mi = ((MethodInfo) mb).GetGenericMethodDefinition (); pd = GetParameterData (mi); /* if (mi.IsGenericMethod) pd = pd.InflateTypes (mi.GetGenericArguments (), mb.GetGenericArguments ()); else pd = pd.InflateTypes (mi.DeclaringType.GetGenericArguments (), mb.GetGenericArguments ()); */ method_params.Add (mb, pd); return pd; } if (mb.DeclaringType.Assembly == CodeGen.Assembly.Builder) { throw new InternalErrorException ("Parameters are not registered for method `{0}'", TypeManager.CSharpName (mb.DeclaringType) + "." + mb.Name); } pd = ParametersImported.Create (mb); #else MethodBase generic = TypeManager.DropGenericMethodArguments (mb); if (generic != mb) { pd = TypeManager.GetParameterData (generic); pd = ParametersImported.Create (pd, mb); } else { pd = ParametersImported.Create (mb); } #endif method_params.Add (mb, pd); } return pd; } public static AParametersCollection GetParameterData (PropertyInfo pi) { AParametersCollection pd = (AParametersCollection)method_params [pi]; if (pd == null) { if (pi is PropertyBuilder) return ParametersCompiled.EmptyReadOnlyParameters; ParameterInfo [] p = pi.GetIndexParameters (); if (p == null) return ParametersCompiled.EmptyReadOnlyParameters; pd = ParametersImported.Create (p, null); method_params.Add (pi, pd); } return pd; } public static AParametersCollection GetDelegateParameters (Type t) { Delegate d = builder_to_declspace [t] as Delegate; if (d != null) return d.Parameters; MethodInfo invoke_mb = Delegate.GetInvokeMethod (t, t); return GetParameterData (invoke_mb); } static public void RegisterOverride (MethodBase override_method, MethodBase base_method) { if (!method_overrides.Contains (override_method)) method_overrides [override_method] = base_method; if (method_overrides [override_method] != base_method) throw new InternalErrorException ("Override mismatch: " + override_method); } static public bool IsOverride (MethodBase m) { m = DropGenericMethodArguments (m); return m.IsVirtual && (m.Attributes & MethodAttributes.NewSlot) == 0 && (m is MethodBuilder || method_overrides.Contains (m)); } static public MethodBase TryGetBaseDefinition (MethodBase m) { m = DropGenericMethodArguments (m); return (MethodBase) method_overrides [m]; } public static void RegisterConstant (FieldInfo fb, IConstant ic) { fields.Add (fb, ic); } public static IConstant GetConstant (FieldInfo fb) { if (fb == null) return null; return (IConstant)fields [fb]; } public static void RegisterProperty (PropertyInfo pi, PropertyBase pb) { propertybuilder_to_property.Add (pi, pb); } public static PropertyBase GetProperty (PropertyInfo pi) { return (PropertyBase)propertybuilder_to_property [pi]; } static public void RegisterFieldBase (FieldBuilder fb, FieldBase f) { fieldbuilders_to_fields.Add (fb, f); } // // The return value can be null; This will be the case for // auxiliary FieldBuilders created by the compiler that have no // real field being declared on the source code // static public FieldBase GetField (FieldInfo fb) { #if GMCS_SOURCE fb = GetGenericFieldDefinition (fb); #endif return (FieldBase) fieldbuilders_to_fields [fb]; } static public MethodInfo GetAddMethod (EventInfo ei) { if (ei is MyEventBuilder) { return ((MyEventBuilder)ei).GetAddMethod (true); } return ei.GetAddMethod (true); } static public MethodInfo GetRemoveMethod (EventInfo ei) { if (ei is MyEventBuilder) { return ((MyEventBuilder)ei).GetRemoveMethod (true); } return ei.GetRemoveMethod (true); } static public void RegisterEventField (EventInfo einfo, EventField e) { if (events == null) events = new Hashtable (); events.Add (einfo, e); } static public EventField GetEventField (EventInfo ei) { if (events == null) return null; return (EventField) events [ei]; } public static bool CheckStructCycles (TypeContainer tc, Hashtable seen) { Hashtable hash = new Hashtable (); return CheckStructCycles (tc, seen, hash); } public static bool CheckStructCycles (TypeContainer tc, Hashtable seen, Hashtable hash) { if ((tc.Kind != Kind.Struct) || IsBuiltinType (tc.TypeBuilder)) return true; // // `seen' contains all types we've already visited. // if (seen.Contains (tc)) return true; seen.Add (tc, null); if (tc.Fields == null) return true; foreach (FieldBase field in tc.Fields) { if (field.FieldBuilder == null || field.FieldBuilder.IsStatic) continue; Type ftype = field.FieldBuilder.FieldType; TypeContainer ftc = LookupTypeContainer (ftype); if (ftc == null) continue; if (hash.Contains (ftc)) { Report.Error (523, tc.Location, "Struct member `{0}.{1}' of type `{2}' " + "causes a cycle in the struct layout", tc.Name, field.Name, ftc.Name); return false; } // // `hash' contains all types in the current path. // hash.Add (tc, null); bool ok = CheckStructCycles (ftc, seen, hash); hash.Remove (tc); if (!ok) return false; if (!seen.Contains (ftc)) seen.Add (ftc, null); } return true; } /// /// Given an array of interface types, expand and eliminate repeated ocurrences /// of an interface. /// /// /// /// This expands in context like: IA; IB : IA; IC : IA, IB; the interface "IC" to /// be IA, IB, IC. /// public static Type[] ExpandInterfaces (TypeExpr [] base_interfaces) { ArrayList new_ifaces = new ArrayList (); foreach (TypeExpr iface in base_interfaces){ Type itype = iface.Type; if (new_ifaces.Contains (itype)) continue; new_ifaces.Add (itype); Type [] implementing = GetInterfaces (itype); foreach (Type imp in implementing){ if (!new_ifaces.Contains (imp)) new_ifaces.Add (imp); } } Type [] ret = new Type [new_ifaces.Count]; new_ifaces.CopyTo (ret, 0); return ret; } public static Type[] ExpandInterfaces (Type [] base_interfaces) { ArrayList new_ifaces = new ArrayList (); foreach (Type itype in base_interfaces){ if (new_ifaces.Contains (itype)) continue; new_ifaces.Add (itype); Type [] implementing = GetInterfaces (itype); foreach (Type imp in implementing){ if (!new_ifaces.Contains (imp)) new_ifaces.Add (imp); } } Type [] ret = new Type [new_ifaces.Count]; new_ifaces.CopyTo (ret, 0); return ret; } static PtrHashtable iface_cache; /// /// This function returns the interfaces in the type `t'. Works with /// both types and TypeBuilders. /// public static Type [] GetInterfaces (Type t) { Type [] cached = iface_cache [t] as Type []; if (cached != null) return cached; // // The reason for catching the Array case is that Reflection.Emit // will not return a TypeBuilder for Array types of TypeBuilder types, // but will still throw an exception if we try to call GetInterfaces // on the type. // // Since the array interfaces are always constant, we return those for // the System.Array // if (t.IsArray) t = TypeManager.array_type; if ((t is TypeBuilder) || IsGenericType (t)) { Type [] base_ifaces; if (t.BaseType == null) base_ifaces = Type.EmptyTypes; else base_ifaces = GetInterfaces (t.BaseType); Type[] type_ifaces; if (IsGenericType (t)) #if MS_COMPATIBLE && GMCS_SOURCE type_ifaces = t.GetGenericTypeDefinition().GetInterfaces (); #else type_ifaces = t.GetInterfaces (); #endif else type_ifaces = (Type []) builder_to_ifaces [t]; if (type_ifaces == null || type_ifaces.Length == 0) type_ifaces = Type.EmptyTypes; int base_count = base_ifaces.Length; Type [] result = new Type [base_count + type_ifaces.Length]; base_ifaces.CopyTo (result, 0); type_ifaces.CopyTo (result, base_count); iface_cache [t] = result; return result; } else if (t is GenericTypeParameterBuilder){ Type[] type_ifaces = (Type []) builder_to_ifaces [t]; if (type_ifaces == null || type_ifaces.Length == 0) type_ifaces = Type.EmptyTypes; iface_cache [t] = type_ifaces; return type_ifaces; } else { Type[] ifaces = t.GetInterfaces (); iface_cache [t] = ifaces; return ifaces; } } // // gets the interfaces that are declared explicitly on t // public static Type [] GetExplicitInterfaces (TypeBuilder t) { return (Type []) builder_to_ifaces [t]; } /// /// The following is used to check if a given type implements an interface. /// The cache helps us reduce the expense of hitting Type.GetInterfaces everytime. /// public static bool ImplementsInterface (Type t, Type iface) { Type [] interfaces; // // FIXME OPTIMIZATION: // as soon as we hit a non-TypeBuiler in the interface // chain, we could return, as the `Type.GetInterfaces' // will return all the interfaces implement by the type // or its bases. // do { interfaces = GetInterfaces (t); if (interfaces != null){ foreach (Type i in interfaces){ if (i == iface || IsVariantOf (i, iface)) return true; } } t = t.BaseType; } while (t != null); return false; } static NumberFormatInfo nf_provider = CultureInfo.CurrentCulture.NumberFormat; // This is a custom version of Convert.ChangeType() which works // with the TypeBuilder defined types when compiling corlib. public static object ChangeType (object value, Type conversionType, out bool error) { IConvertible convert_value = value as IConvertible; if (convert_value == null){ error = true; return null; } // // NOTE 1: // We must use Type.Equals() here since `conversionType' is // the TypeBuilder created version of a system type and not // the system type itself. You cannot use Type.GetTypeCode() // on such a type - it'd always return TypeCode.Object. // // NOTE 2: // We cannot rely on build-in type conversions as they are // more limited than what C# supports. // See char -> float/decimal/double conversion // error = false; try { if (conversionType.Equals (typeof (Boolean))) return (object)(convert_value.ToBoolean (nf_provider)); if (conversionType.Equals (typeof (Byte))) return (object)(convert_value.ToByte (nf_provider)); if (conversionType.Equals (typeof (Char))) return (object)(convert_value.ToChar (nf_provider)); if (conversionType.Equals (typeof (DateTime))) return (object)(convert_value.ToDateTime (nf_provider)); if (conversionType.Equals (decimal_type)) { if (convert_value.GetType () == TypeManager.char_type) return (decimal)convert_value.ToInt32 (nf_provider); return convert_value.ToDecimal (nf_provider); } if (conversionType.Equals (typeof (Double))) { if (convert_value.GetType () == TypeManager.char_type) return (double)convert_value.ToInt32 (nf_provider); return convert_value.ToDouble (nf_provider); } if (conversionType.Equals (typeof (Int16))) return (object)(convert_value.ToInt16 (nf_provider)); if (conversionType.Equals (int32_type)) return (object)(convert_value.ToInt32 (nf_provider)); if (conversionType.Equals (int64_type)) return (object)(convert_value.ToInt64 (nf_provider)); if (conversionType.Equals (typeof (SByte))) return (object)(convert_value.ToSByte (nf_provider)); if (conversionType.Equals (typeof (Single))) { if (convert_value.GetType () == TypeManager.char_type) return (float)convert_value.ToInt32 (nf_provider); return convert_value.ToSingle (nf_provider); } if (conversionType.Equals (typeof (String))) return (object)(convert_value.ToString (nf_provider)); if (conversionType.Equals (typeof (UInt16))) return (object)(convert_value.ToUInt16 (nf_provider)); if (conversionType.Equals (typeof (UInt32))) return (object)(convert_value.ToUInt32 (nf_provider)); if (conversionType.Equals (typeof (UInt64))) return (object)(convert_value.ToUInt64 (nf_provider)); if (conversionType.Equals (typeof (Object))) return (object)(value); else error = true; } catch { error = true; } return null; } // // When compiling with -nostdlib and the type is imported from an external assembly // SRE uses "wrong" type and we have to convert it to the right compiler instance. // public static Type TypeToCoreType (Type t) { if (RootContext.StdLib || t.Module != typeof (object).Module) return t; TypeCode tc = Type.GetTypeCode (t); switch (tc){ case TypeCode.Boolean: return TypeManager.bool_type; case TypeCode.Byte: return TypeManager.byte_type; case TypeCode.SByte: return TypeManager.sbyte_type; case TypeCode.Char: return TypeManager.char_type; case TypeCode.Int16: return TypeManager.short_type; case TypeCode.UInt16: return TypeManager.ushort_type; case TypeCode.Int32: return TypeManager.int32_type; case TypeCode.UInt32: return TypeManager.uint32_type; case TypeCode.Int64: return TypeManager.int64_type; case TypeCode.UInt64: return TypeManager.uint64_type; case TypeCode.Single: return TypeManager.float_type; case TypeCode.Double: return TypeManager.double_type; case TypeCode.String: return TypeManager.string_type; case TypeCode.Decimal: return TypeManager.decimal_type; } if (t == typeof (void)) return TypeManager.void_type; if (t == typeof (object)) return TypeManager.object_type; if (t == typeof (System.Type)) return TypeManager.type_type; if (t == typeof (System.IntPtr)) return TypeManager.intptr_type; if (t == typeof (System.UIntPtr)) return TypeManager.uintptr_type; #if GMCS_SOURCE if (t.IsArray) { int dim = t.GetArrayRank (); t = GetElementType (t); return t.MakeArrayType (dim); } if (t.IsByRef) { t = GetElementType (t); return t.MakeByRefType (); } if (t.IsPointer) { t = GetElementType (t); return t.MakePointerType (); } #endif return t; } // // Converts any type to reflection supported type // public static Type TypeToReflectionType (Type type) { // TODO: Very lame and painful, GetReference () is enough for mcs-cecil return IsDynamicType (type) ? object_type : type; } /// /// Utility function that can be used to probe whether a type /// is managed or not. /// public static bool VerifyUnManaged (Type t, Location loc) { if (IsUnmanagedType (t)) return true; while (t.IsPointer) t = GetElementType (t); Report.SymbolRelatedToPreviousError (t); Report.Error (208, loc, "Cannot take the address of, get the size of, or declare a pointer to a managed type `{0}'", CSharpName (t)); return false; } /// /// Returns the name of the indexer in a given type. /// /// /// The default is not always `Item'. The user can change this behaviour by /// using the IndexerNameAttribute in the container. /// For example, the String class indexer is named `Chars' not `Item' /// public static string IndexerPropertyName (Type t) { t = DropGenericTypeArguments (t); if (t is TypeBuilder) { TypeContainer tc = t.IsInterface ? LookupInterface (t) : LookupTypeContainer (t); return tc == null ? TypeContainer.DefaultIndexerName : tc.IndexerName; } PredefinedAttribute pa = PredefinedAttributes.Get.DefaultMember; if (pa.IsDefined) { System.Attribute attr = System.Attribute.GetCustomAttribute ( t, pa.Type); if (attr != null) { DefaultMemberAttribute dma = (DefaultMemberAttribute) attr; return dma.MemberName; } } return TypeContainer.DefaultIndexerName; } static MethodInfo declare_local_method = null; public static LocalBuilder DeclareLocalPinned (ILGenerator ig, Type t) { if (declare_local_method == null){ declare_local_method = typeof (ILGenerator).GetMethod ( "DeclareLocal", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type [] { typeof (Type), typeof (bool)}, null); if (declare_local_method == null){ Report.RuntimeMissingSupport (Location.Null, "pinned local variables"); return ig.DeclareLocal (t); } } return (LocalBuilder) declare_local_method.Invoke (ig, new object [] { t, true }); } private static bool IsSignatureEqual (Type a, Type b) { /// /// Consider the following example (bug #77674): /// /// public abstract class A /// { /// public abstract T Foo (); /// } /// /// public abstract class B : A /// { /// public override U Foo () /// { return default (U); } /// } /// /// Here, `T' and `U' are method type parameters from different methods /// (A.Foo and B.Foo), so both `==' and Equals() will fail. /// /// However, since we're determining whether B.Foo() overrides A.Foo(), /// we need to do a signature based comparision and consider them equal. if (a == b) return true; #if GMCS_SOURCE if (a.IsGenericParameter && b.IsGenericParameter && (a.DeclaringMethod != null) && (b.DeclaringMethod != null)) { return a.GenericParameterPosition == b.GenericParameterPosition; } #endif if (a.IsArray && b.IsArray) { if (a.GetArrayRank () != b.GetArrayRank ()) return false; return IsSignatureEqual (GetElementType (a), GetElementType (b)); } if (a.IsByRef && b.IsByRef) return IsSignatureEqual (GetElementType (a), GetElementType (b)); if (IsGenericType (a) && IsGenericType (b)) { if (DropGenericTypeArguments (a) != DropGenericTypeArguments (b)) return false; Type[] aargs = GetTypeArguments (a); Type[] bargs = GetTypeArguments (b); if (aargs.Length != bargs.Length) return false; for (int i = 0; i < aargs.Length; i++) { if (!IsSignatureEqual (aargs [i], bargs [i])) return false; } return true; } return false; } // // Returns whether the array of memberinfos contains the given method // public static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method, bool ignoreDeclType) { Type [] new_args = TypeManager.GetParameterData (new_method).Types; foreach (MethodBase method in array) { if (!ignoreDeclType && method.DeclaringType != new_method.DeclaringType) continue; if (method.Name != new_method.Name) continue; if (method is MethodInfo && new_method is MethodInfo && !IsSignatureEqual ( TypeToCoreType (((MethodInfo) method).ReturnType), TypeToCoreType (((MethodInfo) new_method).ReturnType))) continue; Type [] old_args = TypeManager.GetParameterData (method).Types; int old_count = old_args.Length; int i; if (new_args.Length != old_count) continue; for (i = 0; i < old_count; i++){ if (!IsSignatureEqual (old_args [i], new_args [i])) break; } if (i != old_count) continue; return true; } return false; } // // We copy methods from `new_members' into `target_list' if the signature // for the method from in the new list does not exist in the target_list // // The name is assumed to be the same. // public static ArrayList CopyNewMethods (ArrayList target_list, IList new_members) { if (target_list == null){ target_list = new ArrayList (); foreach (MemberInfo mi in new_members){ if (mi is MethodBase) target_list.Add (mi); } return target_list; } MemberInfo [] target_array = new MemberInfo [target_list.Count]; target_list.CopyTo (target_array, 0); foreach (MemberInfo mi in new_members){ MethodBase new_method = (MethodBase) mi; if (!ArrayContainsMethod (target_array, new_method, true)) target_list.Add (new_method); } return target_list; } #region Generics // // Tracks the generic parameters. // static PtrHashtable builder_to_type_param; public static void AddTypeParameter (Type t, TypeParameter tparam) { if (!builder_to_type_param.Contains (t)) builder_to_type_param.Add (t, tparam); } public static TypeParameter LookupTypeParameter (Type t) { return (TypeParameter) builder_to_type_param [t]; } // This method always return false for non-generic compiler, // while Type.IsGenericParameter is returned if it is supported. public static bool IsGenericParameter (Type type) { #if GMCS_SOURCE return type.IsGenericParameter; #else return false; #endif } public static int GenericParameterPosition (Type type) { #if GMCS_SOURCE return type.GenericParameterPosition; #else throw new InternalErrorException ("should not be called"); #endif } public static bool IsGenericType (Type type) { #if GMCS_SOURCE return type.IsGenericType; #else return false; #endif } public static bool IsGenericTypeDefinition (Type type) { #if GMCS_SOURCE return type.IsGenericTypeDefinition; #else return false; #endif } public static bool ContainsGenericParameters (Type type) { #if GMCS_SOURCE return type.ContainsGenericParameters; #else return false; #endif } public static FieldInfo GetGenericFieldDefinition (FieldInfo fi) { #if GMCS_SOURCE if (fi.DeclaringType.IsGenericTypeDefinition || !fi.DeclaringType.IsGenericType) return fi; Type t = fi.DeclaringType.GetGenericTypeDefinition (); BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly; // TODO: use CodeGen.Module.Builder.ResolveField (fi.MetadataToken); foreach (FieldInfo f in t.GetFields (bf)) if (f.MetadataToken == fi.MetadataToken) return f; #endif return fi; } public static bool IsEqual (Type a, Type b) { if (a.Equals (b)) { // MS BCL returns true even if enum types are different if (a.BaseType == TypeManager.enum_type || b.BaseType == TypeManager.enum_type) return a.FullName == b.FullName; // Some types are never equal if (a == TypeManager.null_type || a == InternalType.AnonymousMethod) return false; return true; } if (IsGenericParameter (a) && IsGenericParameter (b)) { // TODO: needs more testing before cleaning up //if (a.DeclaringMethod != b.DeclaringMethod && // (a.DeclaringMethod == null || b.DeclaringMethod == null)) // return false; #if GMCS_SOURCE return a.GenericParameterPosition == b.GenericParameterPosition; #else throw new NotSupportedException (); #endif } if (a.IsArray && b.IsArray) { if (a.GetArrayRank () != b.GetArrayRank ()) return false; return IsEqual (GetElementType (a), GetElementType (b)); } if (a.IsByRef && b.IsByRef) return IsEqual (a.GetElementType (), b.GetElementType ()); if (IsGenericType (a) && IsGenericType (b)) { Type adef = DropGenericTypeArguments (a); Type bdef = DropGenericTypeArguments (b); if (adef != bdef) return false; if (adef.IsEnum && bdef.IsEnum) return true; Type[] aargs = GetTypeArguments (a); Type[] bargs = GetTypeArguments (b); if (aargs.Length != bargs.Length) return false; for (int i = 0; i < aargs.Length; i++) { if (!IsEqual (aargs [i], bargs [i])) return false; } return true; } return false; } public static bool IsEqual (Type[] a, Type[] b) { if (a == null || b == null || a.Length != b.Length) return false; for (int i = 0; i < a.Length; ++i) { if (a [i] == null || b [i] == null) { if (a [i] == b [i]) continue; return false; } if (!IsEqual (a [i], b [i])) return false; } return true; } public static Type DropGenericTypeArguments (Type t) { #if GMCS_SOURCE if (!t.IsGenericType) return t; // Micro-optimization: a generic typebuilder is always a generic type definition if (t is TypeBuilder) return t; return t.GetGenericTypeDefinition (); #else return t; #endif } public static MethodBase DropGenericMethodArguments (MethodBase m) { #if GMCS_SOURCE if (m.IsGenericMethod) m = ((MethodInfo) m).GetGenericMethodDefinition (); Type t = m.DeclaringType; if (!t.IsGenericType || t.IsGenericTypeDefinition) return m; t = t.GetGenericTypeDefinition (); BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly; #if MS_COMPATIBLE // TODO: use CodeGen.Module.Builder.ResolveMethod () return m; #endif if (m is ConstructorInfo) { foreach (ConstructorInfo c in t.GetConstructors (bf)) if (c.MetadataToken == m.MetadataToken) return c; } else { foreach (MethodBase mb in t.GetMethods (bf)) if (mb.MetadataToken == m.MetadataToken) return mb; } #endif return m; } public static Type[] GetGenericArguments (MethodBase mi) { #if GMCS_SOURCE return mi.GetGenericArguments (); #else return Type.EmptyTypes; #endif } public static Type[] GetTypeArguments (Type t) { #if GMCS_SOURCE DeclSpace tc = LookupDeclSpace (t); if (tc != null) { if (!tc.IsGeneric) return Type.EmptyTypes; TypeParameter[] tparam = tc.TypeParameters; Type[] ret = new Type [tparam.Length]; for (int i = 0; i < tparam.Length; i++) { ret [i] = tparam [i].Type; if (ret [i] == null) throw new InternalErrorException (); } return ret; } else return t.GetGenericArguments (); #else throw new InternalErrorException (); #endif } public static GenericConstraints GetTypeParameterConstraints (Type t) { #if GMCS_SOURCE if (!t.IsGenericParameter) throw new InvalidOperationException (); TypeParameter tparam = LookupTypeParameter (t); if (tparam != null) return tparam.GenericConstraints; return ReflectionConstraints.GetConstraints (t); #else throw new InternalErrorException (); #endif } public static bool HasGenericArguments (Type t) { return GetNumberOfTypeArguments (t) > 0; } public static int GetNumberOfTypeArguments (Type t) { #if GMCS_SOURCE if (t.IsGenericParameter) return 0; DeclSpace tc = LookupDeclSpace (t); if (tc != null) return tc.IsGeneric ? tc.CountTypeParameters : 0; else return t.IsGenericType ? t.GetGenericArguments ().Length : 0; #else return 0; #endif } /// /// Check whether `type' and `parent' are both instantiations of the same /// generic type. Note that we do not check the type parameters here. /// public static bool IsInstantiationOfSameGenericType (Type type, Type parent) { int tcount = GetNumberOfTypeArguments (type); int pcount = GetNumberOfTypeArguments (parent); if (tcount != pcount) return false; type = DropGenericTypeArguments (type); parent = DropGenericTypeArguments (parent); return type.Equals (parent); } /// /// Whether `mb' is a generic method definition. /// public static bool IsGenericMethodDefinition (MethodBase mb) { #if GMCS_SOURCE if (mb.DeclaringType is TypeBuilder) { IMethodData method = (IMethodData) builder_to_method [mb]; if (method == null) return false; return method.GenericMethod != null; } return mb.IsGenericMethodDefinition; #else return false; #endif } /// /// Whether `mb' is a generic method. /// public static bool IsGenericMethod (MethodBase mb) { #if GMCS_SOURCE return mb.IsGenericMethod; #else return false; #endif } public static bool IsNullableType (Type t) { #if GMCS_SOURCE return generic_nullable_type == DropGenericTypeArguments (t); #else return false; #endif } #endregion #region MemberLookup implementation // // Whether we allow private members in the result (since FindMembers // uses NonPublic for both protected and private), we need to distinguish. // internal class Closure { internal bool private_ok; // Who is invoking us and which type is being queried currently. internal Type invocation_type; internal Type qualifier_type; // The assembly that defines the type is that is calling us internal Assembly invocation_assembly; internal IList almost_match; private bool CheckValidFamilyAccess (bool is_static, MemberInfo m) { if (invocation_type == null) return false; if (is_static && qualifier_type == null) // It resolved from a simple name, so it should be visible. return true; if (IsNestedChildOf (invocation_type, m.DeclaringType)) return true; for (Type t = invocation_type; t != null; t = t.DeclaringType) { if (!IsFamilyAccessible (t, m.DeclaringType)) continue; // Although a derived class can access protected members of its base class // it cannot do so through an instance of the base class (CS1540). // => Ancestry should be: declaring_type ->* invocation_type ->* qualified_type if (is_static || qualifier_type == null || IsInstantiationOfSameGenericType (t, qualifier_type) || IsFamilyAccessible (qualifier_type, t)) return true; } if (almost_match != null) almost_match.Add (m); return false; } // // This filter filters by name + whether it is ok to include private // members in the search // internal bool Filter (MemberInfo m, object filter_criteria) { // // Hack: we know that the filter criteria will always be in the // `closure' // fields. // if ((filter_criteria != null) && (m.Name != (string) filter_criteria)) return false; if (((qualifier_type == null) || (qualifier_type == invocation_type)) && (invocation_type != null) && IsPrivateAccessible (m.DeclaringType, invocation_type)) return true; // // Ugly: we need to find out the type of `m', and depending // on this, tell whether we accept or not // if (m is MethodBase){ MethodBase mb = (MethodBase) m; MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask; if (ma == MethodAttributes.Public) return true; if (ma == MethodAttributes.PrivateScope) return false; if (ma == MethodAttributes.Private) return private_ok || IsPrivateAccessible (invocation_type, m.DeclaringType) || IsNestedChildOf (invocation_type, m.DeclaringType); if (TypeManager.IsThisOrFriendAssembly (mb.DeclaringType.Assembly)) { if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamORAssem) return true; } else { if (ma == MethodAttributes.Assembly || ma == MethodAttributes.FamANDAssem) return false; } // Family, FamORAssem or FamANDAssem return CheckValidFamilyAccess (mb.IsStatic, m); } if (m is FieldInfo){ FieldInfo fi = (FieldInfo) m; FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask; if (fa == FieldAttributes.Public) return true; if (fa == FieldAttributes.PrivateScope) return false; if (fa == FieldAttributes.Private) return private_ok || IsPrivateAccessible (invocation_type, m.DeclaringType) || IsNestedChildOf (invocation_type, m.DeclaringType); if (TypeManager.IsThisOrFriendAssembly (fi.DeclaringType.Assembly)) { if ((fa == FieldAttributes.Assembly) || (fa == FieldAttributes.FamORAssem)) return true; } else { if ((fa == FieldAttributes.Assembly) || (fa == FieldAttributes.FamANDAssem)) return false; } // Family, FamORAssem or FamANDAssem return CheckValidFamilyAccess (fi.IsStatic, m); } // // EventInfos and PropertyInfos, return true because they lack // permission information, so we need to check later on the methods. // return true; } } static Closure closure; static MemberFilter FilterWithClosure_delegate; // // Looks up a member called `name' in the `queried_type'. This lookup // is done by code that is contained in the definition for `invocation_type' // through a qualifier of type `qualifier_type' (or null if there is no qualifier). // // `invocation_type' is used to check whether we're allowed to access the requested // member wrt its protection level. // // When called from MemberAccess, `qualifier_type' is the type which is used to access // the requested member (`class B { A a = new A (); a.foo = 5; }'; here invocation_type // is B and qualifier_type is A). This is used to do the CS1540 check. // // When resolving a SimpleName, `qualifier_type' is null. // // The `qualifier_type' is used for the CS1540 check; it's normally either null or // the same than `queried_type' - except when we're being called from BaseAccess; // in this case, `invocation_type' is the current type and `queried_type' the base // type, so this'd normally trigger a CS1540. // // The binding flags are `bf' and the kind of members being looked up are `mt' // // The return value always includes private members which code in `invocation_type' // is allowed to access (using the specified `qualifier_type' if given); only use // BindingFlags.NonPublic to bypass the permission check. // // The 'almost_match' argument is used for reporting error CS1540. // // Returns an array of a single element for everything but Methods/Constructors // that might return multiple matches. // public static MemberInfo [] MemberLookup (Type invocation_type, Type qualifier_type, Type queried_type, MemberTypes mt, BindingFlags original_bf, string name, IList almost_match) { Timer.StartTimer (TimerType.MemberLookup); MemberInfo[] retval = RealMemberLookup (invocation_type, qualifier_type, queried_type, mt, original_bf, name, almost_match); Timer.StopTimer (TimerType.MemberLookup); return retval; } static MemberInfo [] RealMemberLookup (Type invocation_type, Type qualifier_type, Type queried_type, MemberTypes mt, BindingFlags original_bf, string name, IList almost_match) { BindingFlags bf = original_bf; ArrayList method_list = null; Type current_type = queried_type; bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0; bool skip_iface_check = true, used_cache = false; bool always_ok_flag = invocation_type != null && IsNestedChildOf (invocation_type, queried_type); closure.invocation_type = invocation_type; closure.invocation_assembly = invocation_type != null ? invocation_type.Assembly : null; closure.qualifier_type = qualifier_type; closure.almost_match = almost_match; // This is from the first time we find a method // in most cases, we do not actually find a method in the base class // so we can just ignore it, and save the arraylist allocation MemberInfo [] first_members_list = null; bool use_first_members_list = false; do { MemberInfo [] list; // // `NonPublic' is lame, because it includes both protected and // private methods, so we need to control this behavior by // explicitly tracking if a private method is ok or not. // // The possible cases are: // public, private and protected (internal does not come into the // equation) // if ((invocation_type != null) && ((invocation_type == current_type) || IsNestedChildOf (invocation_type, current_type)) || always_ok_flag) bf = original_bf | BindingFlags.NonPublic; else bf = original_bf; closure.private_ok = (original_bf & BindingFlags.NonPublic) != 0; Timer.StopTimer (TimerType.MemberLookup); list = MemberLookup_FindMembers (current_type, mt, bf, name, out used_cache); Timer.StartTimer (TimerType.MemberLookup); // // When queried for an interface type, the cache will automatically check all // inherited members, so we don't need to do this here. However, this only // works if we already used the cache in the first iteration of this loop. // // If we used the cache in any further iteration, we can still terminate the // loop since the cache always looks in all base classes. // if (used_cache) searching = false; else skip_iface_check = false; if (current_type == TypeManager.object_type) searching = false; else { current_type = current_type.BaseType; // // This happens with interfaces, they have a null // basetype. Look members up in the Object class. // if (current_type == null) { current_type = TypeManager.object_type; searching = true; } } if (list.Length == 0) continue; // // Events and types are returned by both `static' and `instance' // searches, which means that our above FindMembers will // return two copies of the same. // if (list.Length == 1 && !(list [0] is MethodBase)){ return list; } // // Multiple properties: we query those just to find out the indexer // name // if (list [0] is PropertyInfo) return list; // // We found an event: the cache lookup returns both the event and // its private field. // if (list [0] is EventInfo) { if ((list.Length == 2) && (list [1] is FieldInfo)) return new MemberInfo [] { list [0] }; return list; } // // We found methods, turn the search into "method scan" // mode. // if (first_members_list != null) { if (use_first_members_list) { method_list = CopyNewMethods (method_list, first_members_list); use_first_members_list = false; } method_list = CopyNewMethods (method_list, list); } else { first_members_list = list; use_first_members_list = true; mt &= (MemberTypes.Method | MemberTypes.Constructor); } } while (searching); if (use_first_members_list) return first_members_list; if (method_list != null && method_list.Count > 0) { return (MemberInfo []) method_list.ToArray (typeof (MemberInfo)); } // // This happens if we already used the cache in the first iteration, in this case // the cache already looked in all interfaces. // if (skip_iface_check) return null; // // Interfaces do not list members they inherit, so we have to // scan those. // if (!queried_type.IsInterface) return null; if (queried_type.IsArray) queried_type = TypeManager.array_type; Type [] ifaces = GetInterfaces (queried_type); if (ifaces == null) return null; foreach (Type itype in ifaces){ MemberInfo [] x; x = MemberLookup (null, null, itype, mt, bf, name, null); if (x != null) return x; } return null; } public const BindingFlags AllMembers = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly; // Currently is designed to work with external types only public static PropertyInfo GetPropertyFromAccessor (MethodBase mb) { if (!mb.IsSpecialName) return null; string name = mb.Name; if (name.Length < 5) return null; if (name [3] != '_') return null; if (name.StartsWith ("get") || name.StartsWith ("set")) { MemberInfo[] pi = mb.DeclaringType.FindMembers (MemberTypes.Property, AllMembers, Type.FilterName, name.Substring (4)); if (pi == null) return null; // This can happen when property is indexer (it can have same name but different parameters) foreach (PropertyInfo p in pi) { foreach (MethodInfo p_mi in p.GetAccessors (true)) { if (p_mi == mb || TypeManager.GetParameterData (p_mi).Equals (TypeManager.GetParameterData (mb))) return p; } } } return null; } // Currently is designed to work with external types only public static MemberInfo GetEventFromAccessor (MethodBase mb) { if (!mb.IsSpecialName) return null; string name = mb.Name; if (name.Length < 5) return null; if (name.StartsWith ("add_")) return mb.DeclaringType.GetEvent (name.Substring (4), AllMembers); if (name.StartsWith ("remove_")) return mb.DeclaringType.GetEvent (name.Substring (7), AllMembers); return null; } // Tests whether external method is really special public static bool IsSpecialMethod (MethodBase mb) { if (!mb.IsSpecialName) return false; IMethodData md = TypeManager.GetMethod (mb); if (md != null) return (md is AbstractPropertyEventMethod || md is Operator); PropertyInfo pi = GetPropertyFromAccessor (mb); if (pi != null) return IsValidProperty (pi); if (GetEventFromAccessor (mb) != null) return true; string name = mb.Name; if (name.StartsWith ("op_")) return Operator.GetName (name) != null; return false; } // Tests whether imported property is valid C# property. // TODO: It seems to me that we should do a lot of sanity tests before // we accept property as C# property static bool IsValidProperty (PropertyInfo pi) { MethodInfo get_method = pi.GetGetMethod (true); MethodInfo set_method = pi.GetSetMethod (true); int g_count = 0; int s_count = 0; if (get_method != null && set_method != null) { g_count = get_method.GetParameters ().Length; s_count = set_method.GetParameters ().Length; if (g_count + 1 != s_count) return false; } else if (get_method != null) { g_count = get_method.GetParameters ().Length; } else if (set_method != null) { s_count = set_method.GetParameters ().Length; } // // DefaultMemberName and indexer name has to match to identify valid C# indexer // PredefinedAttribute pa = PredefinedAttributes.Get.DefaultMember; if ((s_count > 1 || g_count > 0) && pa.IsDefined) { object[] o = pi.DeclaringType.GetCustomAttributes (pa.Type, false); if (o.Length == 0) return false; DefaultMemberAttribute dma = (DefaultMemberAttribute) o [0]; if (dma.MemberName != pi.Name) return false; if (get_method != null && "get_" + dma.MemberName != get_method.Name) return false; if (set_method != null && "set_" + dma.MemberName != set_method.Name) return false; } return true; } #endregion } class InternalType { public static readonly Type AnonymousMethod = typeof (AnonymousMethodBody); public static readonly Type Arglist = typeof (ArglistAccess); public static readonly Type Dynamic = new DynamicType (); public static readonly Type MethodGroup = typeof (MethodGroupExpr); } /// /// There is exactly one instance of this class per type. /// public sealed class TypeHandle : IMemberContainer { public readonly IMemberContainer BaseType; readonly int id = ++next_id; static int next_id = 0; static TypeHandle () { Reset (); } /// /// Lookup a TypeHandle instance for the given type. If the type doesn't have /// a TypeHandle yet, a new instance of it is created. This static method /// ensures that we'll only have one TypeHandle instance per type. /// private static TypeHandle GetTypeHandle (Type t) { TypeHandle handle = (TypeHandle) type_hash [t]; if (handle != null) return handle; handle = new TypeHandle (t); type_hash.Add (t, handle); return handle; } public static MemberCache GetMemberCache (Type t) { return GetTypeHandle (t).MemberCache; } public static void CleanUp () { type_hash = null; } public static void Reset () { type_hash = new PtrHashtable (); } /// /// Returns the TypeHandle for TypeManager.object_type. /// public static IMemberContainer ObjectType { get { if (object_type != null) return object_type; object_type = GetTypeHandle (TypeManager.object_type); return object_type; } } /// /// Returns the TypeHandle for TypeManager.array_type. /// public static TypeHandle ArrayType { get { if (array_type != null) return array_type; array_type = GetTypeHandle (TypeManager.array_type); return array_type; } } private static PtrHashtable type_hash; private static TypeHandle object_type = null; private static TypeHandle array_type = null; private Type type; private string full_name; private bool is_interface; private MemberCache member_cache; private MemberCache base_cache; private TypeHandle (Type type) { this.type = type; full_name = type.FullName != null ? type.FullName : type.Name; if (type.BaseType != null) { base_cache = TypeManager.LookupMemberCache (type.BaseType); BaseType = base_cache.Container; } else if (type.IsInterface) base_cache = TypeManager.LookupBaseInterfacesCache (type); this.is_interface = type.IsInterface || TypeManager.IsGenericParameter (type); this.member_cache = new MemberCache (this); } // IMemberContainer methods public string Name { get { return full_name; } } public Type Type { get { return type; } } public MemberCache BaseCache { get { return base_cache; } } public bool IsInterface { get { return is_interface; } } public MemberList GetMembers (MemberTypes mt, BindingFlags bf) { MemberInfo [] members; if (type is GenericTypeParameterBuilder) return MemberList.Empty; #if MS_COMPATIBLE type = TypeManager.DropGenericTypeArguments (type); #endif if (mt == MemberTypes.Event) members = type.GetEvents (bf | BindingFlags.DeclaredOnly); else members = type.FindMembers (mt, bf | BindingFlags.DeclaredOnly, null, null); if (members.Length == 0) return MemberList.Empty; Array.Reverse (members); return new MemberList (members); } // IMemberFinder methods public MemberList FindMembers (MemberTypes mt, BindingFlags bf, string name, MemberFilter filter, object criteria) { return new MemberList (member_cache.FindMembers (mt, bf, name, filter, criteria)); } public MemberCache MemberCache { get { return member_cache; } } public override string ToString () { if (BaseType != null) return "TypeHandle (" + id + "," + Name + " : " + BaseType + ")"; else return "TypeHandle (" + id + "," + Name + ")"; } } }