Merge pull request #1936 from esdrubal/DotNetRelativeOrAbsolute
[mono.git] / mcs / class / corlib / System.Reflection / MonoProperty.cs
1 //
2 // MonoProperty.cs: The class used to represent Properties from the mono runtime.
3 //
4 // Authors:
5 //   Paolo Molaro (lupus@ximian.com)
6 //   Patrik Torstensson (patrik.torstensson@labs2.com)
7 //   Marek Safar (marek.safar@gmail.com)
8 //
9 // (C) 2001 Ximian, Inc.  http://www.ximian.com
10 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
11 // Copyright 2013 Xamarin, Inc (http://www.xamarin.com)
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System.Collections.Generic;
34 using System.Globalization;
35 using System.Runtime.CompilerServices;
36 using System.Runtime.InteropServices;
37 using System.Runtime.Serialization;
38 using System.Security;
39 using System.Text;
40 using System.Diagnostics.Contracts;
41
42 namespace System.Reflection {
43         
44         internal struct MonoPropertyInfo {
45                 public Type parent;
46                 public Type declaring_type;
47                 public String name;
48                 public MethodInfo get_method;
49                 public MethodInfo set_method;
50                 public PropertyAttributes attrs;
51                 
52                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
53                 internal static extern void get_property_info (MonoProperty prop, ref MonoPropertyInfo info,
54                                                                PInfo req_info);
55
56                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
57                 internal static extern Type[] GetTypeModifiers (MonoProperty prop, bool optional);
58
59                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
60                 internal static extern object get_default_value (MonoProperty prop);
61         }
62
63         [Flags]
64         internal enum PInfo {
65                 Attributes = 1,
66                 GetMethod  = 1 << 1,
67                 SetMethod  = 1 << 2,
68                 ReflectedType = 1 << 3,
69                 DeclaringType = 1 << 4,
70                 Name = 1 << 5
71                 
72         }
73
74         internal delegate object GetterAdapter (object _this);
75         internal delegate R Getter<T,R> (T _this);
76
77         abstract class RuntimePropertyInfo : PropertyInfo, ISerializable
78         {
79                 internal BindingFlags BindingFlags {
80                         get {
81                                 return 0;
82                         }
83                 }
84
85                 public override Module Module {
86                         get {
87                                 return GetRuntimeModule ();
88                         }
89                 }
90
91                 internal RuntimeType GetDeclaringTypeInternal ()
92                 {
93                         return (RuntimeType) DeclaringType;
94                 }
95
96                 RuntimeType ReflectedTypeInternal {
97                         get {
98                                 return (RuntimeType) ReflectedType;
99                         }
100                 }
101
102                 internal RuntimeModule GetRuntimeModule ()
103                 {
104                         return GetDeclaringTypeInternal ().GetRuntimeModule ();
105                 }
106
107         #region Object Overrides
108         public override String ToString()
109         {
110             return FormatNameAndSig(false);
111         }
112
113         private string FormatNameAndSig(bool serialization)
114         {
115             StringBuilder sbName = new StringBuilder(PropertyType.FormatTypeName(serialization));
116
117             sbName.Append(" ");
118             sbName.Append(Name);
119
120                         var pi = GetIndexParameters ();
121                         if (pi.Length > 0) {
122                                 sbName.Append (" [");
123                                 ParameterInfo.FormatParameters (sbName, pi, 0, serialization);
124                                 sbName.Append ("]");
125                         }
126
127             return sbName.ToString();
128         }
129         #endregion              
130
131         #region ISerializable Implementation
132         public void GetObjectData(SerializationInfo info, StreamingContext context)
133         {
134             if (info == null)
135                 throw new ArgumentNullException("info");
136             Contract.EndContractBlock();
137
138             MemberInfoSerializationHolder.GetSerializationInfo(
139                 info,
140                 Name,
141                 ReflectedTypeInternal,
142                 ToString(),
143                 SerializationToString(),
144                 MemberTypes.Property,
145                 null);
146         }
147
148         internal string SerializationToString()
149         {
150             return FormatNameAndSig(true);
151         }
152         #endregion
153         }
154
155         [Serializable]
156         [StructLayout (LayoutKind.Sequential)]
157         internal class MonoProperty : RuntimePropertyInfo {
158 #pragma warning disable 649
159                 internal IntPtr klass;
160                 internal IntPtr prop;
161                 MonoPropertyInfo info;
162                 PInfo cached;
163                 GetterAdapter cached_getter;
164
165 #pragma warning restore 649
166
167                 void CachePropertyInfo (PInfo flags)
168                 {
169                         if ((cached & flags) != flags) {
170                                 MonoPropertyInfo.get_property_info (this, ref info, flags);
171                                 cached |= flags;
172                         }
173                 }
174                 
175                 public override PropertyAttributes Attributes {
176                         get {
177                                 CachePropertyInfo (PInfo.Attributes);
178                                 return info.attrs;
179                         }
180                 }
181                 
182                 public override bool CanRead {
183                         get {
184                                 CachePropertyInfo (PInfo.GetMethod);
185                                 return (info.get_method != null);
186                         }
187                 }
188                 
189                 public override bool CanWrite {
190                         get {
191                                 CachePropertyInfo (PInfo.SetMethod);
192                                 return (info.set_method != null);
193                         }
194                 }
195
196                 public override Type PropertyType {
197                         get {
198                                 CachePropertyInfo (PInfo.GetMethod | PInfo.SetMethod);
199
200                                 if (info.get_method != null) {
201                                         return info.get_method.ReturnType;
202                                 } else {
203                                         ParameterInfo[] parameters = info.set_method.GetParametersInternal ();
204                                         
205                                         return parameters [parameters.Length - 1].ParameterType;
206                                 }
207                         }
208                 }
209
210                 public override Type ReflectedType {
211                         get {
212                                 CachePropertyInfo (PInfo.ReflectedType);
213                                 return info.parent;
214                         }
215                 }
216                 
217                 public override Type DeclaringType {
218                         get {
219                                 CachePropertyInfo (PInfo.DeclaringType);
220                                 return info.declaring_type;
221                         }
222                 }
223                 
224                 public override string Name {
225                         get {
226                                 CachePropertyInfo (PInfo.Name);
227                                 return info.name;
228                         }
229                 }
230
231                 public override MethodInfo[] GetAccessors (bool nonPublic)
232                 {
233                         int nget = 0;
234                         int nset = 0;
235                         
236                         CachePropertyInfo (PInfo.GetMethod | PInfo.SetMethod);
237
238                         if (info.set_method != null && (nonPublic || info.set_method.IsPublic))
239                                 nset = 1;
240                         if (info.get_method != null && (nonPublic || info.get_method.IsPublic))
241                                 nget = 1;
242
243                         MethodInfo[] res = new MethodInfo [nget + nset];
244                         int n = 0;
245                         if (nset != 0)
246                                 res [n++] = info.set_method;
247                         if (nget != 0)
248                                 res [n++] = info.get_method;
249                         return res;
250                 }
251
252                 public override MethodInfo GetGetMethod (bool nonPublic)
253                 {
254                         CachePropertyInfo (PInfo.GetMethod);
255                         if (info.get_method != null && (nonPublic || info.get_method.IsPublic))
256                                 return info.get_method;
257                         else
258                                 return null;
259                 }
260
261                 public override ParameterInfo[] GetIndexParameters ()
262                 {
263                         CachePropertyInfo (PInfo.GetMethod | PInfo.SetMethod);
264                         ParameterInfo[] src;
265                         int length;
266                         if (info.get_method != null) {
267                                 src = info.get_method.GetParametersInternal ();
268                                 length = src.Length;
269                         } else if (info.set_method != null) {
270                                 src = info.set_method.GetParametersInternal ();
271                                 length = src.Length - 1;
272                         } else
273                                 return EmptyArray<ParameterInfo>.Value;
274
275                         var dest = new ParameterInfo [length];
276                         for (int i = 0; i < length; ++i) {
277                                 dest [i] = ParameterInfo.New (src [i], this);
278                         }
279                         return dest;    
280                 }
281                 
282                 public override MethodInfo GetSetMethod (bool nonPublic)
283                 {
284                         CachePropertyInfo (PInfo.SetMethod);
285                         if (info.set_method != null && (nonPublic || info.set_method.IsPublic))
286                                 return info.set_method;
287                         else
288                                 return null;
289                 }
290
291
292                 /*TODO verify for attribute based default values, just like ParameterInfo*/
293                 public override object GetConstantValue ()
294                 {
295                         return MonoPropertyInfo.get_default_value (this);
296                 }
297
298                 public override object GetRawConstantValue() {
299                         return MonoPropertyInfo.get_default_value (this);
300                 }
301
302                 // According to MSDN the inherit parameter is ignored here and
303                 // the behavior always defaults to inherit = false
304                 //
305                 public override bool IsDefined (Type attributeType, bool inherit)
306                 {
307                         return MonoCustomAttrs.IsDefined (this, attributeType, false);
308                 }
309
310                 public override object[] GetCustomAttributes (bool inherit)
311                 {
312                         return MonoCustomAttrs.GetCustomAttributes (this, false);
313                 }
314                 
315                 public override object[] GetCustomAttributes (Type attributeType, bool inherit)
316                 {
317                         return MonoCustomAttrs.GetCustomAttributes (this, attributeType, false);
318                 }
319
320
321                 delegate object GetterAdapter (object _this);
322                 delegate R Getter<T,R> (T _this);
323                 delegate R StaticGetter<R> ();
324
325 #pragma warning disable 169
326                 // Used via reflection
327                 static object GetterAdapterFrame<T,R> (Getter<T,R> getter, object obj)
328                 {
329                         return getter ((T)obj);
330                 }
331
332                 static object StaticGetterAdapterFrame<R> (StaticGetter<R> getter, object obj)
333                 {
334                         return getter ();
335                 }
336 #pragma warning restore 169
337
338                 /*
339                  * The idea behing this optimization is to use a pair of delegates to simulate the same effect of doing a reflection call.
340                  * The first delegate cast the this argument to the right type and the second does points to the target method.
341                  */
342                 static GetterAdapter CreateGetterDelegate (MethodInfo method)
343                 {
344                         Type[] typeVector;
345                         Type getterType;
346                         object getterDelegate;
347                         MethodInfo adapterFrame;
348                         Type getterDelegateType;
349                         string frameName;
350
351                         if (method.IsStatic) {
352                                 typeVector = new Type[] { method.ReturnType };
353                                 getterDelegateType = typeof (StaticGetter<>);
354                                 frameName = "StaticGetterAdapterFrame";
355                         } else {
356                                 typeVector = new Type[] { method.DeclaringType, method.ReturnType };
357                                 getterDelegateType = typeof (Getter<,>);
358                                 frameName = "GetterAdapterFrame";
359                         }
360
361                         getterType = getterDelegateType.MakeGenericType (typeVector);
362 #if NET_2_1
363                         // with Silverlight a coreclr failure (e.g. Transparent caller creating a delegate on a Critical method)
364                         // would normally throw an ArgumentException, so we set throwOnBindFailure to false and check for a null
365                         // delegate that we can transform into a MethodAccessException
366                         getterDelegate = Delegate.CreateDelegate (getterType, method, false);
367                         if (getterDelegate == null)
368                                 throw new MethodAccessException ();
369 #else
370                         getterDelegate = Delegate.CreateDelegate (getterType, method);
371 #endif
372                         adapterFrame = typeof (MonoProperty).GetMethod (frameName, BindingFlags.Static | BindingFlags.NonPublic);
373                         adapterFrame = adapterFrame.MakeGenericMethod (typeVector);
374                         return (GetterAdapter)Delegate.CreateDelegate (typeof (GetterAdapter), getterDelegate, adapterFrame, true);
375                 }
376                         
377                 public override object GetValue (object obj, object[] index)
378                 {
379                         if (index == null || index.Length == 0) {
380                                 /*FIXME we should check if the number of arguments matches the expected one, otherwise the error message will be pretty criptic.*/
381 #if !FULL_AOT_RUNTIME
382                                 if (cached_getter == null) {
383                                         MethodInfo method = GetGetMethod (true);
384                                         if (!DeclaringType.IsValueType && !method.ContainsGenericParameters) { //FIXME find a way to build an invoke delegate for value types.
385                                                 if (method == null)
386                                                         throw new ArgumentException ("Get Method not found for '" + Name + "'");
387                                                 cached_getter = CreateGetterDelegate (method);
388                                                 // The try-catch preserves the .Invoke () behaviour
389                                                 try {
390                                                         return cached_getter (obj);
391                                                 } catch (Exception ex) {
392                                                         throw new TargetInvocationException (ex);
393                                                 }
394                                         }
395                                 } else {
396                                         try {
397                                                 return cached_getter (obj);
398                                         } catch (Exception ex) {
399                                                 throw new TargetInvocationException (ex);
400                                         }
401                                 }
402 #endif
403                         }
404
405                         return GetValue (obj, BindingFlags.Default, null, index, null);
406                 }
407
408                 public override object GetValue (object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
409                 {
410                         object ret = null;
411
412                         MethodInfo method = GetGetMethod (true);
413                         if (method == null)
414                                 throw new ArgumentException ("Get Method not found for '" + Name + "'");
415
416                         try {
417                                 if (index == null || index.Length == 0) 
418                                         ret = method.Invoke (obj, invokeAttr, binder, null, culture);
419                                 else
420                                         ret = method.Invoke (obj, invokeAttr, binder, index, culture);
421                         }
422                         catch (SecurityException se) {
423                                 throw new TargetInvocationException (se);
424                         }
425
426                         return ret;
427                 }
428
429                 public override void SetValue (object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture)
430                 {
431                         MethodInfo method = GetSetMethod (true);
432                         if (method == null)
433                                 throw new ArgumentException ("Set Method not found for '" + Name + "'");
434                         
435                         object [] parms;
436                         if (index == null || index.Length == 0) 
437                                 parms = new object [] {value};
438                         else {
439                                 int ilen = index.Length;
440                                 parms = new object [ilen+ 1];
441                                 index.CopyTo (parms, 0);
442                                 parms [ilen] = value;
443                         }
444
445                         method.Invoke (obj, invokeAttr, binder, parms, culture);
446                 }
447
448                 public override Type[] GetOptionalCustomModifiers () {
449                         Type[] types = MonoPropertyInfo.GetTypeModifiers (this, true);
450                         if (types == null)
451                                 return Type.EmptyTypes;
452                         return types;
453                 }
454
455                 public override Type[] GetRequiredCustomModifiers () {
456                         Type[] types = MonoPropertyInfo.GetTypeModifiers (this, false);
457                         if (types == null)
458                                 return Type.EmptyTypes;
459                         return types;
460                 }
461
462                 public override IList<CustomAttributeData> GetCustomAttributesData () {
463                         return CustomAttributeData.GetCustomAttributes (this);
464                 }
465         }
466 }