X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Ftypemanager.cs;h=21f59ee8df73401a25b749cb70f29effc889dcf7;hb=9f5d5cc3b2d87bd771585b5bd94986216c8d234b;hp=355fd3208c0f21e0473a38c404229b71d05226e0;hpb=f0a7e4a0427dad1ed85e5ecad7afa0d073465763;p=mono.git diff --git a/mcs/mcs/typemanager.cs b/mcs/mcs/typemanager.cs index 355fd3208c0..21f59ee8df7 100755 --- a/mcs/mcs/typemanager.cs +++ b/mcs/mcs/typemanager.cs @@ -2,17 +2,23 @@ // typemanager.cs: C# type manager // // Author: Miguel de Icaza (miguel@gnu.org) +// Ravi Pratap (ravi@ximian.com) // // Licensed under the terms of the GNU GPL // // (C) 2001 Ximian, Inc (http://www.ximian.com) // // +#define CACHE using System; +using System.Globalization; using System.Collections; using System.Reflection; using System.Reflection.Emit; +using System.Text.RegularExpressions; +using System.Runtime.CompilerServices; +using System.Diagnostics; namespace Mono.CSharp { @@ -30,6 +36,7 @@ public class TypeManager { static public Type float_type; static public Type double_type; static public Type char_type; + static public Type char_ptr_type; static public Type short_type; static public Type decimal_type; static public Type bool_type; @@ -53,15 +60,25 @@ public class TypeManager { static public Type intptr_type; static public Type monitor_type; static public Type runtime_field_handle_type; + static public Type attribute_type; static public Type attribute_usage_type; static public Type dllimport_type; + static public Type unverifiable_code_type; static public Type methodimpl_attr_type; + static public Type marshal_as_attr_type; static public Type param_array_type; + static public Type void_ptr_type; + static public Type indexer_name_type; + static public object obsolete_attribute_type; + static public object conditional_attribute_type; + + static public Type [] NoTypes; + // // Internal, not really used outside // - Type runtime_helpers_type; + static Type runtime_helpers_type; // // These methods are called by code generated by the compiler @@ -79,48 +96,58 @@ public class TypeManager { static public MethodInfo int_getlength_int; static public MethodInfo delegate_combine_delegate_delegate; static public MethodInfo delegate_remove_delegate_delegate; + static public MethodInfo int_get_offset_to_string_data; + static public MethodInfo int_array_get_length; // // The attribute constructors. // static public ConstructorInfo cons_param_array_attribute; + static public ConstructorInfo void_decimal_ctor_five_args; + static public ConstructorInfo unverifiable_code_ctor; // // Holds the Array of Assemblies that have been loaded // (either because it is the default or the user used the // -r command line option) // - ArrayList assemblies; + static Assembly [] assemblies; // // Keeps a list of module builders. We used this to do lookups // on the modulebuilder using GetType -- needed for arrays // - ArrayList modules; + static ModuleBuilder [] modules; // // This is the type_cache from the assemblies to avoid // hitting System.Reflection on every lookup. // - Hashtable types; + static Hashtable types; // // This is used to hotld the corresponding TypeContainer objects // since we need this in FindMembers // - Hashtable typecontainers; + static Hashtable typecontainers; // // Keeps track of those types that are defined by the // user's program // - ArrayList user_types; + static ArrayList user_types; // // Keeps a mapping between TypeBuilders and their TypeContainers // static PtrHashtable builder_to_container; + // + // Tracks the interfaces implemented by typebuilders. We only + // enter those who do implement or or more interfaces + // + static PtrHashtable builder_to_ifaces; + // // Maps MethodBase.RuntimeTypeHandle to a Type array that contains // the arguments to the method @@ -153,59 +180,144 @@ public class TypeManager { static Hashtable builder_to_attr; - public TypeManager () + struct Signature { + public string name; + public Type [] args; + } + + /// + /// A filter for Findmembers that uses the Signature object to + /// extract objects + /// + static bool SignatureFilter (MemberInfo mi, object criteria) + { + Signature sig = (Signature) criteria; + + if (!(mi is MethodBase)) + return false; + + if (mi.Name != sig.name) + return false; + + int count = sig.args.Length; + + if (mi is MethodBuilder || mi is ConstructorBuilder){ + Type [] candidate_args = GetArgumentTypes ((MethodBase) mi); + + if (candidate_args.Length != count) + return false; + + for (int i = 0; i < count; i++) + if (candidate_args [i] != sig.args [i]) + return false; + + return true; + } else { + ParameterInfo [] pars = ((MethodBase) mi).GetParameters (); + + if (pars.Length != count) + return false; + + for (int i = 0; i < count; i++) + if (pars [i].ParameterType != sig.args [i]) + return false; + return true; + } + } + + // A delegate that points to the filter above. + static MemberFilter signature_filter; + + static TypeManager () { - assemblies = new ArrayList (); - modules = new ArrayList (); + assemblies = new Assembly [0]; + modules = null; user_types = new ArrayList (); + types = new Hashtable (); typecontainers = new Hashtable (); + builder_to_interface = new PtrHashtable (); builder_to_delegate = new PtrHashtable (); builder_to_enum = new PtrHashtable (); builder_to_attr = new PtrHashtable (); - } - - static TypeManager () - { method_arguments = new PtrHashtable (); method_internal_params = new PtrHashtable (); builder_to_container = new PtrHashtable (); - type_interface_cache = new PtrHashtable (); + builder_to_ifaces = new PtrHashtable (); + + NoTypes = new Type [0]; + + signature_filter = new MemberFilter (SignatureFilter); } - public void AddUserType (string name, TypeBuilder t) + public static void AddUserType (string name, TypeBuilder t, Type [] ifaces) { - types.Add (name, t); + try { + types.Add (name, t); + } catch { + Type prev = (Type) types [name]; + TypeContainer tc = (TypeContainer) builder_to_container [prev]; + + if (tc != null){ + // + // This probably never happens, as we catch this before + // + Report.Error (-17, "The type `" + name + "' has already been defined."); + return; + } + + tc = (TypeContainer) builder_to_container [t]; + + Report.Warning ( + 1595, "The type `" + name + "' is defined in an existing assembly;"+ + " Using the new definition from: " + tc.Location); + Report.Warning (1595, "Previously defined in: " + prev.Assembly.FullName); + + types.Remove (name); + types.Add (name, t); + } user_types.Add (t); + + if (ifaces != null) + builder_to_ifaces [t] = ifaces; + } + + // + // This entry point is used by types that we define under the covers + // + public static void RegisterBuilder (TypeBuilder tb, Type [] ifaces) + { + if (ifaces != null) + builder_to_ifaces [tb] = ifaces; } - public void AddUserType (string name, TypeBuilder t, TypeContainer tc) + public static void AddUserType (string name, TypeBuilder t, TypeContainer tc, Type [] ifaces) { - AddUserType (name, t); builder_to_container.Add (t, tc); typecontainers.Add (name, tc); + AddUserType (name, t, ifaces); } - public void AddDelegateType (string name, TypeBuilder t, Delegate del) + public static void AddDelegateType (string name, TypeBuilder t, Delegate del) { types.Add (name, t); builder_to_delegate.Add (t, del); } - public void AddEnumType (string name, TypeBuilder t, Enum en) + public static void AddEnumType (string name, TypeBuilder t, Enum en) { types.Add (name, t); builder_to_enum.Add (t, en); } - public void AddUserInterface (string name, TypeBuilder t, Interface i) + public static void AddUserInterface (string name, TypeBuilder t, Interface i, Type [] ifaces) { - AddUserType (name, t); + AddUserType (name, t, ifaces); builder_to_interface.Add (t, i); } - public void RegisterAttrType (Type t, TypeContainer tc) + public static void RegisterAttrType (Type t, TypeContainer tc) { builder_to_attr.Add (t, tc); } @@ -219,7 +331,7 @@ public class TypeManager { return (TypeContainer) builder_to_container [t]; } - public Interface LookupInterface (Type t) + public static Interface LookupInterface (Type t) { return (Interface) builder_to_interface [t]; } @@ -242,23 +354,35 @@ public class TypeManager { /// /// Registers an assembly to load types from. /// - public void AddAssembly (Assembly a) + public static void AddAssembly (Assembly a) { - assemblies.Add (a); + int top = assemblies.Length; + Assembly [] n = new Assembly [top + 1]; + + assemblies.CopyTo (n, 0); + + n [top] = a; + assemblies = n; } /// /// Registers a module builder to lookup types from /// - public void AddModule (ModuleBuilder mb) + public static void AddModule (ModuleBuilder mb) { - modules.Add (mb); + int top = modules != null ? modules.Length : 0; + ModuleBuilder [] n = new ModuleBuilder [top + 1]; + + if (modules != null) + modules.CopyTo (n, 0); + n [top] = mb; + modules = n; } /// /// Returns the Type associated with @name /// - public Type LookupType (string name) + public static Type LookupType (string name) { Type t; @@ -286,7 +410,7 @@ public class TypeManager { return t; } } - + return null; } @@ -295,47 +419,64 @@ public class TypeManager { /// static public string CSharpName (Type t) { - if (t == int32_type) - return "int"; - else if (t == uint32_type) - return "uint"; - else if (t == int64_type) - return "long"; - else if (t == uint64_type) - return "ulong"; - else if (t == float_type) - return "float"; - else if (t == double_type) - return "double"; - else if (t == char_type) - return "char"; - else if (t == short_type) - return "short"; - else if (t == decimal_type) - return "decimal"; - else if (t == bool_type) - return "bool"; - else if (t == sbyte_type) - return "sbyte"; - else if (t == byte_type) - return "byte"; - else if (t == short_type) - return "short"; - else if (t == ushort_type) - return "ushort"; - else if (t == string_type) - return "string"; - else if (t == object_type) - return "object"; - else - return t.FullName; + return Regex.Replace (t.FullName, + @"^System\." + + @"(Int32|UInt32|Int16|Uint16|Int64|UInt64|" + + @"Single|Double|Char|Decimal|Byte|SByte|Object|" + + @"Boolean|String|Void)" + + @"(\W+|\b)", + new MatchEvaluator (CSharpNameMatch)); + } + + static String CSharpNameMatch (Match match) + { + string s = match.Groups [1].Captures [0].Value; + return s.ToLower (). + Replace ("int32", "int"). + Replace ("uint32", "uint"). + Replace ("int16", "short"). + Replace ("uint16", "ushort"). + Replace ("int64", "long"). + Replace ("uint64", "ulong"). + Replace ("single", "float"). + Replace ("boolean", "bool") + + match.Groups [2].Captures [0].Value; } + /// + /// Returns the signature of the method + /// + static public string CSharpSignature (MethodBase mb) + { + string sig = "("; + + // + // FIXME: We should really have a single function to do + // everything instead of the following 5 line pattern + // + ParameterData iparams = LookupParametersByBuilder (mb); + + if (iparams == null){ + ParameterInfo [] pi = mb.GetParameters (); + iparams = new ReflectionParameters (pi); + } + + for (int i = 0; i < iparams.Count; i++) { + if (i > 0) { + sig += ", "; + } + sig += iparams.ParameterDesc(i); + } + sig += ")"; + + return mb.DeclaringType.Name + "." + mb.Name + sig; + } + /// /// Looks up a type, and aborts if it is not found. This is used /// by types required by the compiler /// - Type CoreLookupType (string name) + static Type CoreLookupType (string name) { Type t = LookupType (name); @@ -351,24 +492,57 @@ public class TypeManager { /// Returns the MethodInfo for a method named `name' defined /// in type `t' which takes arguments of types `args' /// - MethodInfo GetMethod (Type t, string name, Type [] args) + static MethodInfo GetMethod (Type t, string name, Type [] args) { - MethodInfo mi = t.GetMethod (name, args); + MemberInfo [] mi; + Signature sig; - if (mi == null) - throw new Exception ("Can not find the core function `" + name + "'"); + sig.name = name; + sig.args = args; + + mi = FindMembers ( + t, MemberTypes.Method, + instance_and_static | BindingFlags.Public, signature_filter, sig); + if (mi == null || mi.Length == 0 || !(mi [0] is MethodInfo)){ + Report.Error (-19, "Can not find the core function `" + name + "'"); + return null; + } - return mi; + return (MethodInfo) mi [0]; } - ConstructorInfo GetConstructor (Type t, Type [] args) + /// + /// Returns the ConstructorInfo for "args" + /// + static ConstructorInfo GetConstructor (Type t, Type [] args) { - ConstructorInfo ci = t.GetConstructor (args); + MemberInfo [] mi; + Signature sig; + + sig.name = ".ctor"; + sig.args = args; + + mi = FindMembers (t, MemberTypes.Constructor, + instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly, signature_filter, sig); + if (mi == null || mi.Length == 0 || !(mi [0] is ConstructorInfo)){ + Report.Error (-19, "Can not find the core constructor for type `" + t.Name + "'"); + return null; + } + + return (ConstructorInfo) mi [0]; + } - if (ci == null) - throw new Exception ("Can not find the core constructor for `" + t.FullName + "'"); + public static void InitEnumUnderlyingTypes () + { - return ci; + int32_type = CoreLookupType ("System.Int32"); + int64_type = CoreLookupType ("System.Int64"); + uint32_type = CoreLookupType ("System.UInt32"); + uint64_type = CoreLookupType ("System.UInt64"); + byte_type = CoreLookupType ("System.Byte"); + sbyte_type = CoreLookupType ("System.SByte"); + short_type = CoreLookupType ("System.Int16"); + ushort_type = CoreLookupType ("System.UInt16"); } /// @@ -376,22 +550,18 @@ public class TypeManager { /// population of the type has happened (for example, to /// bootstrap the corlib.dll /// - public void InitCoreTypes () + public static void InitCoreTypes () { object_type = CoreLookupType ("System.Object"); value_type = CoreLookupType ("System.ValueType"); + + InitEnumUnderlyingTypes (); + + char_type = CoreLookupType ("System.Char"); string_type = CoreLookupType ("System.String"); - int32_type = CoreLookupType ("System.Int32"); - int64_type = CoreLookupType ("System.Int64"); - uint32_type = CoreLookupType ("System.UInt32"); - uint64_type = CoreLookupType ("System.UInt64"); float_type = CoreLookupType ("System.Single"); double_type = CoreLookupType ("System.Double"); - byte_type = CoreLookupType ("System.Byte"); - sbyte_type = CoreLookupType ("System.SByte"); - char_type = CoreLookupType ("System.Char"); - short_type = CoreLookupType ("System.Int16"); - ushort_type = CoreLookupType ("System.UInt16"); + char_ptr_type = CoreLookupType ("System.Char*"); decimal_type = CoreLookupType ("System.Decimal"); bool_type = CoreLookupType ("System.Boolean"); enum_type = CoreLookupType ("System.Enum"); @@ -415,11 +585,31 @@ public class TypeManager { monitor_type = CoreLookupType ("System.Threading.Monitor"); intptr_type = CoreLookupType ("System.IntPtr"); + attribute_type = CoreLookupType ("System.Attribute"); attribute_usage_type = CoreLookupType ("System.AttributeUsageAttribute"); dllimport_type = CoreLookupType ("System.Runtime.InteropServices.DllImportAttribute"); methodimpl_attr_type = CoreLookupType ("System.Runtime.CompilerServices.MethodImplAttribute"); - param_array_type = CoreLookupType ("System.ParamArrayAttribute"); - + marshal_as_attr_type = CoreLookupType ("System.Runtime.InteropServices.MarshalAsAttribute"); + param_array_type = CoreLookupType ("System.ParamArrayAttribute"); + + unverifiable_code_type= CoreLookupType ("System.Security.UnverifiableCodeAttribute"); + + void_ptr_type = CoreLookupType ("System.Void*"); + + indexer_name_type = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute"); + + // + // Attribute types + // + obsolete_attribute_type = CoreLookupType ("System.ObsoleteAttribute"); + conditional_attribute_type = CoreLookupType ("System.Diagnostics.ConditionalAttribute"); + } + + // + // The helper methods that are used by the compiler + // + public static void InitCodeHelpers () + { // // Now load the default methods that we use. // @@ -456,7 +646,11 @@ public class TypeManager { ienumerator_type, "MoveNext", void_arg); void_dispose_void = GetMethod ( idisposable_type, "Dispose", void_arg); - + int_get_offset_to_string_data = GetMethod ( + runtime_helpers_type, "get_OffsetToStringData", void_arg); + int_array_get_length = GetMethod ( + array_type, "get_Length", void_arg); + // // object arguments // @@ -477,19 +671,32 @@ public class TypeManager { Type [] int_arg = { int32_type }; int_getlength_int = GetMethod ( array_type, "GetLength", int_arg); + + // + // Decimal constructors + // + Type [] dec_arg = { int32_type, int32_type, int32_type, bool_type, byte_type }; + void_decimal_ctor_five_args = GetConstructor ( + decimal_type, dec_arg); // // Attributes // cons_param_array_attribute = GetConstructor ( param_array_type, void_arg); + + unverifiable_code_ctor = GetConstructor ( + unverifiable_code_type, void_arg); } const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance; - - public MemberInfo [] FindMembers (Type t, MemberTypes mt, BindingFlags bf, - MemberFilter filter, object criteria) + + // + // FIXME: This can be optimized easily. speedup by having a single builder mapping + // + public static MemberInfo [] FindMembers (Type t, MemberTypes mt, BindingFlags bf, + MemberFilter filter, object criteria) { // // We have to take care of arrays specially, because GetType on @@ -507,10 +714,21 @@ public class TypeManager { 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 i_members; + } + MemberInfo [] s_members = t.FindMembers ( mt, bf & ~BindingFlags.Instance, filter, criteria); - int i_len = i_members.Length; int s_len = s_members.Length; if (i_len > 0 || s_len > 0){ MemberInfo [] both = new MemberInfo [i_len + s_len]; @@ -519,8 +737,12 @@ public class TypeManager { s_members.CopyTo (both, i_len); return both; - } else - return i_members; + } else { + if (i_len > 0) + return i_members; + else + return s_members; + } } return t.FindMembers (mt, bf, filter, criteria); } @@ -593,13 +815,13 @@ public class TypeManager { /// /// Returns the User Defined Types /// - public ArrayList UserTypes { + public static ArrayList UserTypes { get { return user_types; } } - public Hashtable TypeContainers { + public static Hashtable TypeContainers { get { return typecontainers; } @@ -626,18 +848,20 @@ public class TypeManager { return (Const) builder_to_constant [fb]; } - // - // Gigantic work around for stupidity 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. - // + /// + /// 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 bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args) { - if (method_arguments.Contains (mb)) - return false; - + if (args == null) + args = NoTypes; + method_arguments.Add (mb, args); method_internal_params.Add (mb, ip); @@ -646,8 +870,6 @@ public class TypeManager { static public InternalParameters LookupParametersByBuilder (MethodBase mb) { - object o = method_arguments [mb]; - if (! (mb is ConstructorBuilder || mb is MethodBuilder)) return null; @@ -685,13 +907,9 @@ public class TypeManager { // This is a workaround the fact that GetValue is not // supported for dynamic types // - static Hashtable fields; - - static public bool RegisterField (FieldBuilder fb, object value) + static Hashtable fields = new Hashtable (); + static public bool RegisterFieldValue (FieldBuilder fb, object value) { - if (fields == null) - fields = new Hashtable (); - if (fields.Contains (fb)) return false; @@ -705,6 +923,21 @@ public class TypeManager { return fields [fb]; } + static Hashtable fieldbuilders_to_fields = new Hashtable (); + static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f) + { + if (fieldbuilders_to_fields.Contains (fb)) + return false; + + fieldbuilders_to_fields.Add (fb, f); + return true; + } + + static public FieldBase GetField (FieldInfo fb) + { + return (FieldBase) fieldbuilders_to_fields [fb]; + } + static Hashtable events; static public bool RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove) @@ -805,32 +1038,282 @@ public class TypeManager { } else return pi.GetGetMethod (); } - - // - // 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. - // - static Hashtable type_interface_cache; + /// + /// 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 (Type [] base_interfaces) + { + ArrayList new_ifaces = new ArrayList (); + + foreach (Type iface in base_interfaces){ + if (!new_ifaces.Contains (iface)) + new_ifaces.Add (iface); + + Type [] implementing = TypeManager.GetInterfaces (iface); + + 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; + } + + /// + /// This function returns the interfaces in the type `t'. Works with + /// both types and TypeBuilders. + /// + public static Type [] GetInterfaces (Type t) + { + // + // 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){ + Type [] parent_ifaces; + + if (t.BaseType == null) + parent_ifaces = NoTypes; + else + parent_ifaces = GetInterfaces (t.BaseType); + Type [] type_ifaces = (Type []) builder_to_ifaces [t]; + if (type_ifaces == null) + type_ifaces = NoTypes; + + int parent_count = parent_ifaces.Length; + Type [] result = new Type [parent_count + type_ifaces.Length]; + parent_ifaces.CopyTo (result, 0); + type_ifaces.CopyTo (result, parent_count); + + return result; + } else + return t.GetInterfaces (); + } + + /// + /// 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 parents. + // do { - interfaces = t.GetInterfaces (); + interfaces = GetInterfaces (t); - for (int i = interfaces.Length; i > 0; ){ - i--; - if (interfaces [i] == iface) - return true; + if (interfaces != null){ + foreach (Type i in interfaces){ + if (i == iface) + return true; + } } + t = t.BaseType; } while (t != null); return false; } + + // 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) + { + if (!(value is IConvertible)) + throw new ArgumentException (); + + IConvertible convertValue = (IConvertible) value; + CultureInfo ci = CultureInfo.CurrentCulture; + NumberFormatInfo provider = ci.NumberFormat; + + // + // 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. + // + if (conversionType.Equals (typeof (Boolean))) + return (object)(convertValue.ToBoolean (provider)); + else if (conversionType.Equals (typeof (Byte))) + return (object)(convertValue.ToByte (provider)); + else if (conversionType.Equals (typeof (Char))) + return (object)(convertValue.ToChar (provider)); + else if (conversionType.Equals (typeof (DateTime))) + return (object)(convertValue.ToDateTime (provider)); + else if (conversionType.Equals (typeof (Decimal))) + return (object)(convertValue.ToDecimal (provider)); + else if (conversionType.Equals (typeof (Double))) + return (object)(convertValue.ToDouble (provider)); + else if (conversionType.Equals (typeof (Int16))) + return (object)(convertValue.ToInt16 (provider)); + else if (conversionType.Equals (typeof (Int32))) + return (object)(convertValue.ToInt32 (provider)); + else if (conversionType.Equals (typeof (Int64))) + return (object)(convertValue.ToInt64 (provider)); + else if (conversionType.Equals (typeof (SByte))) + return (object)(convertValue.ToSByte (provider)); + else if (conversionType.Equals (typeof (Single))) + return (object)(convertValue.ToSingle (provider)); + else if (conversionType.Equals (typeof (String))) + return (object)(convertValue.ToString (provider)); + else if (conversionType.Equals (typeof (UInt16))) + return (object)(convertValue.ToUInt16 (provider)); + else if (conversionType.Equals (typeof (UInt32))) + return (object)(convertValue.ToUInt32 (provider)); + else if (conversionType.Equals (typeof (UInt64))) + return (object)(convertValue.ToUInt64 (provider)); + else if (conversionType.Equals (typeof (Object))) + return (object)(value); + else + throw new InvalidCastException (); + } + + // + // This is needed, because enumerations from assemblies + // do not report their underlyingtype, but they report + // themselves + // + public static Type EnumToUnderlying (Type t) + { + if (t == TypeManager.enum_type) + return t; + + t = t.UnderlyingSystemType; + if (!TypeManager.IsEnumType (t)) + return t; + if (t is TypeBuilder) { + // slow path needed to compile corlib + if (t == TypeManager.bool_type || + t == TypeManager.byte_type || + t == TypeManager.sbyte_type || + t == TypeManager.char_type || + t == TypeManager.short_type || + t == TypeManager.ushort_type || + t == TypeManager.int32_type || + t == TypeManager.uint32_type || + t == TypeManager.int64_type || + t == TypeManager.uint64_type) + return t; + throw new Exception ("Unhandled typecode in enum " + " from " + t.AssemblyQualifiedName); + } + 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; + } + throw new Exception ("Unhandled typecode in enum " + tc + " from " + t.AssemblyQualifiedName); + } + + // + // When compiling corlib and called with one of the core types, return + // the corresponding typebuilder for that type. + // + public static Type TypeToCoreType (Type t) + { + if (RootContext.StdLib || (t is TypeBuilder)) + 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.String: + return TypeManager.string_type; + default: + return t; + } + } + + /// + /// Utility function that can be used to probe whether a type + /// is managed or not. + /// + public static bool VerifyUnManaged (Type t, Location loc) + { + if (t.IsValueType || t.IsPointer){ + // + // FIXME: this is more complex, we actually need to + // make sure that the type does not contain any + // classes itself + // + return true; + } + if (!RootContext.StdLib && (t == TypeManager.decimal_type)) + // We need this explicit check here to make it work when + // compiling corlib. + return true; + + Report.Error ( + 208, loc, + "Cannot take the address or size of a variable of a managed type ('" + + CSharpName (t) + "')"); + return false; + } + /// /// Returns the name of the indexer in a given type. /// @@ -843,24 +1326,386 @@ public class TypeManager { public static string IndexerPropertyName (Type t) { + if (t is TypeBuilder) { + TypeContainer tc = (TypeContainer) builder_to_container [t]; + + // + // FIXME: Temporary hack, until we deploy the IndexerName + // property code (and attributes) in the interface code. + // + if (tc == null){ + return "Item"; + } + + return tc.IndexerName; + } + + System.Attribute attr = System.Attribute.GetCustomAttribute ( + t, TypeManager.default_member_type); + if (attr != null){ + DefaultMemberAttribute dma = (DefaultMemberAttribute) attr; + return dma.MemberName; + } + + return "Item"; + } + + public static void MakePinned (LocalBuilder builder) + { // - // FIXME: Replace with something that works around S.R.E failure + // FIXME: Flag the "LocalBuilder" type as being + // pinned. Figure out API. // -//#if FIXME -// System.Attribute attr; -// -// attr = System.Attribute.GetCustomAttribute (t, TypeManager.default_member_type); -// -// if (attr != null) -// { -// DefaultMemberAttribute dma = (DefaultMemberAttribute) attr; -// -// return dma.MemberName; -// } -//#endif - return "Item"; } + + // + // Returns whether the array of memberinfos contains the given method + // + static bool ArrayContainsMethod (MemberInfo [] array, MethodBase new_method) + { + Type [] new_args = TypeManager.GetArgumentTypes (new_method); + + foreach (MethodBase method in array){ + if (method.Name != new_method.Name) + continue; + + Type [] old_args = TypeManager.GetArgumentTypes (method); + int old_count = old_args.Length; + int i; + + if (new_args.Length != old_count) + continue; + + for (i = 0; i < old_count; i++){ + if (old_args [i] != new_args [i]) + break; + } + if (i != old_count) + continue; + + if (!(method is MethodInfo && new_method is MethodInfo)) + return true; + + if (((MethodInfo) method).ReturnType == ((MethodInfo) new_method).ReturnType) + 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, MemberInfo [] 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)) + target_list.Add (new_method); + } + return target_list; + } + + [Flags] + public enum MethodFlags { + IsObsolete = 1, + ShouldIgnore = 2 + } + + static public MethodFlags GetMethodFlags (MethodBase mb) + { + MethodFlags flags = 0; + + if (mb.DeclaringType is TypeBuilder){ + // + // FIXME: Support lookups of Obsolete and ConditionalAttribute + // on MethodBuilders. + // + return 0; + } + + object [] attrs = mb.GetCustomAttributes (false); + foreach (object ta in attrs){ + if (!(ta is System.Attribute)){ + Console.WriteLine ("Unknown type in GetMethodFlags: " + ta); + continue; + } + System.Attribute a = (System.Attribute) ta; + if (a.TypeId == TypeManager.obsolete_attribute_type){ + flags |= MethodFlags.IsObsolete; + continue; + } + + // + // Skip over conditional code. + // + if (a.TypeId == TypeManager.conditional_attribute_type){ + ConditionalAttribute ca = (ConditionalAttribute) a; + + if (RootContext.AllDefines [ca.ConditionString] == null) + flags |= MethodFlags.ShouldIgnore; + } + } + + return flags; + } + +#region MemberLookup implementation + + // + // Name of the member + // + static string closure_name; + + // + // Whether we allow private members in the result (since FindMembers + // uses NonPublic for both protected and private), we need to distinguish. + // + static bool closure_private_ok; + + // + // Who is invoking us and which type is being queried currently. + // + static Type closure_invocation_type; + static Type closure_queried_type; + + // + // The assembly that defines the type is that is calling us + // + static Assembly closure_invocation_assembly; + + // + // This filter filters by name + whether it is ok to include private + // members in the search + // + static internal bool FilterWithClosure (MemberInfo m, object filter_criteria) + { + // + // Hack: we know that the filter criteria will always be in the `closure' + // fields. + // + + if (m.Name != closure_name) + return false; + + // + // 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.Private) + return closure_private_ok; + + // + // FamAndAssem requires that we not only derivate, but we are on the + // same assembly. + // + if (ma == MethodAttributes.FamANDAssem){ + if (closure_invocation_assembly != mb.DeclaringType.Assembly) + return false; + } + + // FamORAssem, Family and Public: + return true; + } + + if (m is FieldInfo){ + FieldInfo fi = (FieldInfo) m; + FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask; + + if (fa == FieldAttributes.Private) + return closure_private_ok; + + // + // FamAndAssem requires that we not only derivate, but we are on the + // same assembly. + // + if (fa == FieldAttributes.FamANDAssem){ + if (closure_invocation_assembly != fi.DeclaringType.Assembly) + return false; + } + // FamORAssem, Family and Public: + return true; + } + + // + // EventInfos and PropertyInfos, return true + // + return true; + } + + static MemberFilter FilterWithClosure_delegate = new MemberFilter (FilterWithClosure); + + // + // 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'. + // + // The binding flags are `bf' and the kind of members being looked up are `mt' + // + // 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 queried_type, + MemberTypes mt, BindingFlags original_bf, string name) + { + BindingFlags bf = original_bf; + + ArrayList method_list = null; + Type current_type = queried_type; + bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0; + bool private_ok; + bool always_ok_flag = false; + + closure_name = name; + closure_invocation_type = invocation_type; + closure_invocation_assembly = invocation_type != null ? invocation_type.Assembly : null; + + // + // If we are a nested class, we always have access to our container + // type names + // + if (invocation_type != null){ + string invocation_name = invocation_type.FullName; + if (invocation_name.IndexOf ('+') != -1){ + string container = queried_type.FullName + "+"; + int container_length = container.Length; + + if (invocation_name.Length > container_length){ + string shared = invocation_name.Substring (0, container_length); + + if (shared == container) + always_ok_flag = true; + } + } + } + + do { + MemberInfo [] mi; + + // + // `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){ + if (invocation_type == current_type){ + private_ok = true; + } else + private_ok = always_ok_flag; + + if (private_ok || invocation_type.IsSubclassOf (current_type)) + bf = original_bf | BindingFlags.NonPublic; + } else { + private_ok = false; + bf = original_bf & ~BindingFlags.NonPublic; + } + + closure_private_ok = private_ok; + closure_queried_type = current_type; + + mi = TypeManager.FindMembers ( + current_type, mt, bf | BindingFlags.DeclaredOnly, + FilterWithClosure_delegate, name); + + 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; + } + + if (mi == null) + continue; + + int count = mi.Length; + + if (count == 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 (count == 1 && !(mi [0] is MethodBase)){ + return mi; + } + + // + // Multiple properties: we query those just to find out the indexer + // name + // + if (mi [0] is PropertyInfo) + return mi; + + // + // We found methods, turn the search into "method scan" + // mode. + // + + method_list = CopyNewMethods (method_list, mi); + mt &= (MemberTypes.Method | MemberTypes.Constructor); + } while (searching); + + if (method_list != null && method_list.Count > 0) + return (MemberInfo []) method_list.ToArray (typeof (MemberInfo)); + + // + // 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, itype, mt, bf, name); + if (x != null) + return x; + } + + return null; + } +#endregion + } }