X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmbas%2Ftypemanager.cs;h=608ee89dfee433cef07a380b7c1808b59821cd9c;hb=abdd584d6d74bfa880a413357e65aa56ab4667fd;hp=bea0e7eafbf4e90031397143d75b580a210a7fba;hpb=3d7b99fb498a871f46c1972868287307b712da35;p=mono.git diff --git a/mcs/mbas/typemanager.cs b/mcs/mbas/typemanager.cs index bea0e7eafbf..608ee89dfee 100644 --- a/mcs/mbas/typemanager.cs +++ b/mcs/mbas/typemanager.cs @@ -9,16 +9,16 @@ // (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 { +namespace Mono.MonoBASIC { public class TypeManager { // @@ -37,6 +37,7 @@ public class TypeManager { static public Type char_ptr_type; static public Type short_type; static public Type decimal_type; + static public Type date_type; static public Type bool_type; static public Type sbyte_type; static public Type byte_type; @@ -67,10 +68,48 @@ public class TypeManager { static public Type param_array_type; static public Type void_ptr_type; static public Type indexer_name_type; - static public Type trace_type; - static public Type debug_type; - + static public Type exception_type; + static public object obsolete_attribute_type; + static public object conditional_attribute_type; + + // + // An empty array of types + // static public Type [] NoTypes; + + + // + // Expressions representing the internal types. Used during declaration + // definition. + // + static public Expression system_object_expr, system_string_expr; + static public Expression system_boolean_expr, system_decimal_expr; + static public Expression system_single_expr, system_double_expr; + static public Expression system_sbyte_expr, system_byte_expr; + static public Expression system_int16_expr, system_uint16_expr; + static public Expression system_int32_expr, system_uint32_expr; + static public Expression system_int64_expr, system_uint64_expr; + static public Expression system_char_expr, system_void_expr; + static public Expression system_date_expr; + static public Expression system_asynccallback_expr; + static public Expression system_iasyncresult_expr; + + // + // This is only used when compiling corlib + // + static public Type system_int32_type; + static public Type system_array_type; + static public Type system_type_type; + static public Type system_assemblybuilder_type; + static public MethodInfo system_int_array_get_length; + static public MethodInfo system_int_array_get_rank; + static public MethodInfo system_object_array_clone; + static public MethodInfo system_int_array_get_length_int; + static public MethodInfo system_int_array_get_lower_bound_int; + static public MethodInfo system_int_array_get_upper_bound_int; + static public MethodInfo system_void_array_copyto_array_int; + static public MethodInfo system_void_set_corlib_type_builders; + // // Internal, not really used outside @@ -95,12 +134,21 @@ public class TypeManager { static public MethodInfo delegate_remove_delegate_delegate; static public MethodInfo int_get_offset_to_string_data; static public MethodInfo int_array_get_length; + static public MethodInfo int_array_get_rank; + static public MethodInfo object_array_clone; + static public MethodInfo int_array_get_length_int; + static public MethodInfo int_array_get_lower_bound_int; + static public MethodInfo int_array_get_upper_bound_int; + static public MethodInfo void_array_copyto_array_int; // // The attribute constructors. // static public ConstructorInfo cons_param_array_attribute; static public ConstructorInfo void_decimal_ctor_five_args; + static public ConstructorInfo void_datetime_ctor_ticks_arg; + static public ConstructorInfo unverifiable_code_ctor; + static public ConstructorInfo default_member_ctor; // // Holds the Array of Assemblies that have been loaded @@ -113,19 +161,25 @@ public class TypeManager { // Keeps a list of module builders. We used this to do lookups // on the modulebuilder using GetType -- needed for arrays // - static ModuleBuilder [] modules; + + // This is changed from list of ModuleBuilders + // to list of Modules for getting addmodule + // compiler option working + // Anirban - 13.07.2004 + + static System.Reflection.Module [] modules; // // This is the type_cache from the assemblies to avoid // hitting System.Reflection on every lookup. // - static Hashtable types; + static CaseInsensitiveHashtable types; // // This is used to hotld the corresponding TypeContainer objects // since we need this in FindMembers // - static Hashtable typecontainers; + static CaseInsensitiveHashtable typecontainers; // // Keeps track of those types that are defined by the @@ -133,10 +187,7 @@ public class TypeManager { // static ArrayList user_types; - // - // Keeps a mapping between TypeBuilders and their TypeContainers - // - static PtrHashtable builder_to_container; + static PtrHashtable builder_to_declspace; // // Tracks the interfaces implemented by typebuilders. We only @@ -151,30 +202,22 @@ public class TypeManager { static Hashtable method_arguments; // - // Maybe `method_arguments' should be replaced and only - // method_internal_params should be kept? - // - static Hashtable method_internal_params; - - static PtrHashtable builder_to_interface; - - // - // Keeps track of delegate types + // Maps PropertyBuilder to a Type array that contains + // the arguments to the indexer // - - static Hashtable builder_to_delegate; + static Hashtable indexer_arguments; // - // Keeps track of enum types - // - - static Hashtable builder_to_enum; + // Maybe 'method_arguments' should be replaced and only + // method_internal_params should be kept? + // + static Hashtable method_internal_params; // - // Keeps track of attribute types + // Keeps track of methods // - static Hashtable builder_to_attr; + static Hashtable builder_to_method; struct Signature { public string name; @@ -224,27 +267,54 @@ public class TypeManager { // A delegate that points to the filter above. static MemberFilter signature_filter; + // + // 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_date_expr = new TypeLookupExpression ("System.DateTime"); + system_asynccallback_expr = new TypeLookupExpression ("System.AsyncCallback"); + system_iasyncresult_expr = new TypeLookupExpression ("System.IAsyncResult"); + } + static TypeManager () { assemblies = new Assembly [0]; modules = null; user_types = new ArrayList (); - types = new Hashtable (); - typecontainers = new Hashtable (); + types = new CaseInsensitiveHashtable (); + negative_hits = new CaseInsensitiveHashtable (); + typecontainers = new CaseInsensitiveHashtable (); - builder_to_interface = new PtrHashtable (); - builder_to_delegate = new PtrHashtable (); - builder_to_enum = new PtrHashtable (); - builder_to_attr = new PtrHashtable (); + builder_to_declspace = new PtrHashtable (); + builder_to_method = new PtrHashtable (); method_arguments = new PtrHashtable (); method_internal_params = new PtrHashtable (); - builder_to_container = new PtrHashtable (); + indexer_arguments = new PtrHashtable (); builder_to_ifaces = new PtrHashtable (); NoTypes = new Type [0]; signature_filter = new MemberFilter (SignatureFilter); + InitExpressionTypes (); } public static void AddUserType (string name, TypeBuilder t, Type [] ifaces) @@ -253,20 +323,20 @@ public class TypeManager { types.Add (name, t); } catch { Type prev = (Type) types [name]; - TypeContainer tc = (TypeContainer) builder_to_container [prev]; + TypeContainer tc = builder_to_declspace [prev] as TypeContainer; if (tc != null){ // // This probably never happens, as we catch this before // - Report.Error (-17, "The type `" + name + "' has already been defined."); + Report.Error (-17, "The type '" + name + "' has already been defined."); return; } - tc = (TypeContainer) builder_to_container [t]; + tc = builder_to_declspace [t] as TypeContainer; Report.Warning ( - 1595, "The type `" + name + "' is defined in an existing assembly;"+ + 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); @@ -290,7 +360,7 @@ public class TypeManager { public static void AddUserType (string name, TypeBuilder t, TypeContainer tc, Type [] ifaces) { - builder_to_container.Add (t, tc); + builder_to_declspace.Add (t, tc); typecontainers.Add (name, tc); AddUserType (name, t, ifaces); } @@ -298,53 +368,64 @@ public class TypeManager { public static void AddDelegateType (string name, TypeBuilder t, Delegate del) { types.Add (name, t); - builder_to_delegate.Add (t, del); + builder_to_declspace.Add (t, del); } public static void AddEnumType (string name, TypeBuilder t, Enum en) { types.Add (name, t); - builder_to_enum.Add (t, en); + builder_to_declspace.Add (t, en); } public static void AddUserInterface (string name, TypeBuilder t, Interface i, Type [] ifaces) { AddUserType (name, t, ifaces); - builder_to_interface.Add (t, i); + builder_to_declspace.Add (t, i); } - public static void RegisterAttrType (Type t, TypeContainer tc) + public static void AddMethod (MethodBuilder builder, MethodData method) { - builder_to_attr.Add (t, tc); + builder_to_method.Add (builder, method); } - + /// - /// Returns the TypeContainer whose Type is `t' or null if there is no - /// TypeContainer for `t' (ie, the Type comes from a library) + /// 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 (TypeContainer) builder_to_container [t]; + return builder_to_declspace [t] as TypeContainer; + } + + public static IMemberContainer LookupMemberContainer (Type t) + { + if (t is TypeBuilder) { + IMemberContainer container = builder_to_declspace [t] as IMemberContainer; + if (container != null) + return container; + } + + return TypeHandle.GetTypeHandle (t); } public static Interface LookupInterface (Type t) { - return (Interface) builder_to_interface [t]; + return builder_to_declspace [t] as Interface; } public static Delegate LookupDelegate (Type t) { - return (Delegate) builder_to_delegate [t]; + return builder_to_declspace [t] as Delegate; } public static Enum LookupEnum (Type t) { - return (Enum) builder_to_enum [t]; + return builder_to_declspace [t] as Enum; } - - public static TypeContainer LookupAttr (Type t) + + public static TypeContainer LookupClass (Type t) { - return (TypeContainer) builder_to_attr [t]; + return builder_to_declspace [t] as TypeContainer; } /// @@ -359,15 +440,20 @@ public class TypeManager { n [top] = a; assemblies = n; + + foreach(Type type in a.GetTypes()) { + if (type.IsPublic ) // && type. attributed as standard module + AddStandardModule(type); + } } /// /// Registers a module builder to lookup types from /// - public static void AddModule (ModuleBuilder mb) + public static void AddModule (System.Reflection.Module mb) { int top = modules != null ? modules.Length : 0; - ModuleBuilder [] n = new ModuleBuilder [top + 1]; + System.Reflection.Module [] n = new System.Reflection.Module [top + 1]; if (modules != null) modules.CopyTo (n, 0); @@ -375,8 +461,138 @@ public class TypeManager { modules = n; } + private class StandardModule { + public readonly string Namespace; + public readonly string Name; + private readonly string asString; + public StandardModule(string _namespace, string name) { + Namespace = _namespace; + Name = name; + asString = ((Namespace != null && Namespace.Length > 0)?(Namespace + "."):"") + Name; + } + public override string ToString() { return asString; } + } + + private static StandardModule[] standardModules; + + /// + /// Registers a new 'standard module' to lookup short-qualified or unqualified members + /// + internal static void AddStandardModule(Module module) + { + int top = standardModules != null ? standardModules.Length : 0; + StandardModule [] n = new StandardModule [top + 1]; + + if (standardModules != null) + standardModules.CopyTo (n, 0); + string name = module.Name; + int split = name.LastIndexOf('.'); + if (split > 0) + name = name.Substring(split+1); + n [top] = new StandardModule(module.Namespace.Name, name); + // Console.WriteLine("Standard Module added: " + n [top]); + standardModules = n; + } + + /// + /// Registers a existing 'standard module' to lookup short-qualified or unqualified members + /// + private static void AddStandardModule(Type type) + { + object[] attributes = type.GetCustomAttributes(false); + for (int i = 0; i < attributes.Length; i ++) { + if (attributes[i].ToString() == "Microsoft.VisualBasic.CompilerServices.StandardModuleAttribute") { + int top = standardModules != null ? standardModules.Length : 0; + StandardModule [] n = new StandardModule [top + 1]; + + if (standardModules != null) + standardModules.CopyTo (n, 0); + n [top] = new StandardModule(type.Namespace, type.Name) ; + standardModules = n; + return; + } + } + } + + // + // + // + public static Type[] GetPertinentStandardModules(params string[] namespaces) + { + ArrayList list = new ArrayList(); + foreach(string Namespace in namespaces) + { + for(int i = 0; i < standardModules.Length; i++) { + if (standardModules[i].Namespace == Namespace) { + string name = standardModules[i].ToString(); + Type t = LookupType(name); + if (t == null) { + System.Console.WriteLine("Could not find standard module '" + name + "'"); + } + else { + list.Add(t); + } + } + } + } + return (Type[])list.ToArray(typeof(Type)); + } + + // + // Low-level lookup, cache-less + // + static Type LookupTypeReflection (string name) + { + Type t; + + try { + foreach (Assembly a in assemblies){ + t = a.GetType (name, false, true); + if (t != null) + return t; + } + + foreach (System.Reflection.Module mb in modules) { + t = mb.GetType (name, false, true); + if (t != null){ + return t; + } + } + } catch (Exception e) { + System.Console.WriteLine("\nERROR: " + e.ToString() + "WHILE EXECUTING LookupTypeReflection(\"" + name + "\")\n"); + } + return null; + } + + static CaseInsensitiveHashtable negative_hits; + // + // This function is used when you want to avoid the lookups, and want to go + // directly to the source. This will use the cache. + // + // Notice that bypassing the cache is bad, because on Microsoft.NET runtime + // GetType ("DynamicType[]") != GetType ("DynamicType[]"), and there is no + // way to test things other than doing a fullname compare + // + public static Type LookupTypeDirect (string name) + { + Type t = (Type) types [name]; + if (t != null) + return t; + + if (negative_hits.Contains (name)) + return null; + t = LookupTypeReflection (name); + if (t == null) + negative_hits [name] = null; + else + types [name] = t; + return t; + } + /// - /// Returns the Type associated with @name + /// Returns the Type associated with @name, takes care of the fact that + /// reflection expects nested types to be separated from the main type + /// with a "+" instead of a "." /// public static Type LookupType (string name) { @@ -390,59 +606,106 @@ public class TypeManager { if (t != null) return t; - foreach (Assembly a in assemblies){ - t = a.GetType (name); - if (t != null){ - types [name] = t; + if (negative_hits.Contains (name)) + return null; - return t; - } - } + // + // Optimization: ComposedCast will work with an existing type, and might already have the + // full name of the type, so the full system lookup can probably be avoided. + // + + string [] elements = name.Split ('.'); + int count = elements.Length; - foreach (ModuleBuilder mb in modules) { - t = mb.GetType (name); - if (t != null) { + for (int n = 1; n <= count; n++){ + string top_level_type = String.Join (".", elements, 0, n); + + if (negative_hits.Contains (top_level_type)) + continue; + + t = (Type) types [top_level_type]; + if (t == null){ + t = LookupTypeReflection (top_level_type); + if (t == null){ + negative_hits [top_level_type] = null; + continue; + } + } + + if (count == n){ types [name] = t; return t; - } + } + + string newt = top_level_type + "+" + String.Join ("+", elements, n, count - n); + t = LookupTypeReflection (newt); + if (t == null) + negative_hits [name] = null; + else + types [name] = t; + return t; } - + negative_hits [name] = null; return null; } + // + // Returns a list of all namespaces in the assemblies and types loaded. + // + public static CaseInsensitiveHashtable GetNamespaces () + { + CaseInsensitiveHashtable namespaces = new CaseInsensitiveHashtable (); + + foreach (Assembly a in assemblies) { + foreach (Type t in a.GetTypes ()) { + string ns = t.Namespace; + + if (namespaces.Contains (ns)) + continue; + namespaces [ns] = ns; + } + } + + foreach (System.Reflection.Module mb in modules) { + foreach (Type t in mb.GetTypes ()) { + string ns = t.Namespace; + + if (namespaces.Contains (ns)) + continue; + namespaces [ns] = ns; + } + } + + return namespaces; + } + /// /// Returns the C# name of a type if possible, or the full type name otherwise /// - static public string CSharpName (Type t) + static public string MonoBASIC_Name (Type t) { return Regex.Replace (t.FullName, @"^System\." + - @"(Int32|UInt32|Int16|Uint16|Int64|UInt64|" + - @"Single|Double|Char|Decimal|Byte|SByte|Object|" + - @"Boolean|String|Void)" + + @"(Int32|Int16|Int64|Single|Double|Char|Decimal|Byte|Object|Boolean|String|DateTime)" + @"(\W+|\b)", - new MatchEvaluator (CSharpNameMatch)); + new MatchEvaluator (MonoBASIC_NameMatch)); } - static String CSharpNameMatch (Match match) + static String MonoBASIC_NameMatch (Match match) { string s = match.Groups [1].Captures [0].Value; return s.ToLower (). - Replace ("int32", "int"). - Replace ("uint32", "uint"). + Replace ("int32", "integer"). Replace ("int16", "short"). - Replace ("uint16", "ushort"). Replace ("int64", "long"). - Replace ("uint64", "ulong"). - Replace ("single", "float"). - Replace ("boolean", "bool") + Replace ("datetime", "date") + match.Groups [2].Captures [0].Value; } /// /// Returns the signature of the method /// - static public string CSharpSignature (MethodBase mb) + static public string MonoBASIC_Signature (MethodBase mb) { string sig = "("; @@ -477,7 +740,7 @@ public class TypeManager { Type t = LookupType (name); if (t == null){ - Report.Error (518, "The predefined type `" + name + "' is not defined or imported"); + Report.Error (518, "The predefined type '" + name + "' is not defined or imported"); Environment.Exit (0); } @@ -485,47 +748,59 @@ public class TypeManager { } /// - /// Returns the MethodInfo for a method named `name' defined - /// in type `t' which takes arguments of types `args' + /// Returns the MethodInfo for a method named 'name' defined + /// in type 't' which takes arguments of types 'args' /// static MethodInfo GetMethod (Type t, string name, Type [] args) { - MemberInfo [] mi; + MemberList list; Signature sig; 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 + "'"); + list = FindMembers (t, MemberTypes.Method, instance_and_static | BindingFlags.Public| BindingFlags.IgnoreCase, + signature_filter, sig); + if (list.Count == 0) { + Report.Error (-19, "Can not find the core function '" + name + "'"); + return null; + } + + MethodInfo mi = list [0] as MethodInfo; + if (mi == null) { + Report.Error (-19, "Can not find the core function '" + name + "'"); return null; } - return (MethodInfo) mi [0]; + return mi; } /// /// Returns the ConstructorInfo for "args" /// - static ConstructorInfo GetConstructor (Type t, Type [] args) + public static ConstructorInfo GetConstructor (Type t, Type [] args) { - MemberInfo [] mi; + MemberList list; Signature sig; sig.name = ".ctor"; sig.args = args; - mi = FindMembers (t, MemberTypes.Constructor, - instance_and_static | BindingFlags.Public, 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 + "'"); + list = FindMembers (t, MemberTypes.Constructor, + instance_and_static | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.IgnoreCase, + signature_filter, sig); + if (list.Count == 0){ + Report.Error (-19, "Can not find the core constructor for type '" + t.Name + "'"); return null; } - return (ConstructorInfo) mi [0]; + ConstructorInfo ci = list [0] as ConstructorInfo; + if (ci == null){ + Report.Error (-19, "Can not find the core constructor for type '" + t.Name + "'"); + return null; + } + + return ci; } public static void InitEnumUnderlyingTypes () @@ -567,6 +842,7 @@ public class TypeManager { array_type = CoreLookupType ("System.Array"); void_type = CoreLookupType ("System.Void"); + date_type = CoreLookupType ("System.DateTime"); type_type = CoreLookupType ("System.Type"); runtime_field_handle_type = CoreLookupType ("System.RuntimeFieldHandle"); @@ -593,8 +869,61 @@ public class TypeManager { void_ptr_type = CoreLookupType ("System.Void*"); indexer_name_type = CoreLookupType ("System.Runtime.CompilerServices.IndexerNameAttribute"); - trace_type = CoreLookupType ("System.Diagnostics.Trace"); - debug_type = CoreLookupType ("System.Diagnostics.Debug"); + + exception_type = CoreLookupType ("System.Exception"); + + // + // Attribute types + // + obsolete_attribute_type = CoreLookupType ("System.ObsoleteAttribute"); + conditional_attribute_type = CoreLookupType ("System.Diagnostics.ConditionalAttribute"); + + // + // When compiling corlib, store the "real" types here. + // + if (!RootContext.StdLib) { + system_int32_type = typeof (System.Int32); + system_array_type = typeof (System.Array); + system_type_type = typeof (System.Type); + system_assemblybuilder_type = typeof (System.Reflection.Emit.AssemblyBuilder); + + Type [] void_arg = { }; + system_int_array_get_length = GetMethod ( + system_array_type, "get_Length", void_arg); + system_int_array_get_rank = GetMethod ( + system_array_type, "get_Rank", void_arg); + system_object_array_clone = GetMethod ( + system_array_type, "Clone", void_arg); + + Type [] system_int_arg = { system_int32_type }; + system_int_array_get_length_int = GetMethod ( + system_array_type, "GetLength", system_int_arg); + system_int_array_get_upper_bound_int = GetMethod ( + system_array_type, "GetUpperBound", system_int_arg); + system_int_array_get_lower_bound_int = GetMethod ( + system_array_type, "GetLowerBound", system_int_arg); + + Type [] system_array_int_arg = { system_array_type, system_int32_type }; + system_void_array_copyto_array_int = GetMethod ( + system_array_type, "CopyTo", system_array_int_arg); + + Type [] system_type_type_arg = { system_type_type, system_type_type, system_type_type }; + + try { + system_void_set_corlib_type_builders = GetMethod ( + system_assemblybuilder_type, "SetCorlibTypeBuilders", + system_type_type_arg); + + object[] args = new object [3]; + args [0] = object_type; + args [1] = value_type; + args [2] = enum_type; + + system_void_set_corlib_type_builders.Invoke (CodeGen.AssemblyBuilder, args); + } catch { + Console.WriteLine ("Corlib compilation is not supported in Microsoft.NET due to bugs in it"); + } + } } // @@ -642,6 +971,28 @@ public class TypeManager { runtime_helpers_type, "get_OffsetToStringData", void_arg); int_array_get_length = GetMethod ( array_type, "get_Length", void_arg); + int_array_get_rank = GetMethod ( + array_type, "get_Rank", void_arg); + + // + // Int32 arguments + // + Type [] int_arg = { int32_type }; + int_array_get_length_int = GetMethod ( + array_type, "GetLength", int_arg); + int_array_get_upper_bound_int = GetMethod ( + array_type, "GetUpperBound", int_arg); + int_array_get_lower_bound_int = GetMethod ( + array_type, "GetLowerBound", int_arg); + + // + // System.Array methods + // + object_array_clone = GetMethod ( + array_type, "Clone", void_arg); + Type [] array_int_arg = { array_type, int32_type }; + void_array_copyto_array_int = GetMethod ( + array_type, "CopyTo", array_int_arg); // // object arguments @@ -660,7 +1011,6 @@ public class TypeManager { // // Array functions // - Type [] int_arg = { int32_type }; int_getlength_int = GetMethod ( array_type, "GetLength", int_arg); @@ -671,97 +1021,151 @@ public class TypeManager { void_decimal_ctor_five_args = GetConstructor ( decimal_type, dec_arg); + // DateTime constructor + Type [] ticks_arg = { int64_type }; + void_datetime_ctor_ticks_arg = GetConstructor ( date_type, ticks_arg); + // // Attributes // cons_param_array_attribute = GetConstructor ( param_array_type, void_arg); + + unverifiable_code_ctor = GetConstructor ( + unverifiable_code_type, void_arg); + default_member_ctor = GetConstructor ( + default_member_type, string_); } const BindingFlags instance_and_static = BindingFlags.Static | BindingFlags.Instance; - // - // 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) + static CaseInsensitiveHashtable type_hash = new CaseInsensitiveHashtable (); + + /// + /// 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) { + DeclSpace decl = (DeclSpace) builder_to_declspace [t]; + bf |= BindingFlags.IgnoreCase; + // + // '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 (t.IsSubclassOf (TypeManager.array_type)) - return TypeManager.array_type.FindMembers (mt, bf, filter, criteria); - - if (!(t is TypeBuilder)){ - // - // 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 i_members; - } + return new MemberList (TypeManager.array_type.FindMembers (mt, bf, filter, criteria)); + + // + // 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) | BindingFlags.IgnoreCase, 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){ - MemberInfo [] both = new MemberInfo [i_len + s_len]; - - i_members.CopyTo (both, 0); - s_members.CopyTo (both, i_len); - - return both; - } else { - if (i_len > 0) - return i_members; - else - return s_members; - } + MemberInfo [] s_members = t.FindMembers ( + mt, (bf & ~BindingFlags.Instance) | BindingFlags.IgnoreCase, 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 t.FindMembers (mt, bf, filter, criteria); } + 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 MemberList MemberLookup_FindMembers (Type t, MemberTypes mt, BindingFlags bf, + string name, out bool used_cache) + { // - // FIXME: We should not have builder_to_blah everywhere, - // we should just have a builder_to_findmemberizable - // and have them implement a new ICanFindMembers interface + // 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. // - Enum e = (Enum) builder_to_enum [t]; + if (t.IsSubclassOf (TypeManager.array_type)) { + used_cache = true; + return TypeHandle.ArrayType.MemberCache.FindMembers ( + mt, bf, name, FilterWithClosure_delegate, null); + } - if (e != null) - return e.FindMembers (mt, bf, filter, criteria); - - Delegate del = (Delegate) builder_to_delegate [t]; + // + // 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 (t is TypeBuilder) { + DeclSpace decl = (DeclSpace) builder_to_declspace [t]; + MemberCache cache = decl.MemberCache; - if (del != null) - return del.FindMembers (mt, bf, filter, criteria); + // + // If this DeclSpace has a MemberCache, use it. + // - Interface iface = (Interface) builder_to_interface [t]; + if (cache != null) { + used_cache = true; + return cache.FindMembers ( + mt, bf, name, FilterWithClosure_delegate, null); + } - if (iface != null) - return iface.FindMembers (mt, bf, filter, criteria); - - TypeContainer tc = (TypeContainer) builder_to_container [t]; + // If there is no MemberCache, we need to use the "normal" FindMembers. - if (tc != null) - return tc.FindMembers (mt, bf, filter, criteria); + MemberList list; + Timer.StartTimer (TimerType.FindMembers); + list = decl.FindMembers (mt, bf | BindingFlags.DeclaredOnly | BindingFlags.IgnoreCase, + FilterWithClosure_delegate, name); + Timer.StopTimer (TimerType.FindMembers); + used_cache = false; + return list; + } - return null; + // + // This call will always succeed. There is exactly one TypeHandle instance per + // type, TypeHandle.GetTypeHandle() will either return it or create a new one + // if it didn't already exist. + // + TypeHandle handle = TypeHandle.GetTypeHandle (t); + + used_cache = true; + return handle.MemberCache.FindMembers (mt, bf, name, FilterWithClosure_delegate, null); } public static bool IsBuiltinType (Type t) @@ -769,7 +1173,8 @@ public class TypeManager { 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 == sbyte_type || t == byte_type || t == ushort_type || t == void_type || + t == date_type) return true; else return false; @@ -790,10 +1195,58 @@ public class TypeManager { else return false; } + + // + // Whether a type is unmanaged. This is used by the unsafe code (25.2) + // + public static bool IsUnmanagedType (Type t) + { + if (IsBuiltinType (t) && t != TypeManager.string_type) + return true; + + if (IsEnumType (t)) + return true; + + if (t.IsPointer) + return true; + + if (IsValueType (t)){ + if (t is TypeBuilder){ + TypeContainer tc = LookupTypeContainer (t); + + foreach (Field f in tc.Fields){ + if (f.FieldBuilder.IsStatic) + continue; + if (!IsUnmanagedType (f.FieldBuilder.FieldType)) + return false; + } + } else { + FieldInfo [] fields = t.GetFields (); + + foreach (FieldInfo f in fields){ + if (f.IsStatic) + continue; + if (!IsUnmanagedType (f.FieldType)) + return false; + } + } + return true; + } + + return false; + } + + public static bool IsValueType (Type t) + { + if (t.IsSubclassOf (TypeManager.value_type)) + return true; + else + return false; + } public static bool IsInterfaceType (Type t) { - Interface iface = (Interface) builder_to_interface [t]; + Interface iface = builder_to_declspace [t] as Interface; if (iface != null) return true; @@ -801,6 +1254,33 @@ public class TypeManager { return false; } + // + // Checks whether 'type' is a subclass or nested child of 'parent'. + // + public static bool IsSubclassOrNestedChildOf (Type type, Type parent) + { + do { + if ((type == parent) || type.IsSubclassOf (parent)) + 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 == parent) || type.IsSubclassOf (parent)) + return false; + else + return IsSubclassOrNestedChildOf (type, parent); + } + /// /// Returns the User Defined Types /// @@ -810,7 +1290,7 @@ public class TypeManager { } } - public static Hashtable TypeContainers { + public static CaseInsensitiveHashtable TypeContainers { get { return typecontainers; } @@ -891,18 +1371,71 @@ public class TypeManager { return types; } } - - // - // This is a workaround the fact that GetValue is not - // supported for dynamic types - // - static Hashtable fields = new Hashtable (); - static public bool RegisterFieldValue (FieldBuilder fb, object value) - { - if (fields.Contains (fb)) - return false; - fields.Add (fb, value); + /// + /// Returns the argument types for an indexer based on its PropertyInfo + /// + /// For dynamic indexers, we use the compiler provided types, for + /// indexers from existing assemblies we load them from GetParameters, + /// and insert them into the cache + /// + static public Type [] GetArgumentTypes (PropertyInfo indexer) + { + if (indexer_arguments.Contains (indexer)) + return (Type []) indexer_arguments [indexer]; + else { + // If we're a PropertyBuilder and not in the + // 'indexer_arguments' hash, then we're a property and + // not an indexer. + + MethodInfo mi = indexer.GetSetMethod (true); + if (mi == null) { + mi = indexer.GetGetMethod (true); + if (mi == null) + return NoTypes; + } + + ParameterInfo [] pi = mi.GetParameters (); + if (pi == null) + return NoTypes; + + int c = pi.Length; + Type [] types = new Type [c]; + + for (int i = 0; i < c; i++) + types [i] = pi [i].ParameterType; + + indexer_arguments.Add (indexer, types); + return types; + } + /*else + { + ParameterInfo [] pi = indexer.GetIndexParameters (); + // Property, not an indexer. + if (pi == null) + return NoTypes; + int c = pi.Length; + Type [] types = new Type [c]; + + for (int i = 0; i < c; i++) + types [i] = pi [i].ParameterType; + + indexer_arguments.Add (indexer, types); + return types; + }*/ + } + + // + // This is a workaround the fact that GetValue is not + // supported for dynamic types + // + static CaseInsensitiveHashtable fields = new CaseInsensitiveHashtable (); + static public bool RegisterFieldValue (FieldBuilder fb, object value) + { + if (fields.Contains (fb)) + return false; + + fields.Add (fb, value); return true; } @@ -912,7 +1445,7 @@ public class TypeManager { return fields [fb]; } - static Hashtable fieldbuilders_to_fields = new Hashtable (); + static CaseInsensitiveHashtable fieldbuilders_to_fields = new CaseInsensitiveHashtable (); static public bool RegisterFieldBase (FieldBuilder fb, FieldBase f) { if (fieldbuilders_to_fields.Contains (fb)) @@ -927,12 +1460,12 @@ public class TypeManager { return (FieldBase) fieldbuilders_to_fields [fb]; } - static Hashtable events; + static CaseInsensitiveHashtable events; static public bool RegisterEvent (MyEventBuilder eb, MethodBase add, MethodBase remove) { if (events == null) - events = new Hashtable (); + events = new CaseInsensitiveHashtable (); if (events.Contains (eb)) return false; @@ -962,12 +1495,32 @@ public class TypeManager { return ei.GetAddMethod (); } - static Hashtable properties; + static CaseInsensitiveHashtable priv_fields_events; + + static public bool RegisterPrivateFieldOfEvent (EventInfo einfo, FieldBuilder builder) + { + if (priv_fields_events == null) + priv_fields_events = new CaseInsensitiveHashtable (); + + if (priv_fields_events.Contains (einfo)) + return false; + + priv_fields_events.Add (einfo, builder); + + return true; + } + + static public MemberInfo GetPrivateFieldOfEvent (EventInfo ei) + { + return (MemberInfo) priv_fields_events [ei]; + } + + static CaseInsensitiveHashtable properties; static public bool RegisterProperty (PropertyBuilder pb, MethodBase get, MethodBase set) { if (properties == null) - properties = new Hashtable (); + properties = new CaseInsensitiveHashtable (); if (properties.Contains (pb)) return false; @@ -976,36 +1529,15 @@ public class TypeManager { return true; } - - // - // FIXME: we need to return the accessors depending on whether - // they are visible or not. - // - static public MethodInfo [] GetAccessors (PropertyInfo pi) - { - MethodInfo [] ret; - if (pi is PropertyBuilder){ - Pair pair = (Pair) properties [pi]; - - ret = new MethodInfo [2]; - ret [0] = (MethodInfo) pair.First; - ret [1] = (MethodInfo) pair.Second; - - return ret; - } else { - MethodInfo [] mi = new MethodInfo [2]; + static public bool RegisterIndexer (PropertyBuilder pb, MethodBase get, MethodBase set, Type[] args) + { + if (!RegisterProperty (pb, get,set)) + return false; - // - // Why this and not pi.GetAccessors? - // Because sometimes index 0 is the getter - // sometimes it is 1 - // - mi [0] = pi.GetGetMethod (true); - mi [1] = pi.GetSetMethod (true); + indexer_arguments.Add (pb, args); - return mi; - } + return true; } static public MethodInfo GetPropertyGetter (PropertyInfo pi) @@ -1015,7 +1547,7 @@ public class TypeManager { return (MethodInfo) de.Second; } else - return pi.GetSetMethod (); + return pi.GetSetMethod (true); } static public MethodInfo GetPropertySetter (PropertyInfo pi) @@ -1025,11 +1557,51 @@ public class TypeManager { return (MethodInfo) de.First; } else - return pi.GetGetMethod (); + return pi.GetGetMethod (true); } /// - /// This function returns the interfaces in the type `t'. Works with + /// 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(); + ExpandAllInterfaces (base_interfaces, ref new_ifaces); + Type [] ret = new Type [new_ifaces.Count]; + new_ifaces.CopyTo (ret, 0); + + return ret; + } + + /// + /// Recursively finds out each base interface in case + /// of multiple inheritance + /// + public static void ExpandAllInterfaces + (Type [] base_interfaces, ref ArrayList new_ifaces) + { + foreach (Type iface in base_interfaces) { + if (!new_ifaces.Contains (iface)) + new_ifaces.Add (iface); + + Type [] implementing = TypeManager.GetInterfaces (iface); + // + // Incase any base interface is present call this function again + // + if (implementing.Length != 0) + ExpandAllInterfaces (implementing, ref new_ifaces); + } + } + + /// + /// This function returns the interfaces in the type 't'. Works with /// both types and TypeBuilders. /// public static Type [] GetInterfaces (Type t) @@ -1047,9 +1619,24 @@ public class TypeManager { if (t.IsArray) t = TypeManager.array_type; - if (t is TypeBuilder) - return (Type []) builder_to_ifaces [t]; - else + 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 (); } @@ -1064,7 +1651,7 @@ public class TypeManager { // // FIXME OPTIMIZATION: // as soon as we hit a non-TypeBuiler in the interface - // chain, we could return, as the `Type.GetInterfaces' + // chain, we could return, as the 'Type.GetInterfaces' // will return all the interfaces implement by the type // or its parents. // @@ -1084,6 +1671,59 @@ public class TypeManager { 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 @@ -1091,10 +1731,28 @@ public class TypeManager { // 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){ @@ -1119,7 +1777,54 @@ public class TypeManager { case TypeCode.UInt64: return TypeManager.uint64_type; } - throw new Exception ("Unhandled typecode in enum" + tc); + 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; + case TypeCode.DateTime: + return TypeManager.date_type; + default: + 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; + return t; + } } /// @@ -1128,7 +1833,7 @@ public class TypeManager { /// public static bool VerifyUnManaged (Type t, Location loc) { - if (t.IsValueType){ + if (t.IsValueType || t.IsPointer){ // // FIXME: this is more complex, we actually need to // make sure that the type does not contain any @@ -1137,10 +1842,15 @@ public class TypeManager { 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) + "')"); + MonoBASIC_Name (t) + "')"); return false; } @@ -1148,26 +1858,29 @@ public class TypeManager { /// Returns the name of the indexer in a given type. /// /// - /// The default is not always `Item'. The user can change this behaviour by + /// The default is not always 'Item'. The user can change this behaviour by /// using the DefaultMemberAttribute in the class. /// - /// For example, the String class indexer is named `Chars' not `Item' + /// For example, the String class indexer is named 'Chars' not 'Item' /// public static string IndexerPropertyName (Type t) { - if (t is TypeBuilder) { - TypeContainer tc = (TypeContainer) builder_to_container [t]; + if (t.IsInterface) { + Interface i = LookupInterface (t); - // - // FIXME: Temporary hack, until we deploy the IndexerName - // property code (and attributes) in the interface code. - // - if (tc == null){ - return "Item"; + if ((i == null) || (i.DefaultPropName == null)) + return "Item"; + + return i.DefaultPropName; + } else { + TypeContainer tc = LookupTypeContainer (t); + + if ((tc == null) || (tc.DefaultPropName == null)) + return "Item"; + + return tc.DefaultPropName; } - - return tc.IndexerName; } System.Attribute attr = System.Attribute.GetCustomAttribute ( @@ -1213,23 +1926,19 @@ public class TypeManager { } 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 true; } return false; } // - // We copy methods from `new_members' into `target_list' if the signature + // 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) + public static ArrayList CopyNewMethods (ArrayList target_list, MemberList new_members) { if (target_list == null){ target_list = new ArrayList (); @@ -1253,6 +1962,72 @@ public class TypeManager { return target_list; } + [Flags] + public enum MethodFlags { + IsObsolete = 1, + IsObsoleteError = 2, + ShouldIgnore = 3 + } + + // + // Returns the TypeManager.MethodFlags for this method. + // This emits an error 619 / warning 618 if the method is obsolete. + // In the former case, TypeManager.MethodFlags.IsObsoleteError is returned. + // + static public MethodFlags GetMethodFlags (MethodBase mb, Location loc) + { + MethodFlags flags = 0; + + if (mb.DeclaringType is TypeBuilder){ + MethodData method = (MethodData) builder_to_method [mb]; + if (method == null) { + // FIXME: implement Obsolete attribute on Property, + // Indexer and Event. + return 0; + } + + return method.GetMethodFlags (loc); + } + + object [] attrs = mb.GetCustomAttributes (true); + 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){ + ObsoleteAttribute oa = (ObsoleteAttribute) a; + + string method_desc = TypeManager.MonoBASIC_Signature (mb); + + if (oa.IsError) { + Report.Error (619, loc, "Method '" + method_desc + + "' is obsolete: '" + oa.Message + "'"); + return MethodFlags.IsObsoleteError; + } else + Report.Warning (618, loc, "Method '" + method_desc + + "' is obsolete: '" + oa.Message + "'"); + + 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 // @@ -1271,6 +2046,7 @@ public class TypeManager { // static Type closure_invocation_type; static Type closure_queried_type; + static Type closure_start_type; // // The assembly that defines the type is that is calling us @@ -1284,15 +2060,19 @@ public class TypeManager { static internal bool FilterWithClosure (MemberInfo m, object filter_criteria) { // - // Hack: we know that the filter criteria will always be in the `closure' + // Hack: we know that the filter criteria will always be in the 'closure' // fields. // - if (m.Name != closure_name) - return false; + if ((filter_criteria != null) && (m.Name != (string) filter_criteria)) + return false; + + if ((closure_start_type == closure_invocation_type) && + (m.DeclaringType == closure_invocation_type)) + return true; // - // Ugly: we need to find out the type of `m', and depending + // Ugly: we need to find out the type of 'm', and depending // on this, tell whether we accept or not // if (m is MethodBase){ @@ -1300,7 +2080,7 @@ public class TypeManager { MethodAttributes ma = mb.Attributes & MethodAttributes.MemberAccessMask; if (ma == MethodAttributes.Private) - return closure_private_ok; + return closure_private_ok || (closure_invocation_type == m.DeclaringType); // // FamAndAssem requires that we not only derivate, but we are on the @@ -1311,7 +2091,28 @@ public class TypeManager { return false; } - // FamORAssem, Family and Public: + // Assembly and FamORAssem succeed if we're in the same assembly. + if ((ma == MethodAttributes.Assembly) || (ma == MethodAttributes.FamORAssem)){ + if (closure_invocation_assembly == mb.DeclaringType.Assembly) + return true; + } + + // We already know that we aren't in the same assembly. + if (ma == MethodAttributes.Assembly) + return false; + + // Family and FamANDAssem require that we derive. + if ((ma == MethodAttributes.Family) || (ma == MethodAttributes.FamANDAssem)){ + if (closure_invocation_type == null) + return false; + + if (!IsSubclassOrNestedChildOf (closure_invocation_type, mb.DeclaringType)) + return false; + + return true; + } + + // Public. return true; } @@ -1320,7 +2121,7 @@ public class TypeManager { FieldAttributes fa = fi.Attributes & FieldAttributes.FieldAccessMask; if (fa == FieldAttributes.Private) - return closure_private_ok; + return closure_private_ok || (closure_invocation_type == m.DeclaringType); // // FamAndAssem requires that we not only derivate, but we are on the @@ -1330,7 +2131,35 @@ public class TypeManager { if (closure_invocation_assembly != fi.DeclaringType.Assembly) return false; } - // FamORAssem, Family and Public: + + // Assembly and FamORAssem succeed if we're in the same assembly. + if ((fa == FieldAttributes.Assembly) || (fa == FieldAttributes.FamORAssem)){ + if (closure_invocation_assembly == fi.DeclaringType.Assembly) + return true; + } + + // We already know that we aren't in the same assembly. + if (fa == FieldAttributes.Assembly) + return false; + + // Family and FamANDAssem require that we derive. + if ((fa == FieldAttributes.Family) || (fa == FieldAttributes.FamANDAssem)){ + if (closure_invocation_type == null) + return false; + + if (!IsSubclassOrNestedChildOf (closure_invocation_type, fi.DeclaringType)) + return false; + + // Although a derived class can access protected members of its base class + // it cannot do so through an instance of the base class (CS1540). + if ((closure_invocation_type != closure_start_type) && + closure_invocation_type.IsSubclassOf (closure_start_type)) + return false; + + return true; + } + + // Public. return true; } @@ -1341,30 +2170,47 @@ public class TypeManager { } 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'. + // 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' + // 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) + { + Timer.StartTimer (TimerType.MemberLookup); + + MemberInfo[] retval = RealMemberLookup (invocation_type, queried_type, + mt, original_bf, name); + + Timer.StopTimer (TimerType.MemberLookup); + + return retval; + } + + static MemberInfo [] RealMemberLookup (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; + if (queried_type == null) + throw new ArgumentNullException("queried_type"); bool searching = (original_bf & BindingFlags.DeclaredOnly) == 0; bool private_ok; bool always_ok_flag = false; + bool skip_iface_check = true, used_cache = false; closure_name = name; closure_invocation_type = invocation_type; closure_invocation_assembly = invocation_type != null ? invocation_type.Assembly : null; + closure_start_type = queried_type; // // If we are a nested class, we always have access to our container @@ -1386,10 +2232,10 @@ public class TypeManager { } do { - MemberInfo [] mi; + MemberList list; // - // `NonPublic' is lame, because it includes both protected and + // '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. // @@ -1399,11 +2245,14 @@ public class TypeManager { // if (invocation_type != null){ if (invocation_type == current_type){ - private_ok = true; + private_ok = (bf & BindingFlags.NonPublic) != 0; } else private_ok = always_ok_flag; + + if (invocation_type.IsSubclassOf (current_type)) + private_ok = true; - if (private_ok || invocation_type.IsSubclassOf (current_type)) + if (private_ok) bf = original_bf | BindingFlags.NonPublic; } else { private_ok = false; @@ -1412,11 +2261,27 @@ public class TypeManager { closure_private_ok = private_ok; closure_queried_type = current_type; - - mi = TypeManager.FindMembers ( - current_type, mt, bf | BindingFlags.DeclaredOnly, - FilterWithClosure_delegate, name); - + + Timer.StopTimer (TimerType.MemberLookup); + bf |= BindingFlags.IgnoreCase; + 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 parent classes. + // + + if (used_cache) + searching = false; + else + skip_iface_check = false; + if (current_type == TypeManager.object_type) searching = false; else { @@ -1430,42 +2295,44 @@ public class TypeManager { current_type = TypeManager.object_type; } - if (mi == null) - continue; - - int count = mi.Length; - - if (count == 0) + if (list.Count == 0) continue; - + // - // Events and types are returned by both `static' and `instance' + // 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; + if (list.Count == 1 && !(list [0] is MethodBase)){ + return (MemberInfo []) list; } // // Multiple properties: we query those just to find out the indexer // name // - if (mi [0] is PropertyInfo) - return mi; - + if (list [0] is PropertyInfo) + return (MemberInfo []) list; + // // We found methods, turn the search into "method scan" // mode. // - method_list = CopyNewMethods (method_list, mi); + method_list = CopyNewMethods (method_list, list); mt &= (MemberTypes.Method | MemberTypes.Constructor); } while (searching); 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. @@ -1494,4 +2361,134 @@ public class TypeManager { } +/// +/// There is exactly one instance of this class per type. +/// +public sealed class TypeHandle : IMemberContainer { + public readonly TypeHandle BaseType; + + readonly int id = ++next_id; + static int next_id = 0; + + /// + /// 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. + /// + public 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; + } + + /// + /// 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 IMemberContainer ArrayType { + get { + if (array_type != null) + return array_type; + + array_type = GetTypeHandle (TypeManager.array_type); + + return array_type; + } + } + + private static PtrHashtable type_hash = new PtrHashtable (); + + private static TypeHandle object_type = null; + private static TypeHandle array_type = null; + + private Type type; + private bool is_interface; + private MemberCache member_cache; + + private TypeHandle (Type type) + { + this.type = type; + if (type.BaseType != null) + BaseType = GetTypeHandle (type.BaseType); + else if ((type != TypeManager.object_type) && (type != typeof (object))) + is_interface = true; + this.member_cache = new MemberCache (this); + } + + // IMemberContainer methods + + public string Name { + get { + return type.FullName; + } + } + + public Type Type { + get { + return type; + } + } + + public IMemberContainer Parent { + get { + return BaseType; + } + } + + public bool IsInterface { + get { + return is_interface; + } + } + + public MemberList GetMembers (MemberTypes mt, BindingFlags bf) + { + if (mt == MemberTypes.Event) + return new MemberList (type.GetEvents (bf | BindingFlags.DeclaredOnly)); + else + return new MemberList (type.FindMembers (mt, bf | BindingFlags.DeclaredOnly | BindingFlags.IgnoreCase, + null, null)); + } + + // IMemberFinder methods + + public MemberList FindMembers (MemberTypes mt, BindingFlags bf, string name, + MemberFilter filter, object criteria) + { + return 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 + ")"; + } +} + }