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