New tests.
[mono.git] / mcs / class / corlib / System.Reflection / MonoMethod.cs
1 //
2 // System.Reflection/MonoMethod.cs
3 // The class used to represent methods from the mono runtime.
4 //
5 // Author:
6 //   Paolo Molaro (lupus@ximian.com)
7 //
8 // (C) 2001 Ximian, Inc.  http://www.ximian.com
9 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System.Collections.Generic;
32 using System.Globalization;
33 using System.Runtime.CompilerServices;
34 using System.Runtime.InteropServices;
35 using System.Runtime.Serialization;
36 using System.Reflection.Emit;
37 using System.Security;
38 using System.Threading;
39 using System.Text;
40
41
42 namespace System.Reflection {
43         
44         internal struct MonoMethodInfo 
45         {
46 #pragma warning disable 649     
47                 private Type parent;
48                 private Type ret;
49                 internal MethodAttributes attrs;
50                 internal MethodImplAttributes iattrs;
51                 private CallingConventions callconv;
52 #pragma warning restore 649             
53
54                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
55                 static extern void get_method_info (IntPtr handle, out MonoMethodInfo info);
56                 
57                 internal static MonoMethodInfo GetMethodInfo (IntPtr handle)
58                 {
59                         MonoMethodInfo info;
60                         MonoMethodInfo.get_method_info (handle, out info);
61                         return info;
62                 }
63
64                 internal static Type GetDeclaringType (IntPtr handle)
65                 {
66                         return GetMethodInfo (handle).parent;
67                 }
68
69                 internal static Type GetReturnType (IntPtr handle)
70                 {
71                         return GetMethodInfo (handle).ret;
72                 }
73
74                 internal static MethodAttributes GetAttributes (IntPtr handle)
75                 {
76                         return GetMethodInfo (handle).attrs;
77                 }
78
79                 internal static CallingConventions GetCallingConvention (IntPtr handle)
80                 {
81                         return GetMethodInfo (handle).callconv;
82                 }
83
84                 internal static MethodImplAttributes GetMethodImplementationFlags (IntPtr handle)
85                 {
86                         return GetMethodInfo (handle).iattrs;
87                 }
88
89                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
90                 static extern ParameterInfo[] get_parameter_info (IntPtr handle, MemberInfo member);
91
92                 static internal ParameterInfo[] GetParametersInfo (IntPtr handle, MemberInfo member)
93                 {
94                         return get_parameter_info (handle, member);
95                 }
96
97                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
98                 static extern UnmanagedMarshal get_retval_marshal (IntPtr handle);
99
100                 static internal ParameterInfo GetReturnParameterInfo (MonoMethod method)
101                 {
102                         return new ParameterInfo (GetReturnType (method.mhandle), method, get_retval_marshal (method.mhandle));
103                 }
104         };
105         
106         /*
107          * Note: most of this class needs to be duplicated for the contructor, since
108          * the .NET reflection class hierarchy is so broken.
109          */
110         [Serializable()]
111         internal class MonoMethod : MethodInfo, ISerializable
112         {
113 #pragma warning disable 649
114                 internal IntPtr mhandle;
115                 string name;
116                 Type reftype;
117 #pragma warning restore 649
118
119                 internal MonoMethod () {
120                 }
121
122                 internal MonoMethod (RuntimeMethodHandle mhandle) {
123                         this.mhandle = mhandle.Value;
124                 }
125                 
126                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
127                 internal static extern string get_name (MethodBase method);
128
129                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
130                 internal static extern MonoMethod get_base_method (MonoMethod method, bool definition);
131
132                 public override MethodInfo GetBaseDefinition ()
133                 {
134                         return get_base_method (this, true);
135                 }
136
137                 internal override MethodInfo GetBaseMethod ()
138                 {
139                         return get_base_method (this, false);
140                 }
141
142                 public override ParameterInfo ReturnParameter {
143                         get {
144                                 return MonoMethodInfo.GetReturnParameterInfo (this);
145                         }
146                 }
147
148                 public override Type ReturnType {
149                         get {
150                                 return MonoMethodInfo.GetReturnType (mhandle);
151                         }
152                 }
153                 public override ICustomAttributeProvider ReturnTypeCustomAttributes { 
154                         get {
155                                 return MonoMethodInfo.GetReturnParameterInfo (this);
156                         }
157                 }
158                 
159                 public override MethodImplAttributes GetMethodImplementationFlags ()
160                 {
161                         return MonoMethodInfo.GetMethodImplementationFlags (mhandle);
162                 }
163
164                 public override ParameterInfo[] GetParameters ()
165                 {
166                         ParameterInfo[] src = MonoMethodInfo.GetParametersInfo (mhandle, this);
167                         ParameterInfo[] res = new ParameterInfo [src.Length];
168                         src.CopyTo (res, 0);
169                         return res;
170                 }
171                 
172                 internal override int GetParameterCount ()
173                 {
174                         var pi = MonoMethodInfo.GetParametersInfo (mhandle, this);
175                         return pi == null ? 0 : pi.Length;
176                 }
177
178                 /*
179                  * InternalInvoke() receives the parameters correctly converted by the 
180                  * binder to match the types of the method signature.
181                  */
182                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
183                 internal extern Object InternalInvoke (Object obj, Object[] parameters, out Exception exc);
184
185                 public override Object Invoke (Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) 
186                 {
187                         if (binder == null)
188                                 binder = Binder.DefaultBinder;
189                         /*Avoid allocating an array every time*/
190                         ParameterInfo[] pinfo = MonoMethodInfo.GetParametersInfo (mhandle, this);
191
192                         if ((parameters == null && pinfo.Length != 0) || (parameters != null && parameters.Length != pinfo.Length))
193                                 throw new TargetParameterCountException ("parameters do not match signature");
194                         
195                         if ((invokeAttr & BindingFlags.ExactBinding) == 0) {
196                                 if (!Binder.ConvertArgs (binder, parameters, pinfo, culture))
197                                         throw new ArgumentException ("failed to convert parameters");
198                         } else {
199                                 for (int i = 0; i < pinfo.Length; i++)
200                                         if (parameters[i].GetType() != pinfo[i].ParameterType)
201                                                 throw new ArgumentException ("parameters do not match signature");
202                         }
203
204 #if !NET_2_1
205                         if (SecurityManager.SecurityEnabled) {
206                                 // sadly Attributes doesn't tell us which kind of security action this is so
207                                 // we must do it the hard way - and it also means that we can skip calling
208                                 // Attribute (which is another an icall)
209                                 SecurityManager.ReflectedLinkDemandInvoke (this);
210                         }
211 #endif
212
213                         if (ContainsGenericParameters)
214                                 throw new InvalidOperationException ("Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true.");
215
216                         Exception exc;
217                         object o = null;
218
219                         try {
220                                 // The ex argument is used to distinguish exceptions thrown by the icall
221                                 // from the exceptions thrown by the called method (which need to be
222                                 // wrapped in TargetInvocationException).
223                                 o = InternalInvoke (obj, parameters, out exc);
224                         } catch (ThreadAbortException) {
225                                 throw;
226 #if NET_2_1
227                         } catch (MethodAccessException) {
228                                 throw;
229 #endif
230                         } catch (Exception e) {
231                                 throw new TargetInvocationException (e);
232                         }
233
234                         if (exc != null)
235                                 throw exc;
236                         return o;
237                 }
238
239                 public override RuntimeMethodHandle MethodHandle { 
240                         get {return new RuntimeMethodHandle (mhandle);} 
241                 }
242                 public override MethodAttributes Attributes { 
243                         get {
244                                 return MonoMethodInfo.GetAttributes (mhandle);
245                         } 
246                 }
247
248                 public override CallingConventions CallingConvention { 
249                         get {
250                                 return MonoMethodInfo.GetCallingConvention (mhandle);
251                         }
252                 }
253                 
254                 public override Type ReflectedType {
255                         get {
256                                 return reftype;
257                         }
258                 }
259                 public override Type DeclaringType {
260                         get {
261                                 return MonoMethodInfo.GetDeclaringType (mhandle);
262                         }
263                 }
264                 public override string Name {
265                         get {
266                                 if (name != null)
267                                         return name;
268                                 return get_name (this);
269                         }
270                 }
271                 
272                 public override bool IsDefined (Type attributeType, bool inherit) {
273                         return MonoCustomAttrs.IsDefined (this, attributeType, inherit);
274                 }
275
276                 public override object[] GetCustomAttributes( bool inherit) {
277                         return MonoCustomAttrs.GetCustomAttributes (this, inherit);
278                 }
279                 public override object[] GetCustomAttributes( Type attributeType, bool inherit) {
280                         return MonoCustomAttrs.GetCustomAttributes (this, attributeType, inherit);
281                 }
282
283                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
284                 internal static extern DllImportAttribute GetDllImportAttribute (IntPtr mhandle);
285
286                 internal object[] GetPseudoCustomAttributes ()
287                 {
288                         int count = 0;
289
290                         /* MS.NET doesn't report MethodImplAttribute */
291
292                         MonoMethodInfo info = MonoMethodInfo.GetMethodInfo (mhandle);
293                         if ((info.iattrs & MethodImplAttributes.PreserveSig) != 0)
294                                 count ++;
295                         if ((info.attrs & MethodAttributes.PinvokeImpl) != 0)
296                                 count ++;
297                         
298                         if (count == 0)
299                                 return null;
300                         object[] attrs = new object [count];
301                         count = 0;
302
303                         if ((info.iattrs & MethodImplAttributes.PreserveSig) != 0)
304                                 attrs [count ++] = new PreserveSigAttribute ();
305                         if ((info.attrs & MethodAttributes.PinvokeImpl) != 0) {
306                                 DllImportAttribute attr = GetDllImportAttribute (mhandle);
307                                 if ((info.iattrs & MethodImplAttributes.PreserveSig) != 0)
308                                         attr.PreserveSig = true;
309                                 attrs [count ++] = attr;
310                         }
311
312                         return attrs;
313                 }
314
315                 static bool ShouldPrintFullName (Type type) {
316                         return type.IsClass && (!type.IsPointer ||
317                                 (!type.GetElementType ().IsPrimitive && !type.GetElementType ().IsNested));
318                 }
319
320                 public override string ToString () {
321                         StringBuilder sb = new StringBuilder ();
322                         Type retType = ReturnType;
323                         if (ShouldPrintFullName (retType))
324                                 sb.Append (retType.ToString ());
325                         else
326                                 sb.Append (retType.Name);
327                         sb.Append (" ");
328                         sb.Append (Name);
329                         if (IsGenericMethod) {
330                                 Type[] gen_params = GetGenericArguments ();
331                                 sb.Append ("[");
332                                 for (int j = 0; j < gen_params.Length; j++) {
333                                         if (j > 0)
334                                                 sb.Append (",");
335                                         sb.Append (gen_params [j].Name);
336                                 }
337                                 sb.Append ("]");
338                         }
339                         sb.Append ("(");
340                         ParameterInfo[] p = GetParameters ();
341                         for (int i = 0; i < p.Length; ++i) {
342                                 if (i > 0)
343                                         sb.Append (", ");
344                                 Type pt = p[i].ParameterType;
345                                 bool byref = pt.IsByRef;
346                                 if (byref)
347                                         pt = pt.GetElementType ();
348                                 if (ShouldPrintFullName (pt))
349                                         sb.Append (pt.ToString ());
350                                 else
351                                         sb.Append (pt.Name);
352                                 if (byref)
353                                         sb.Append (" ByRef");
354                         }
355                         if ((CallingConvention & CallingConventions.VarArgs) != 0) {
356                                 if (p.Length > 0)
357                                         sb.Append (", ");
358                                 sb.Append ("...");
359                         }
360                         
361                         sb.Append (")");
362                         return sb.ToString ();
363                 }
364
365         
366                 // ISerializable
367                 public void GetObjectData(SerializationInfo info, StreamingContext context) 
368                 {
369                         Type[] genericArguments = IsGenericMethod && !IsGenericMethodDefinition
370                                 ? GetGenericArguments () : null;
371                         MemberInfoSerializationHolder.Serialize ( info, Name, ReflectedType, ToString(), MemberTypes.Method, genericArguments);
372                 }
373
374                 public override MethodInfo MakeGenericMethod (Type [] methodInstantiation)
375                 {
376                         if (methodInstantiation == null)
377                                 throw new ArgumentNullException ("methodInstantiation");
378
379                         if (!IsGenericMethodDefinition)
380                                 throw new InvalidOperationException ("not a generic method definition");
381
382                         /*FIXME add GetGenericArgumentsLength() internal vcall to speed this up*/
383                         if (GetGenericArguments ().Length != methodInstantiation.Length)
384                                 throw new ArgumentException ("Incorrect length");
385
386                         bool hasUserType = false;
387                         foreach (Type type in methodInstantiation) {
388                                 if (type == null)
389                                         throw new ArgumentNullException ();
390                                 if (!(type is MonoType))
391                                         hasUserType = true;
392                         }
393
394                         if (hasUserType)
395                                 return new MethodOnTypeBuilderInst (this, methodInstantiation);
396
397                         MethodInfo ret = MakeGenericMethod_impl (methodInstantiation);
398                         if (ret == null)
399                                 throw new ArgumentException (String.Format ("The method has {0} generic parameter(s) but {1} generic argument(s) were provided.", GetGenericArguments ().Length, methodInstantiation.Length));
400                         return ret;
401                 }
402
403                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
404                 extern MethodInfo MakeGenericMethod_impl (Type [] types);
405
406                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
407                 public override extern Type [] GetGenericArguments ();
408
409                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
410                 extern MethodInfo GetGenericMethodDefinition_impl ();
411
412                 public override MethodInfo GetGenericMethodDefinition ()
413                 {
414                         MethodInfo res = GetGenericMethodDefinition_impl ();
415                         if (res == null)
416                                 throw new InvalidOperationException ();
417
418                         return res;
419                 }
420
421                 public override extern bool IsGenericMethodDefinition {
422                         [MethodImplAttribute(MethodImplOptions.InternalCall)]
423                         get;
424                 }
425
426                 public override extern bool IsGenericMethod {
427                         [MethodImplAttribute(MethodImplOptions.InternalCall)]
428                         get;
429                 }
430
431                 public override bool ContainsGenericParameters {
432                         get {
433                                 if (IsGenericMethod) {
434                                         foreach (Type arg in GetGenericArguments ())
435                                                 if (arg.ContainsGenericParameters)
436                                                         return true;
437                                 }
438                                 return DeclaringType.ContainsGenericParameters;
439                         }
440                 }
441
442                 public override MethodBody GetMethodBody () {
443                         return GetMethodBody (mhandle);
444                 }
445
446 #if NET_4_0
447                 public override IList<CustomAttributeData> GetCustomAttributesData () {
448                         return CustomAttributeData.GetCustomAttributes (this);
449                 }
450 #endif
451         }
452         
453         internal class MonoCMethod : ConstructorInfo, ISerializable
454         {
455 #pragma warning disable 649             
456                 internal IntPtr mhandle;
457                 string name;
458                 Type reftype;
459 #pragma warning restore 649             
460                 
461                 public override MethodImplAttributes GetMethodImplementationFlags ()
462                 {
463                         return MonoMethodInfo.GetMethodImplementationFlags (mhandle);
464                 }
465
466                 public override ParameterInfo[] GetParameters ()
467                 {
468                         return MonoMethodInfo.GetParametersInfo (mhandle, this);
469                 }
470
471                 internal override int GetParameterCount ()
472                 {
473                         var pi = MonoMethodInfo.GetParametersInfo (mhandle, this);
474                         return pi == null ? 0 : pi.Length;
475                 }
476
477                 /*
478                  * InternalInvoke() receives the parameters corretcly converted by the binder
479                  * to match the types of the method signature.
480                  */
481                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
482                 internal extern Object InternalInvoke (Object obj, Object[] parameters, out Exception exc);
483
484                 public override Object Invoke (Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) 
485                 {
486                         if (binder == null)
487                                 binder = Binder.DefaultBinder;
488
489                         ParameterInfo[] pinfo = GetParameters ();
490
491                         if ((parameters == null && pinfo.Length != 0) || (parameters != null && parameters.Length != pinfo.Length))
492                                 throw new TargetParameterCountException ("parameters do not match signature");
493                         
494                         if ((invokeAttr & BindingFlags.ExactBinding) == 0) {
495                                 if (!Binder.ConvertArgs (binder, parameters, pinfo, culture))
496                                         throw new ArgumentException ("failed to convert parameters");
497                         } else {
498                                 for (int i = 0; i < pinfo.Length; i++)
499                                         if (parameters[i].GetType() != pinfo[i].ParameterType)
500                                                 throw new ArgumentException ("parameters do not match signature");
501                         }
502
503 #if !NET_2_1
504                         if (SecurityManager.SecurityEnabled) {
505                                 // sadly Attributes doesn't tell us which kind of security action this is so
506                                 // we must do it the hard way - and it also means that we can skip calling
507                                 // Attribute (which is another an icall)
508                                 SecurityManager.ReflectedLinkDemandInvoke (this);
509                         }
510 #endif
511
512                         if (obj == null && DeclaringType.ContainsGenericParameters)
513                                 throw new MemberAccessException ("Cannot create an instance of " + DeclaringType + " because Type.ContainsGenericParameters is true.");
514
515                         if ((invokeAttr & BindingFlags.CreateInstance) != 0 && DeclaringType.IsAbstract) {
516                                 throw new MemberAccessException (String.Format ("Cannot create an instance of {0} because it is an abstract class", DeclaringType));
517                         }
518
519                         Exception exc = null;
520                         object o = null;
521
522                         try {
523                                 o = InternalInvoke (obj, parameters, out exc);
524 #if NET_2_1
525                         } catch (MethodAccessException) {
526                                 throw;
527 #endif
528                         } catch (Exception e) {
529                                 throw new TargetInvocationException (e);
530                         }
531
532                         if (exc != null)
533                                 throw exc;
534                         return (obj == null) ? o : null;
535                 }
536
537                 public override Object Invoke (BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) {
538                         return Invoke (null, invokeAttr, binder, parameters, culture);
539                 }
540
541                 public override RuntimeMethodHandle MethodHandle { 
542                         get {return new RuntimeMethodHandle (mhandle);} 
543                 }
544                 public override MethodAttributes Attributes { 
545                         get {
546                                 return MonoMethodInfo.GetAttributes (mhandle);
547                         } 
548                 }
549
550                 public override CallingConventions CallingConvention { 
551                         get {
552                                 return MonoMethodInfo.GetCallingConvention (mhandle);
553                         }
554                 }
555                 
556                 public override Type ReflectedType {
557                         get {
558                                 return reftype;
559                         }
560                 }
561                 public override Type DeclaringType {
562                         get {
563                                 return MonoMethodInfo.GetDeclaringType (mhandle);
564                         }
565                 }
566                 public override string Name {
567                         get {
568                                 if (name != null)
569                                         return name;
570                                 return MonoMethod.get_name (this);
571                         }
572                 }
573
574                 public override bool IsDefined (Type attributeType, bool inherit) {
575                         return MonoCustomAttrs.IsDefined (this, attributeType, inherit);
576                 }
577
578                 public override object[] GetCustomAttributes( bool inherit) {
579                         return MonoCustomAttrs.GetCustomAttributes (this, inherit);
580                 }
581
582                 public override object[] GetCustomAttributes( Type attributeType, bool inherit) {
583                         return MonoCustomAttrs.GetCustomAttributes (this, attributeType, inherit);
584                 }
585
586                 public override MethodBody GetMethodBody () {
587                         return GetMethodBody (mhandle);
588                 }
589
590                 public override string ToString () {
591                         StringBuilder sb = new StringBuilder ();
592                         sb.Append ("Void ");
593                         sb.Append (Name);
594                         sb.Append ("(");
595                         ParameterInfo[] p = GetParameters ();
596                         for (int i = 0; i < p.Length; ++i) {
597                                 if (i > 0)
598                                         sb.Append (", ");
599                                 sb.Append (p[i].ParameterType.Name);
600                         }
601                         if (CallingConvention == CallingConventions.Any)
602                                 sb.Append (", ...");
603                         sb.Append (")");
604                         return sb.ToString ();
605                 }
606
607                 // ISerializable
608                 public void GetObjectData(SerializationInfo info, StreamingContext context) 
609                 {
610                         MemberInfoSerializationHolder.Serialize ( info, Name, ReflectedType, ToString(), MemberTypes.Constructor);
611                 }
612
613 #if NET_4_0
614                 public override IList<CustomAttributeData> GetCustomAttributesData () {
615                         return CustomAttributeData.GetCustomAttributes (this);
616                 }
617 #endif
618         }
619 }