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