* ContainerControlTest.cs: Added tests for ActiveControl.
[mono.git] / mcs / mcs / typemanager.cs
index 83ed8dfe1f540c192ffc5a31caeaf88877f4fa2b..52249cedb125169056dc4a076c7227c00f20e3cf 100644 (file)
@@ -31,7 +31,10 @@ using System.Diagnostics;
 
 namespace Mono.CSharp {
 
-public partial class TypeManager {
+#if GMCS_SOURCE
+       partial
+#endif
+       class TypeManager {
        //
        // A list of core types that the compiler requires or uses
        //
@@ -57,7 +60,6 @@ public partial class TypeManager {
        static public Type multicast_delegate_type;
        static public Type void_type;
        static public Type null_type;
-       static public Type enumeration_type;
        static public Type array_type;
        static public Type runtime_handle_type;
        static public Type icloneable_type;
@@ -70,6 +72,7 @@ public partial class TypeManager {
        static public Type iasyncresult_type;
        static public Type asynccallback_type;
        static public Type intptr_type;
+       static public Type uintptr_type;
        static public Type monitor_type;
        static public Type interlocked_type;
        static public Type runtime_field_handle_type;
@@ -269,6 +272,7 @@ public partial class TypeManager {
                builder_to_declspace = null;
                builder_to_member_cache = null;
                builder_to_ifaces = null;
+               builder_to_type_param = null;
                indexer_arguments = null;
                method_params = null;
                builder_to_method = null;
@@ -282,8 +286,6 @@ public partial class TypeManager {
 
 #if GMCS_SOURCE
                assembly_internals_vis_attrs = null;
-
-               CleanUpGenerics ();
 #endif
 
                TypeHandle.CleanUp ();
@@ -299,7 +301,7 @@ public partial class TypeManager {
 
                if (!(mi is MethodBase))
                        return false;
-               
+
                if (mi.Name != sig.name)
                        return false;
 
@@ -373,6 +375,7 @@ public partial class TypeManager {
                builder_to_declspace = new PtrHashtable ();
                builder_to_member_cache = new PtrHashtable ();
                builder_to_method = new PtrHashtable ();
+               builder_to_type_param = new PtrHashtable ();
                method_params = new PtrHashtable ();
                method_overrides = new PtrHashtable ();
                indexer_arguments = new PtrHashtable ();
@@ -385,11 +388,10 @@ public partial class TypeManager {
 
 #if GMCS_SOURCE
                assembly_internals_vis_attrs = new PtrHashtable ();
-               
-               InitGenerics ();
 #endif
 
                // to uncover regressions
+               AllClsTopLevelTypes = null;
                cons_param_array_attribute = null;
        }
 
@@ -768,8 +770,7 @@ public partial class TypeManager {
                string parameters = iparams.GetSignatureForError ();
                string accessor = "";
 
-               // Is property
-               if (mb.IsSpecialName) {
+               if (!mb.IsConstructor && TypeManager.IsSpecialMethod (mb)) {
                        Operator.OpType ot = Operator.GetOperatorType (mb.Name);
                        if (ot != Operator.OpType.TOP) {
                                sig.Append ("operator ");
@@ -778,25 +779,19 @@ public partial class TypeManager {
                                return sig.ToString ();
                        }
 
-                       if (mb.Name.StartsWith ("get_") || mb.Name.StartsWith ("set_")) {
+                       bool is_getter = mb.Name.StartsWith ("get_");
+                       bool is_setter = mb.Name.StartsWith ("set_");
+                       if (is_getter || is_setter) {
                                accessor = mb.Name.Substring (0, 3);
                        }
-               }
 
-               // Is indexer
-               if (mb.IsSpecialName && !mb.IsConstructor) {
-                       if (iparams.Count > (mb.Name.StartsWith ("get_") ? 0 : 1)) {
+                       // Is indexer
+                       if (iparams.Count > (is_getter ? 0 : 1)) {
                                sig.Append ("this[");
-                               if (show_accessor) {
+                               if (is_getter)
                                        sig.Append (parameters.Substring (1, parameters.Length - 2));
-                               }
-                               else {
-                                       int before_ret_val = parameters.LastIndexOf (',');
-                                       if (before_ret_val < 0)
-                                               sig.Append (parameters.Substring (1, parameters.Length - 2));
-                                       else
-                                               sig.Append (parameters.Substring (1, before_ret_val - 1));
-                               }
+                               else
+                                       sig.Append (parameters.Substring (1, parameters.LastIndexOf (',') - 1));
                                sig.Append (']');
                        } else {
                                sig.Append (mb.Name.Substring (4));
@@ -846,7 +841,7 @@ public partial class TypeManager {
 
        static public string CSharpSignature (EventInfo ei)
        {
-               return CSharpName (ei.DeclaringType) + '.' + ei.Name;
+               return CSharpName (ei.DeclaringType) + "." + ei.Name;
        }
 
        /// <summary>
@@ -901,7 +896,7 @@ public partial class TypeManager {
                return GetMethod (t, name, args, false, report_errors);
        }
 
-       static MethodInfo GetMethod (Type t, string name, Type [] args)
+       public static MethodInfo GetMethod (Type t, string name, Type [] args)
        {
                return GetMethod (t, name, args, true);
        }
@@ -1020,6 +1015,7 @@ public partial class TypeManager {
                interlocked_type     = CoreLookupType ("System.Threading", "Interlocked");
                monitor_type         = CoreLookupType ("System.Threading", "Monitor");
                intptr_type          = CoreLookupType ("System", "IntPtr");
+               uintptr_type         = CoreLookupType ("System", "UIntPtr");
 
                attribute_type       = CoreLookupType ("System", "Attribute");
                attribute_usage_type = CoreLookupType ("System", "AttributeUsageAttribute");
@@ -1430,6 +1426,11 @@ public partial class TypeManager {
        {
                MemberCache cache;
 
+#if GMCS_SOURCE && MS_COMPATIBLE
+        if (t.IsGenericType && !t.IsGenericTypeDefinition)
+            t = t.GetGenericTypeDefinition();
+#endif
+
                //
                // 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.
@@ -1465,7 +1466,7 @@ public partial class TypeManager {
                // a TypeBuilder array will return a Type, not a TypeBuilder,
                // and we can not call FindMembers on this type.
                //
-               if (t == TypeManager.array_type || t.IsSubclassOf (TypeManager.array_type)) {
+               if (t.IsArray) { //  == TypeManager.array_type || t.IsSubclassOf (TypeManager.array_type)) {
                        used_cache = true;
                        return TypeHandle.ArrayType.MemberCache.FindMembers (
                                mt, bf, name, FilterWithClosure_delegate, null);
@@ -1483,8 +1484,9 @@ public partial class TypeManager {
                        used_cache = true;
                        return (MemberInfo []) list;
                }
+#endif
 
-               if (t.IsGenericType && (mt == MemberTypes.NestedType)) {
+               if (IsGenericType (t) && (mt == MemberTypes.NestedType)) {
                        //
                        // This happens if we're resolving a class'es base class and interfaces
                        // in TypeContainer.DefineType().  At this time, the types aren't
@@ -1495,7 +1497,6 @@ public partial class TypeManager {
                        used_cache = false;
                        return info;
                }
-#endif
 
                //
                // This call will always succeed.  There is exactly one TypeHandle instance per
@@ -1552,7 +1553,7 @@ public partial class TypeManager {
                        return true;
 
 #if MS_COMPATIBLE && GMCS_SOURCE
-               if (t.IsGenericParameter)
+               if (t.IsGenericParameter || t.IsGenericType)
                        return false;
 #endif
                return t.IsEnum;
@@ -1669,7 +1670,6 @@ public partial class TypeManager {
 
        public static bool IsSubclassOf (Type type, Type base_type)
        {
-#if GMCS_SOURCE
                TypeParameter tparam = LookupTypeParameter (type);
                TypeParameter pparam = LookupTypeParameter (base_type);
 
@@ -1680,10 +1680,9 @@ public partial class TypeManager {
                        return tparam.IsSubclassOf (base_type);
                }
 
-#if MS_COMPATIBLE
+#if MS_COMPATIBLE && GMCS_SOURCE
                if (type.IsGenericType)
                        type = type.GetGenericTypeDefinition ();
-#endif
 #endif
 
                if (type.IsSubclassOf (base_type))
@@ -1712,7 +1711,6 @@ public partial class TypeManager {
 
        public static bool IsFamilyAccessible (Type type, Type parent)
        {
-#if GMCS_SOURCE
                TypeParameter tparam = LookupTypeParameter (type);
                TypeParameter pparam = LookupTypeParameter (parent);
 
@@ -1722,7 +1720,6 @@ public partial class TypeManager {
 
                        return tparam.IsSubclassOf (parent);
                }
-#endif
 
                do {
                        if (IsInstantiationOfSameGenericType (type, parent))
@@ -2639,6 +2636,23 @@ public partial class TypeManager {
                return target_list;
        }
 
+#region Generics
+       // <remarks>
+       //   Tracks the generic parameters.
+       // </remarks>
+       static PtrHashtable builder_to_type_param;
+
+       public static void AddTypeParameter (Type t, TypeParameter tparam)
+       {
+               if (!builder_to_type_param.Contains (t))
+                       builder_to_type_param.Add (t, tparam);
+       }
+
+       public static TypeParameter LookupTypeParameter (Type t)
+       {
+               return (TypeParameter) builder_to_type_param [t];
+       }
+
        // This method always return false for non-generic compiler,
        // while Type.IsGenericParameter is returned if it is supported.
        public static bool IsGenericParameter (Type type)
@@ -2668,6 +2682,15 @@ public partial class TypeManager {
 #endif
        }
 
+       public static bool IsGenericTypeDefinition (Type type)
+       {
+#if GMCS_SOURCE
+               return type.IsGenericTypeDefinition;
+#else
+               return false;
+#endif
+       }
+
        public static bool ContainsGenericParameters (Type type)
        {
 #if GMCS_SOURCE
@@ -2677,10 +2700,34 @@ public partial class TypeManager {
 #endif
        }
 
+       public static FieldInfo GetGenericFieldDefinition (FieldInfo fi)
+       {
+#if GMCS_SOURCE
+               if (fi.DeclaringType.IsGenericTypeDefinition ||
+                   !fi.DeclaringType.IsGenericType)
+                       return fi;
+
+               Type t = fi.DeclaringType.GetGenericTypeDefinition ();
+               BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic |
+                       BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly;
+
+               foreach (FieldInfo f in t.GetFields (bf))
+                       if (f.MetadataToken == fi.MetadataToken)
+                               return f;
+#endif
+
+               return fi;
+       }
+
        public static bool IsEqual (Type a, Type b)
        {
-               if (a.Equals (b))
+               if (a.Equals (b)) {
+                       // MS BCL returns true even if enum types are different
+                       if (a.BaseType == TypeManager.enum_type || b.BaseType == TypeManager.enum_type)
+                               return a.FullName == b.FullName;
+
                        return true;
+               }
 
 #if GMCS_SOURCE
                if (a.IsGenericParameter && b.IsGenericParameter) {
@@ -2749,6 +2796,10 @@ public partial class TypeManager {
                BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic |
                        BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly;
 
+#if MS_COMPATIBLE
+               return m;
+#endif
+
                if (m is ConstructorInfo) {
                        foreach (ConstructorInfo c in t.GetConstructors (bf))
                                if (c.MetadataToken == m.MetadataToken)
@@ -2763,6 +2814,15 @@ public partial class TypeManager {
                return m;
        }
 
+       public static Type[] GetGenericArguments (MethodInfo mi)
+       {
+#if GMCS_SOURCE
+               return mi.GetGenericArguments ();
+#else
+               return Type.EmptyTypes;
+#endif
+       }
+
        public static Type[] GetTypeArguments (Type t)
        {
 #if GMCS_SOURCE
@@ -2825,6 +2885,80 @@ public partial class TypeManager {
                return type.Equals (parent);
        }
 
+       /// <summary>
+       ///   Whether `mb' is a generic method definition.
+       /// </summary>
+       public static bool IsGenericMethodDefinition (MethodBase mb)
+       {
+#if GMCS_SOURCE
+               if (mb.DeclaringType is TypeBuilder) {
+                       IMethodData method = (IMethodData) builder_to_method [mb];
+                       if (method == null)
+                               return false;
+
+                       return method.GenericMethod != null;
+               }
+
+               return mb.IsGenericMethodDefinition;
+#else
+               return false;
+#endif
+       }
+
+       /// <summary>
+       ///   Whether `mb' is a generic method.
+       /// </summary>
+       public static bool IsGenericMethod (MethodBase mb)
+       {
+#if GMCS_SOURCE
+               if (mb.DeclaringType is TypeBuilder) {
+                       IMethodData method = (IMethodData) builder_to_method [mb];
+                       if (method == null)
+                               return false;
+
+                       return method.GenericMethod != null;
+               }
+
+               return mb.IsGenericMethod;
+#else
+               return false;
+#endif
+       }
+
+       public static bool IsNullableType (Type t)
+       {
+#if GMCS_SOURCE
+               return generic_nullable_type == DropGenericTypeArguments (t);
+#else
+               return false;
+#endif
+       }
+
+       public static bool IsNullableTypeOf (Type t, Type nullable)
+       {
+#if GMCS_SOURCE
+               if (!IsNullableType (t))
+                       return false;
+
+               return GetTypeArguments (t) [0] == nullable;
+#else
+               return false;
+#endif
+       }
+
+       public static bool IsNullableValueType (Type t)
+       {
+#if GMCS_SOURCE
+               if (!IsNullableType (t))
+                       return false;
+
+               return GetTypeArguments (t) [0].IsValueType;
+#else
+               return false;
+#endif
+       }
+#endregion
+
 #region MemberLookup implementation
        
        //
@@ -2903,7 +3037,10 @@ public partial class TypeManager {
 
                                if (ma == MethodAttributes.Public)
                                        return true;
-                               
+
+                               if (ma == MethodAttributes.PrivateScope)
+                                       return false;
+
                                if (ma == MethodAttributes.Private)
                                        return private_ok ||
                                                IsPrivateAccessible (invocation_type, m.DeclaringType) ||
@@ -2928,7 +3065,10 @@ public partial class TypeManager {
                                
                                if (fa == FieldAttributes.Public)
                                        return true;
-                               
+
+                               if (fa == FieldAttributes.PrivateScope)
+                                       return false;
+
                                if (fa == FieldAttributes.Private)
                                        return private_ok ||
                                                IsPrivateAccessible (invocation_type, m.DeclaringType) ||
@@ -3172,19 +3312,79 @@ public partial class TypeManager {
                return null;
        }
 
-       // Tests whether external method is really special
-       public static bool IsSpecialMethod (MethodBase mb)
+       const BindingFlags AllMembers = BindingFlags.Public | BindingFlags.NonPublic |
+                                                                       BindingFlags.Static | BindingFlags.Instance | 
+                                                                       BindingFlags.DeclaredOnly;
+
+       // Currently is designed to work with external types only
+       public static PropertyInfo GetPropertyFromAccessor (MethodBase mb)
        {
+               if (!mb.IsSpecialName)
+                       return null;
+
                string name = mb.Name;
-               if (name.StartsWith ("get_") || name.StartsWith ("set_"))
-                       return mb.DeclaringType.GetProperty (name.Substring (4)) != null;
-                               
+               if (name.Length < 5)
+                       return null;
+
+               if (name [3] != '_')
+                       return null;
+
+               if (name.StartsWith ("get") || name.StartsWith ("set")) {
+                       MemberInfo[] pi = mb.DeclaringType.FindMembers (MemberTypes.Property, AllMembers,
+                               Type.FilterName, name.Substring (4));
+
+                       if (pi == null)
+                               return null;
+
+                       // This can happen when property is indexer (it can have same name but different parameters)
+                       foreach (PropertyInfo p in pi) {
+                               foreach (MethodInfo p_mi in p.GetAccessors (true)) {
+                                       if (p_mi == mb || TypeManager.GetParameterData (p_mi).Equals (TypeManager.GetParameterData (mb)))
+                                               return p;
+                               }
+                       }
+               }
+
+               return null;
+       }
+
+       // Currently is designed to work with external types only
+       public static MemberInfo GetEventFromAccessor (MethodBase mb)
+       {
+               if (!mb.IsSpecialName)
+                       return null;
+
+               string name = mb.Name;
+               if (name.Length < 5)
+                       return null;
+
                if (name.StartsWith ("add_"))
-                       return mb.DeclaringType.GetEvent (name.Substring (4)) != null;
+                       return mb.DeclaringType.GetEvent (name.Substring (4), AllMembers);
 
                if (name.StartsWith ("remove_"))
-                       return mb.DeclaringType.GetEvent (name.Substring (7)) != null;
+                       return mb.DeclaringType.GetEvent (name.Substring (7), AllMembers);
 
+               return null;
+       }
+
+       // Tests whether external method is really special
+       public static bool IsSpecialMethod (MethodBase mb)
+       {
+               if (!mb.IsSpecialName)
+                       return false;
+
+               IMethodData md = TypeManager.GetMethod (mb);
+               if (md != null) 
+                       return (md is AbstractPropertyEventMethod || md is Operator);
+
+               PropertyInfo pi = GetPropertyFromAccessor (mb);
+               if (pi != null)
+                       return IsValidProperty (pi);
+                               
+               if (GetEventFromAccessor (mb) != null)
+                       return true;
+
+               string name = mb.Name;
                if (name.StartsWith ("op_")){
                        foreach (string oname in Unary.oper_names) {
                                if (oname == name)
@@ -3199,6 +3399,22 @@ public partial class TypeManager {
                return false;
        }
 
+       // Tests whether imported property is valid C# property.
+       // TODO: It seems to me that we should do a lot of sanity tests before
+       // we accept property as C# property
+       static bool IsValidProperty (PropertyInfo pi)
+       {
+               MethodInfo get_method = pi.GetGetMethod (true);
+               MethodInfo set_method = pi.GetSetMethod (true);
+               if (get_method != null && set_method != null) {
+                       int g_count = get_method.GetParameters ().Length;
+                       int s_count = set_method.GetParameters ().Length;
+                       if (g_count + 1 != s_count)
+                               return false;
+               }
+               return true;
+       }
+
 #endregion
        
 }
@@ -3333,10 +3549,12 @@ public sealed class TypeHandle : IMemberContainer {
        public MemberList GetMembers (MemberTypes mt, BindingFlags bf)
        {
                 MemberInfo [] members;
+
 #if GMCS_SOURCE
                if (type is GenericTypeParameterBuilder)
                        return MemberList.Empty;
 #endif
+
                if (mt == MemberTypes.Event)
                         members = type.GetEvents (bf | BindingFlags.DeclaredOnly);
                 else