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