Patch from Matthew Metnestsky
[mono.git] / mcs / class / corlib / System.Reflection / MonoMethod.cs
index 39b1ac6640209b7f6eb2412a7203fc19e6509ed3..1e084107fa5769c6bfd6a941aed8a53bc7c813c2 100644 (file)
@@ -34,6 +34,9 @@ using System.Runtime.InteropServices;
 using System.Runtime.Serialization;
 using System.Reflection.Emit;
 using System.Security;
+using System.Threading;
+using System.Text;
+
 
 namespace System.Reflection {
        
@@ -62,9 +65,11 @@ namespace System.Reflection {
        [Serializable()]
        internal class MonoMethod : MethodInfo, ISerializable
        {
+#pragma warning disable 649
                internal IntPtr mhandle;
                string name;
                Type reftype;
+#pragma warning restore 649
 
                internal MonoMethod () {
                }
@@ -73,6 +78,9 @@ namespace System.Reflection {
                        this.mhandle = mhandle.Value;
                }
                
+               [MethodImplAttribute(MethodImplOptions.InternalCall)]
+               internal static extern string get_name (MethodBase method);
+
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                internal static extern MonoMethod get_base_definition (MonoMethod method);
 
@@ -117,37 +125,63 @@ namespace System.Reflection {
                 * binder to match the types of the method signature.
                 */
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               internal extern Object InternalInvoke (Object obj, Object[] parameters);
-               
+               internal extern Object InternalInvoke (Object obj, Object[] parameters, out Exception exc);
+
                public override Object Invoke (Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) 
                {
                        if (binder == null)
                                binder = Binder.DefaultBinder;
                        ParameterInfo[] pinfo = GetParameters ();
-                       if (!Binder.ConvertArgs (binder, parameters, pinfo, culture))
-                               throw new ArgumentException ("parameters");
 
+                       if ((parameters == null && pinfo.Length != 0) || (parameters != null && parameters.Length != pinfo.Length))
+                               throw new TargetParameterCountException ("parameters do not match signature");
+                       
+                       if ((invokeAttr & BindingFlags.ExactBinding) == 0) {
+                               if (!Binder.ConvertArgs (binder, parameters, pinfo, culture))
+                                       throw new ArgumentException ("failed to convert parameters");
+                       } else {
+                               for (int i = 0; i < pinfo.Length; i++)
+                                       if (parameters[i].GetType() != pinfo[i].ParameterType)
+                                               throw new ArgumentException ("parameters do not match signature");
+                       }
+
+#if !NET_2_1
                        if (SecurityManager.SecurityEnabled) {
                                // sadly Attributes doesn't tell us which kind of security action this is so
                                // we must do it the hard way - and it also means that we can skip calling
                                // Attribute (which is another an icall)
                                SecurityManager.ReflectedLinkDemandInvoke (this);
                        }
+#endif
 
 #if NET_2_0
                        if (ContainsGenericParameters)
                                throw new InvalidOperationException ("Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true.");
 #endif
 
+                       Exception exc;
+                       object o = null;
+
                        try {
-                               return InternalInvoke (obj, parameters);
-                       } catch (InvalidOperationException) {
+                               // The ex argument is used to distinguish exceptions thrown by the icall
+                               // from the exceptions thrown by the called method (which need to be
+                               // wrapped in TargetInvocationException).
+                               o = InternalInvoke (obj, parameters, out exc);
+#if NET_2_0
+                       } catch (ThreadAbortException) {
                                throw;
-                       } catch (TargetException) {
+#endif
+#if NET_2_1
+                       } catch (MethodAccessException) {
                                throw;
+#endif
                        } catch (Exception e) {
                                throw new TargetInvocationException (e);
                        }
+
+                       if (exc != null)
+                               throw exc;
+                       return o;
                }
 
                public override RuntimeMethodHandle MethodHandle { 
@@ -183,7 +217,9 @@ namespace System.Reflection {
                }
                public override string Name {
                        get {
-                               return name;
+                               if (name != null)
+                                       return name;
+                               return get_name (this);
                        }
                }
                
@@ -231,56 +267,87 @@ namespace System.Reflection {
                        return attrs;
                }
 
+               static bool ShouldPrintFullName (Type type) {
+                       return type.IsClass && (!type.IsPointer ||
+#if NET_2_0
+                               (!type.GetElementType ().IsPrimitive && !type.GetElementType ().IsNested));
+#else
+                               !type.GetElementType ().IsPrimitive);
+#endif
+               }
+
                public override string ToString () {
-                       string parms = "";
+                       StringBuilder sb = new StringBuilder ();
+                       Type retType = ReturnType;
+                       if (ShouldPrintFullName (retType))
+                               sb.Append (retType.ToString ());
+                       else
+                               sb.Append (retType.Name);
+                       sb.Append (" ");
+                       sb.Append (Name);
+#if NET_2_0 || BOOTSTRAP_NET_2_0
+                       if (IsGenericMethod) {
+                               Type[] gen_params = GetGenericArguments ();
+                               sb.Append ("[");
+                               for (int j = 0; j < gen_params.Length; j++) {
+                                       if (j > 0)
+                                               sb.Append (",");
+                                       sb.Append (gen_params [j].Name);
+                               }
+                               sb.Append ("]");
+                       }
+#endif
+                       sb.Append ("(");
                        ParameterInfo[] p = GetParameters ();
                        for (int i = 0; i < p.Length; ++i) {
                                if (i > 0)
-                                       parms = parms + ", ";
+                                       sb.Append (", ");
                                Type pt = p[i].ParameterType;
                                bool byref = pt.IsByRef;
                                if (byref)
                                        pt = pt.GetElementType ();
-                               if (pt.IsClass && pt.Namespace != "")
-                                       parms = parms + pt.Namespace + "." + pt.Name;
+                               if (ShouldPrintFullName (pt))
+                                       sb.Append (pt.ToString ());
                                else
-                                       parms = parms + pt.Name;
+                                       sb.Append (pt.Name);
                                if (byref)
-                                       parms += " ByRef";
+                                       sb.Append (" ByRef");
                        }
-                       if (ReturnType.IsClass && ReturnType.Namespace != "")
-                               return ReturnType.Namespace + "." + ReturnType.Name + " " + Name + "(" + parms + ")";
-                       string generic = "";
-#if NET_2_0 || BOOTSTRAP_NET_2_0
-                       if (IsGenericMethod) {
-                               Type[] gen_params = GetGenericArguments ();
-                               generic = "[";
-                               for (int j = 0; j < gen_params.Length; j++) {
-                                       if (j > 0)
-                                               generic += ",";
-                                       generic += gen_params [j].Name;
-                               }
-                               generic += "]";
+                       if ((CallingConvention & CallingConventions.VarArgs) != 0) {
+                               if (p.Length > 0)
+                                       sb.Append (", ");
+                               sb.Append ("...");
                        }
-#endif
-                       return ReturnType.Name + " " + Name + generic + "(" + parms + ")";
+                       
+                       sb.Append (")");
+                       return sb.ToString ();
                }
 
        
                // ISerializable
                public void GetObjectData(SerializationInfo info, StreamingContext context) 
                {
-                       ReflectionSerializationHolder.Serialize ( info, Name, ReflectedType, ToString(), MemberTypes.Method);
+#if NET_2_0
+                       Type[] genericArguments = IsGenericMethod && !IsGenericMethodDefinition
+                               ? GetGenericArguments () : null;
+                       MemberInfoSerializationHolder.Serialize ( info, Name, ReflectedType, ToString(), MemberTypes.Method, genericArguments);
+#else
+                       MemberInfoSerializationHolder.Serialize ( info, Name, ReflectedType, ToString(), MemberTypes.Method);
+#endif
                }
 
 #if NET_2_0 || BOOTSTRAP_NET_2_0
-               public override MethodInfo MakeGenericMethod (Type [] types)
+               public override MethodInfo MakeGenericMethod (Type [] methodInstantiation)
                {
-                       if (types == null)
-                               throw new ArgumentNullException ("types");
-                       MethodInfo ret = MakeGenericMethod_impl (types);
+                       if (methodInstantiation == null)
+                               throw new ArgumentNullException ("methodInstantiation");
+                       foreach (Type type in methodInstantiation)
+                               if (type == null)
+                                       throw new ArgumentNullException ();
+
+                       MethodInfo ret = MakeGenericMethod_impl (methodInstantiation);
                        if (ret == null)
-                               throw new ArgumentException (String.Format ("The method has {0} generic parameter(s) but {1} generic argument(s) were provided.", GetGenericArguments ().Length, types.Length));
+                               throw new ArgumentException (String.Format ("The method has {0} generic parameter(s) but {1} generic argument(s) were provided.", GetGenericArguments ().Length, methodInstantiation.Length));
                        return ret;
                }
 
@@ -333,9 +400,11 @@ namespace System.Reflection {
        
        internal class MonoCMethod : ConstructorInfo, ISerializable
        {
+#pragma warning disable 649            
                internal IntPtr mhandle;
                string name;
                Type reftype;
+#pragma warning restore 649            
                
                public override MethodImplAttributes GetMethodImplementationFlags() {
                        MonoMethodInfo info;
@@ -352,15 +421,26 @@ namespace System.Reflection {
                 * to match the types of the method signature.
                 */
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               internal extern Object InternalInvoke (Object obj, Object[] parameters);
+               internal extern Object InternalInvoke (Object obj, Object[] parameters, out Exception exc);
 
                public override Object Invoke (Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) 
                {
                        if (binder == null)
                                binder = Binder.DefaultBinder;
+
                        ParameterInfo[] pinfo = GetParameters ();
-                       if (!Binder.ConvertArgs (binder, parameters, pinfo, culture))
-                               throw new ArgumentException ("parameters");
+
+                       if ((parameters == null && pinfo.Length != 0) || (parameters != null && parameters.Length != pinfo.Length))
+                               throw new TargetParameterCountException ("parameters do not match signature");
+                       
+                       if ((invokeAttr & BindingFlags.ExactBinding) == 0) {
+                               if (!Binder.ConvertArgs (binder, parameters, pinfo, culture))
+                                       throw new ArgumentException ("failed to convert parameters");
+                       } else {
+                               for (int i = 0; i < pinfo.Length; i++)
+                                       if (parameters[i].GetType() != pinfo[i].ParameterType)
+                                               throw new ArgumentException ("parameters do not match signature");
+                       }
 
                        if (SecurityManager.SecurityEnabled) {
                                // sadly Attributes doesn't tell us which kind of security action this is so
@@ -369,15 +449,31 @@ namespace System.Reflection {
                                SecurityManager.ReflectedLinkDemandInvoke (this);
                        }
 
+#if NET_2_0
+                       if (obj == null && DeclaringType.ContainsGenericParameters)
+                               throw new MemberAccessException ("Cannot create an instance of " + DeclaringType + " because Type.ContainsGenericParameters is true.");
+#endif
+
+                       if ((invokeAttr & BindingFlags.CreateInstance) != 0 && DeclaringType.IsAbstract) {
+                               throw new MemberAccessException (String.Format ("Cannot create an instance of {0} because it is an abstract class", DeclaringType));
+                       }
+
+                       Exception exc = null;
+                       object o = null;
+
                        try {
-                               return InternalInvoke (obj, parameters);
-                       } catch (InvalidOperationException) {
-                               throw;
-                       } catch (TargetException) {
+                               o = InternalInvoke (obj, parameters, out exc);
+#if NET_2_1
+                       } catch (MethodAccessException) {
                                throw;
+#endif
                        } catch (Exception e) {
                                throw new TargetInvocationException (e);
                        }
+
+                       if (exc != null)
+                               throw exc;
+                       return (obj == null) ? o : null;
                }
 
                public override Object Invoke (BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) {
@@ -417,7 +513,9 @@ namespace System.Reflection {
                }
                public override string Name {
                        get {
-                               return name;
+                               if (name != null)
+                                       return name;
+                               return MonoMethod.get_name (this);
                        }
                }
 
@@ -433,20 +531,6 @@ namespace System.Reflection {
                        return MonoCustomAttrs.GetCustomAttributes (this, attributeType, inherit);
                }
 
-#if NET_2_0 || BOOTSTRAP_NET_2_0
-               public override bool IsGenericMethodDefinition {
-                       get {
-                               return false;
-                       }
-               }
-
-               public override bool IsGenericMethod {
-                       get {
-                               return false;
-                       }
-               }
-#endif
-
 #if NET_2_0
                public override MethodBody GetMethodBody () {
                        return GetMethodBody (mhandle);
@@ -454,20 +538,24 @@ namespace System.Reflection {
 #endif
 
                public override string ToString () {
-                       string parms = "";
+                       StringBuilder sb = new StringBuilder ();
+                       sb.Append ("Void ");
+                       sb.Append (Name);
+                       sb.Append ("(");
                        ParameterInfo[] p = GetParameters ();
                        for (int i = 0; i < p.Length; ++i) {
                                if (i > 0)
-                                       parms = parms + ", ";
-                               parms = parms + p [i].ParameterType.Name;
+                                       sb.Append (", ");
+                               sb.Append (p[i].ParameterType.Name);
                        }
-                       return "Void "+Name+"("+parms+")";
+                       sb.Append (")");
+                       return sb.ToString ();
                }
 
                // ISerializable
                public void GetObjectData(SerializationInfo info, StreamingContext context) 
                {
-                       ReflectionSerializationHolder.Serialize ( info, Name, ReflectedType, ToString(), MemberTypes.Constructor);
+                       MemberInfoSerializationHolder.Serialize ( info, Name, ReflectedType, ToString(), MemberTypes.Constructor);
                }
        }
 }