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